21KB to 74 Bytes: How We Compressed Three Post-Quantum Signature Families Into One Attestation
Dilithium, FALCON, and SPHINCS+ produce 21,054 bytes of signatures. We got the persistent footprint down to 74 bytes. Here's exactly how.
The Problem
Post-quantum cryptography has a size problem. The algorithms that protect against quantum computers produce signatures that are orders of magnitude larger than what we're used to.
A Schnorr signature on Bitcoin is 64 bytes. An ECDSA signature on Ethereum is 65 bytes. These are the numbers that every blockchain, every protocol, every system was designed around.
Now look at the post-quantum alternatives:
| Algorithm | Family | Signature Size |
|---|---|---|
| ML-DSA-65 (Dilithium) | Lattice (MLWE) | 3,309 bytes |
| FALCON-512 | Lattice (NTRU) | ~657 bytes |
| SPHINCS+-SHA2-128f | Hash-based | 17,088 bytes |
| Total (3-key) | 3 families | ~21,054 bytes |
21 kilobytes. Per attestation. If you want the security of three independent mathematical families—which you do, because betting your infrastructure on one family is how you get burned when a breakthrough happens—you're looking at 21KB of signature data that needs to go somewhere.
For context, a typical Bitcoin transaction is about 250 bytes. An OP_RETURN output is limited to 80 bytes. Asking any blockchain to carry 21KB of post-quantum signatures per transaction is not a conversation worth having.
The Insight: Signatures Are Ephemeral
We spent weeks trying to compress the signatures. STARK proofs got us from 6,813 bytes (Dilithium + FALCON) down to 440 bytes—a 15.5x compression. But 440 bytes was still too large for the constraints we were working with. We needed to be under 100 bytes total.
Then we asked a different question: why do the signatures need to persist at all?
A signature exists to prove that a specific key signed a specific message at a specific time. Once that's been verified, the verification result is what matters—not the raw signature. You don't carry your passport through every door after the guard checked it at the entrance. The guard stamps your badge and you move on.
The signatures are evidence of a verification event. The verification event is the thing that persists. And a verification event can be represented in far fewer than 21,054 bytes.
The H33 Substrate
The H33 Substrate is a 58-byte canonical byte sequence that bridges any FHE (fully homomorphic encryption) computation output to any post-quantum signature algorithm. It's the universal adapter between "I computed something on encrypted data" and "here's a post-quantum proof that it happened."
The layout:
[0] version 1 byte
[1] computation_type 1 byte (biometric, payment, KYC, etc.)
[2..34] fhe_commitment 32 bytes (SHA3-256 of FHE output)
[34..42] timestamp_ms 8 bytes (big-endian)
[42..58] nonce 16 bytes (random)
58 bytes. Fixed size regardless of what was computed or how large the FHE ciphertext was. The fhe_commitment is a SHA3-256 hash of the computation output, so it binds to the specific result without carrying the result itself. The computation_type byte provides domain separation—a biometric attestation can't be replayed as a payment attestation because the type byte is different and it's inside the signed boundary.
The signing message is SHA3-256 of the complete 58-byte substrate. That's the 32-byte value that all three post-quantum algorithms sign. Same message, three independent signatures, three independent mathematical families.
The Attestation Pipeline
Here's where the 21KB becomes 74 bytes.
Step 1: Create the substrate (58 bytes)
Take the FHE computation output, SHA3-256 hash it, pack it with the computation type, timestamp, and a fresh nonce. You now have a 58-byte canonical commitment.
Step 2: Derive the signing message (32 bytes)
SHA3-256 of the 58-byte substrate. This is what gets signed. Fixed size, deterministic, irreversible.
Step 3: Sign with three families (~21KB, ephemeral)
Dilithium signs the 32-byte message. FALCON signs the same 32-byte message. SPHINCS+ signs the same 32-byte message. Three signatures, three mathematical families, ~21KB of raw signature data now exists in memory.
Step 4: Verify all three
Each signature is independently verified against its corresponding public key. This takes about 15 milliseconds for all three.
Step 5: Compress to a 42-byte receipt
This is the key step. After verification, we build a compact verification receipt:
[0] version 1 byte
[1..33] verification_hash 32 bytes (SHA3-256 of msg + all PKs + all sigs)
[33..41] verified_at_ms 8 bytes (timestamp)
[41] algo_flags 1 byte (which families verified: bitmask)
--------
42 bytes
The verification_hash is a SHA3-256 digest that commits to the signing message, all three public keys, and all three signatures. If any component changes—different message, different key, different signature—the hash changes. This 32-byte hash is the cryptographic binding between the 42-byte receipt and the 21KB of signatures that produced it.
Step 6: Zeroize the raw signatures
The 21KB of raw Dilithium + FALCON + SPHINCS+ signature data is explicitly zeroed from memory. It existed for about 15 milliseconds. It never touched disk. It never left the process. It's gone.
Step 7: Cache the receipt
The 42-byte receipt is stored in a high-speed cache, keyed by the 32-byte signing message (which is the same value that goes on-chain). Subsequent verifications are a cache lookup. We measure these at 0.059 microseconds.
The Numbers
| Component | Bytes | Lifetime |
|---|---|---|
| Dilithium signature | 3,309 | ~15ms (ephemeral) |
| FALCON signature | ~657 | ~15ms (ephemeral) |
| SPHINCS+ signature | 17,088 | ~15ms (ephemeral) |
| On-chain hash | 32 | Permanent |
| Cached receipt | 42 | Permanent |
| Total persistent | 74 |
285x compression. 21,054 bytes of raw PQ signatures become 74 bytes of persistent state. The signatures are born, verified, compressed, and destroyed. What survives is a 32-byte on-chain anchor and a 42-byte verification receipt that proves three independent mathematical families attested to this specific computation at this specific time.
Why This Works Cryptographically
The natural objection: "You threw away the signatures. How is this still secure?"
The 42-byte receipt contains a verification_hash that is SHA3-256 of the signing message concatenated with all three public keys and all three signatures. This hash has three properties:
- Binding: Any change to any input (message, key, or signature) produces a completely different hash. You cannot find two different sets of (message, keys, signatures) that produce the same receipt.
- One-way: You cannot recover the signatures from the hash. The receipt proves verification occurred without revealing the verification inputs.
- Deterministic: The same inputs always produce the same hash. If someone later re-signs with the same keys and message, the verification hash will match.
The on-chain 32-byte hash (SHA3-256 of the substrate) deterministically derives from the substrate. The substrate deterministically derives from the FHE computation output. The receipt's verification hash deterministically derives from the signatures. The chain is unbreakable: tamper with any link and the hashes diverge.
What This Means for Blockchains
Every blockchain is eventually going to need post-quantum protection. The question is how much that costs in block space, transaction weight, and validator overhead.
If you put a Dilithium signature directly on-chain, that's 3,309 bytes per transaction. At 600,000 Bitcoin transactions per day, that's 1.98 GB of additional chain growth per day—just from signatures. In a year, that's 723 GB. The blockchain would double in size from signatures alone.
Our approach: 32 bytes per transaction on-chain. At 600,000 transactions per day, that's 19.2 MB. In a year, 7 GB. That's 103x less chain growth than a single-algorithm approach, and we're covering three algorithm families instead of one.
No validator changes. No consensus changes. No block size impact. The 32-byte hash fits inside an existing OP_RETURN on Bitcoin (well under the 80-byte limit), a PDA on Solana, or a contract storage slot on Ethereum. The 42-byte verification receipt lives off-chain and serves lookups in under a microsecond.
The Domain Separation Registry
The substrate's computation_type byte isn't just metadata. It's an append-only registry value that provides cryptographically enforced domain separation.
A biometric authentication attestation carries type 0x01. A Bitcoin UTXO attestation carries type 0x06. A KYC verification carries type 0x07. These values are assigned once, permanently, and never reused. Because the type byte is inside the substrate, and the substrate is inside the signing message, and the signing message is what all three algorithms sign—the type byte is covered by the post-quantum signatures.
You cannot take a biometric attestation and present it as a payment attestation. The type byte doesn't match, so the signing message doesn't match, so the signatures don't verify. This is protocol-level replay prevention, not application-layer metadata that can be stripped.
Production Status
The H33 Substrate is integrated across our production stack:
- Biometric authentication pipeline: Every FHE biometric match produces a substrate attestation. 2.2 million authentications per second, each with a 74-byte 3-key proof.
- Identity system (UPQ-ID): Chain bindings to Bitcoin and Solana use substrate commitments. Each binding is 74 bytes total per chain.
- Archive signing: Long-term document signatures include substrate commitments binding three PQ families.
- Video conferencing (V100): Meeting recordings, transcripts, and AI summaries carry substrate attestations. Participant metadata is encrypted with AES-256-GCM under Kyber-derived keys, with substrate binding.
- API triple-key signing: The
/api/v1/triple-key/signendpoint returns a substrate attestation alongside the backwards-compatible signature.
69 tests in the substrate crate. 3,696 tests passing across all integrated products. The crate is 1,724 lines of Rust. No async. No networking. No FHE. No signing libraries. Just the substrate—the 58-byte payload, the 42-byte receipt, and the Bitcoin OP_RETURN bridge.
The Scale Math
At Bitcoin's transaction volume (600,000 per day), the off-chain receipts accumulate at 25.2 MB per day. That's 9.2 GB per year. A decade of every Bitcoin transaction PQ-attested fits in 92 GB of storage. One machine.
At Solana's peak throughput (65,000 TPS), the receipts accumulate at 235 GB per day. That's one high-memory server for hot storage, with warm and cold tiers for older receipts. At no scale does 42 bytes per attestation create a storage problem that doesn't already exist from the system's normal operation.
The on-chain cost is even smaller. 32 bytes per transaction adds 19.2 MB per day to Bitcoin's chain—about a 15% increase over normal chain growth. Compare that to raw Dilithium signatures at 1.98 GB per day (a 1,000% increase) or full three-family signatures at 12.6 GB per day (a 6,300% increase).
The receipt architecture doesn't just reduce storage. It changes the cost curve from linear in signature count (every new algorithm adds kilobytes) to constant (74 bytes regardless of how many algorithms verify). Adding a fourth algorithm family in the future wouldn't add a single byte to the persistent footprint. The receipt hash would simply incorporate the additional verification, and the algorithm flags byte has room for 5 more families.
What We Didn't Do
We didn't compress the signatures. STARK compression gets Dilithium + FALCON from 6,813 bytes to 440 bytes, and that's useful for other contexts, but it's still too large for the constraints we were targeting.
We didn't compromise on security. Three independent mathematical families—MLWE lattice, NTRU lattice, and hash-based—all verify independently. If any one family breaks in the next 30 years, the other two still hold.
We didn't require consensus changes. No new opcodes. No soft forks. No validator upgrades. The substrate works with every blockchain exactly as it exists today.
We asked a simpler question: what if the signatures don't need to persist? What if the proof of verification is enough? The answer was 74 bytes.
Build with the H33 Substrate
The substrate crate is available for integration. Every H33 API call now returns a substrate attestation.
Get API Key Read the Docs