Dilithium (ML-DSA): How Post-Quantum Digital Signatures Work
Dilithium3 — officially ML-DSA-65 under FIPS 204 — is the NIST-standardized post-quantum digital signature algorithm. It replaces RSA and ECDSA signatures with quantum-safe integrity guarantees built on lattice mathematics.
Where Kyber handles encryption (keeping data secret), Dilithium handles integrity and authentication (proving data has not been tampered with and verifying who created it). Both are essential for a complete post-quantum security posture.
Why RSA and ECDSA Signatures Break
RSA signatures rely on the difficulty of factoring large integers. ECDSA signatures rely on the elliptic curve discrete logarithm problem. Shor's algorithm solves both problems efficiently on a quantum computer.
The consequences of broken signatures are different from broken encryption — and in some ways more dangerous:
- Forged audit trails. An attacker could retroactively forge signatures on financial records or compliance documents.
- Tampered software. Code signing protects software supply chains. Forged signatures mean malicious updates appear legitimate.
- Spoofed identities. Digital certificates prove server identity. Forged certificates enable man-in-the-middle attacks.
- Invalidated contracts. Digitally signed contracts lose their legal standing if the signature scheme is broken.
Encryption protects confidentiality — keeping secrets. Signatures protect integrity and authenticity — proving that data is genuine and unmodified. Both need quantum-safe replacements.
Lattice-Based Signatures — The Intuition
Dilithium shares its mathematical foundation with Kyber: the Module-LWE problem family. Both operate on lattices in high-dimensional space. But where Kyber uses lattice problems for key encapsulation, Dilithium uses them for signatures.
How Signing Works (Conceptually)
Signing with Dilithium works like solving a puzzle whose answer is hard to find but easy to check:
- The message is hashed and mapped to a challenge — a specific "target" in the lattice.
- The signer uses the private key to find a "short vector" that satisfies the challenge. Finding a short vector requires knowledge of a secret lattice structure (the private key). Without it, the search space is astronomically large.
- The verifier checks that the vector is genuinely short and satisfies the challenge, using only the public key. This check is fast and deterministic.
The analogy: imagine a lock that can only be opened by finding a very specific, very small key that fits perfectly. The private key holder knows a shortcut to manufacture this tiny key for any lock. Everyone else would have to search through an impossibly large space of candidate keys. And once someone presents a key, anyone can quickly test whether it fits.
Fiat-Shamir with Aborts
Dilithium uses a technique called Fiat-Shamir with Aborts. During signing, the algorithm generates a candidate signature and then checks whether it could leak information about the private key. If it does, the candidate is discarded and the algorithm tries again.
This "abort and retry" behavior is not a bug — it is a carefully designed security feature. On average, signing succeeds within a few attempts. The retries are invisible to the caller: you send a message and receive a signature. The internal retries happen in microseconds.
This is a fundamental difference from ECDSA, where signing always succeeds on the first attempt. Dilithium's willingness to abort and retry is what prevents subtle information leakage that could compromise the private key over many signatures.
How Sign / Verify Works
Key Generation: Generate a key pair. The signing key (private, 4,000 bytes) stays secret. The verification key (public, 1,952 bytes) is shared.
Signing: Hash the message, then use the signing key to produce a signature (3,293 bytes). The signature is deterministic for the same message and key — signing the same message twice produces the same signature.
Verification: Given the message, signature, and verification key, check whether the signature is valid. This is a fast, one-shot computation. The result is binary: valid or invalid.
The Dilithium3 signature is 3,293 bytes — much larger than ECDSA's 64 bytes. This is the price of quantum resistance. For API payloads, this overhead is negligible. For high-throughput, low-bandwidth protocols, it requires consideration.
Dilithium3 Specifics
Dilithium3 vs. Classical Signature Algorithms
RSA-2048 Legacy | ECDSA P-256 Legacy | Dilithium3 FIPS 204 | |
|---|---|---|---|
| Public key | 256 bytes | 64 bytes | 1,952 bytes |
| Signature size | 256 bytes | 64 bytes | 3,293 bytes |
| Sign time | ~1ms | ~0.5ms | ~3ms |
| Verify time | ~0.1ms | ~0.5ms | ~1ms |
| Quantum-safe | No | No | ✓ Yes |
| NIST standard | Legacy | Legacy | ✓ FIPS 204 |
| Security basis | Integer factoring | Discrete logarithm | Module-LWE (lattice) |
Performance at Qpher: signature operations complete in under 30ms at the 95th percentile, including network latency, authentication, and the cryptographic operation.
Using Dilithium3 with Qpher
Generate a Signature Key Pair
from qpher import Qpher
client = Qpher(api_key="qph_your_api_key")
result = client.keys.generate(algorithm="Dilithium3")
print(f"Key version: {result.key_version}")
print(f"Algorithm: {result.algorithm}")
print(f"Status: {result.status}")Sign a Message
import base64
message = b"Invoice #QP-2026-001 Total: $10,000"
message_b64 = base64.b64encode(message).decode()
result = client.signatures.sign(
message=message_b64,
key_version=1,
)
print(f"Signature: {result.signature[:40]}...")
print(f"Signature size: ~3,293 bytes")Verify a Signature
verification = client.signatures.verify(
message=message_b64,
signature=result.signature,
key_version=1,
)
print(f"Valid: {verification.valid}") # TrueCommon signing use cases: invoices, audit logs, API responses, code artifacts, compliance documents, and any data where provenance and tamper-detection matter.
Dilithium vs. ECDSA: When to Use Which
The transition to Dilithium does not need to happen overnight. A pragmatic approach considers the signature's lifetime:
- Use Dilithium3 (via Qpher) for: Long-lived signatures (documents, audit trails, compliance records), regulatory environments moving toward PQC mandates, and any signature that must remain valid for more than 5 years.
- ECDSA is still acceptable for: Short-lived signatures with lifetimes under 5 years, such as TLS session authentication or ephemeral API tokens. These will expire long before quantum computers arrive.
- Hybrid approach: For maximum safety during the transition period, some organizations sign with both ECDSA and Dilithium. Verifiers that support Dilithium check the quantum-safe signature; legacy verifiers fall back to ECDSA.
Next Steps
You now understand both sides of post-quantum cryptography: Kyber for encryption and Dilithium for signatures. The next article explains how these pieces fit together in a complete encryption system: the KEM-DEM hybrid scheme that Qpher uses internally.
Explore the Sign Documents guide for step-by-step integration instructions, or see the Signature API Reference for full endpoint documentation.