Carr Digital

Measurement · August 9, 2026

The same 985 bytes

Certificate compression recovers a median 985 bytes on the chains real sites serve. After a drop-in ML-DSA-44 migration it recovers a median 985 bytes. The saving is structural, and migration adds no structure.

A search summary told me last week that post-quantum certificate overhead “is largely mitigated through TLS 1.3 certificate compression and caching mechanisms.” It named a paper as the source. That paper contains one instance of the word “compress,” and it is a metaphor about summarizing operational cost.

The two IETF drafts that actually address the question say the opposite, in plain language, and they have said it for two years. So the qualitative answer has been settled and publicly available the whole time. What nobody has put a number on is how badly compression stops working, on the chains that real sites serve, once those chains carry ML-DSA.

I captured the certificate chains 8,152 of the Tranco top 10,000 serve and compressed every one of them at maximum effort. The median chain gives back 985 bytes. Carried onto the same site’s chain after a drop-in ML-DSA-44 migration, the median chain gives back 985 bytes.

That is the finding. The saving does not grow, because the thing it feeds on does not grow.

None of this is a discovery, and two drafts say so

Certificate compression is RFC 8879. The server compresses its Certificate message with zlib, brotli, or zstd, the client advertises which of the three it can decompress, and both sides save the difference. It is old, deployed, and useful.

Its limits against post-quantum certificates are documented. draft-ietf-uta-pqc-app-03 puts it this way: “While effective in many scenarios, its impact on PQ or PQ/T hybrid certificates is limited due to the larger sizes of public keys and signatures in PQC. These high-entropy fields, inherent to PQC algorithms, constrain the overall compression effectiveness.” draft-ietf-tls-cert-abridge-02 is blunter: post-quantum certificates “cannot be compressed with existing TLS Certificate Compression schemes because most of the size of the certificate is in high entropy fields such as cryptographic keys and signatures.”

Measuring compression across real chains is also published work, and it is the same draft that did it. Dennis Jackson evaluated roughly 75,000 Tranco chains and reported percentiles: a median chain of 4,032 bytes compressing to 3,243 with ZStandard at maximum parameters. My corpus is 8,152 chains, about a ninth the size. I am not reporting a new kind of measurement, and the entire existence of cert-abridge, and of Merkle Tree Certificates alongside it, is the standards community already routing around this problem.

What I have that the drafts do not is the join. This is the same corpus I used to project what real chains weigh under ML-DSA, so I can take each site’s measured compression saving and carry it onto that same site’s projected chain. One number per site, before and after.

What compression gives back today

Every chain below is the concatenated DER certificate_list as captured off the wire, compressed with zlib at level 9, brotli at quality 11, and zstd at level 22. Maximum effort on all three, which makes these an upper bound. A production server picks something cheaper and saves less.

p5 p50 p95
Chain as served 2,456 3,754 6,465
Compressed, best of three 1,709 2,668 4,494
Saving 694 985 1,912
Saving, percent 18.7% 28.6% 39.8%

Each row is its own distribution, so the rows do not subtract: the median saving is the median of 8,152 per-site savings, not the gap between two other medians.

The instrument calibrates against the published figure before it gets used for anything. Comparing like with like means comparing zstd to zstd, since that is the algorithm the draft’s row used: my median zstd saving is 942 bytes against the draft’s 789. My corpus compresses somewhat better than the draft’s did. Corpus size, corpus composition, and two years of chain growth are all tangled together in that gap, so I record it and make no trend claim out of it.

One incidental result, since I ran all three algorithms and the draft ran one. Brotli wins 87.4% of real chains, zstd takes the other 12.6%, and zlib never wins. Brotli’s median margin over zstd is 45 bytes. That is small enough to be a footnote for a server operator and large enough to be worth knowing that the ordering is not the one the draft’s evaluation implies.

Where the 985 bytes come from

Split the saving in two. Compress each certificate on its own and you capture the redundancy inside it: the X.509 boilerplate, the OID soup, the repeated extension scaffolding, the long distinguished names. Compress them together and you additionally capture what repeats between them, chiefly each certificate’s issuer name restating the subject name of the one above it.

On the median real chain: 515 bytes found inside certificates, 442 bytes found across them.

Both halves are structure. Names, SANs, CRL URLs, SCT framing, the ASN.1 itself. None of it is cryptography.

That matters because of what happens next, and it is worth being precise about a correlation that looks reassuring and is not. Across the corpus, the saving tracks chain size fairly well (r = +0.80) and certificate count only loosely (r = +0.32). It would be easy to read that first number as “bigger chains compress better, so bigger post-quantum chains will too.” On classical chains, size largely is structure. The median leaf in this corpus carries 2 subject alternative names; the 99th percentile carries 148, and one carries 447. Those names are text, they repeat, and they compress. Post-quantum migration adds size that is not structure. The correlation and the mechanism point in the same direction today and separate completely on migration day.

The part that does not compress

I checked rather than assumed. Here is what happens when you hand an ML-DSA signature and public key to each RFC 8879 algorithm, with the X.509 structure stripped away so there is nothing else to find:

Raw zlib brotli zstd
ML-DSA-44 signature 2,420 2,424 2,424 2,424
ML-DSA-65 signature 3,309 3,313 3,313 3,313
ML-DSA-87 signature 4,627 4,631 4,631 4,631
ML-DSA-44 public key 1,334 1,338 1,338 1,338

Every cell comes out four bytes larger than it went in. Compressing a lattice signature makes it bigger.

Nobody should be surprised. Those four bytes are the compressor’s own framing, and framing is the only thing a compressor can contribute to input with no redundancy in it. This is the drafts’ “high entropy fields” sentence, weighed. It is an illustration of a known fact, not a new one.

It is also the assumption the rest of this rests on, which is why it gets measured instead of asserted.

The same coupon against a bigger bill

Now carry each site’s measured saving onto its own migrated chain. The projection swaps exactly two things per certificate, the measured signature bytes and the measured public-key bytes, for their FIPS 204 equivalents as OpenSSL 3.5.5 emits them. Everything else stays as observed. The saving stays where the measurement put it, because the added bytes contribute nothing to it.

Median payload Median saving Saving, percent
Classical, today 3,754 985 28.6%
ML-DSA-44 13,103 985 7.4%
ML-DSA-65 17,686 985 5.5%

The spread is narrow, which is the useful part. Under ML-DSA-44 the saving lands between 5.5% and 13.2% for 90% of sites. There is no tail of sites where compression rescues the situation.

A fixed-value coupon is the honest analogy. Five dollars off is a quarter of a twenty dollar order and a rounding error on a hundred and fifty dollar one. The coupon never changed. Compression is the same instrument on migration day that it is today, recovering the same names and the same boilerplate, while the chain around it grows by a factor of three and a half.

There is a lab result that shows the same shape from the other end. On minimal certificates built for testing, short names, one SAN, no SCTs, no URLs, compression recovers about 240 bytes and it recovers about 240 bytes whether the chain is 900 bytes of ECDSA or 15,703 bytes of SLH-DSA. Strip the structure out and the size-independence is visible directly. Real certificates carry four times that structure, which is exactly why the real-web figure is 985 and not 240. Both numbers are correct. They answer different questions, and quoting the lab one as a WebPKI figure would understate compression by a factor of four.

What actually helps

The drafts already answer this, which is why they exist. cert-abridge gets the median chain to 1,060 bytes by shipping clients a dictionary of known intermediates and roots, so the parts of the chain that every client already has stop travelling. That is a different mechanism from compression: it removes certificates rather than squeezing them. Merkle Tree Certificates attack it from another angle again.

From my own corpus, the cheapest available move is still the one I found last time: leaf-only migration, where a post-quantum key sits in the leaf and the chain signatures stay classical. That fits the initial congestion window at more than 99% of sites in both parameter sets. It works because it migrates the fewest signatures, not because anything compresses. Chain check runs that projection against any public domain, from this same corpus.

What does not help is putting compression in the plan and moving on. It is worth turning on. It is worth 985 bytes. Budget it at 985 bytes.

Limits

The compression figures are measured; every post-quantum figure here is a projection under stated assumptions, and no compression was run against a migrated chain because the corpus contains no post-quantum certificates to run it against. Maximum-effort settings on all three algorithms make the savings an upper bound. The payload measured is the DER certificate_list rather than the byte-exact Certificate handshake message, which adds roughly 15 bytes of framing that I have not included. The corpus is a one-day snapshot of one ranking’s top slice, chains rotate, and a top-10k corpus is concentrated in a few issuers and CDNs. cert-abridge’s dictionary results are quoted from its table and were not reproduced here.

Provenance

Measured here (Verified). The 8,152 captured chains, their compressed sizes under all three RFC 8879 algorithms, the decomposition into within-certificate and cross-certificate savings, the per-algorithm win rates, and the correlations come from a capture taken 2026-08-07 on one machine, Tranco list ZJGPG pinned, analyzed offline. The ML-DSA field expansion was measured against real ML-DSA certificates minted locally with OpenSSL 3.5.5. Script and dataset are public at pqc-chain-budget (DOI 10.5281/zenodo.21846142) as src/compress_chains.py, with the run recorded in data/2026-08-09_compression.md; the field-level measurement is in pqc-cert-matrix (DOI 10.5281/zenodo.21749600) as phase3/compressibility.py.

Projected, not measured (Proposed). Every post-migration payload and percentage. The projection holds the measured structural saving constant and grows the payload by the FIPS 204 delta per certificate, which is sound only because of the field measurement above. The 985-byte saving after migration is an inference from two measurements, not a third measurement.

Cited, not claimed (Reported). That certificate compression does not rescue post-quantum certificates is stated in draft-ietf-uta-pqc-app-03 and draft-ietf-tls-cert-abridge-02, both quoted above from the full drafts rather than from any summary. Measurement of compression across a large corpus of real WebPKI chains is Jackson’s, in the cert-abridge draft, over roughly 75,000 Tranco chains; his Table 1 is the source of every figure I attribute to it, including the dictionary results. The mechanism is RFC 8879. The congestion-window framing and the flight-level budget come from work cited in full in an earlier piece. I found no published post-migration compression percentage on real chains after searching; cert-abridge cites Westerbaan’s “Sizing Up Post-Quantum Signatures” for post-quantum sizing, and that post does not discuss certificate compression at all.

Things this project got wrong along the way. The lab measurement that started this reported compression’s saving as roughly 240 bytes, and its own prior-art file flagged that figure as a floor for minimal certificates rather than a WebPKI number. It was low by a factor of four, and that caveat is the reason this corpus run happened. Separately, the search summary in the first paragraph is the third fabricated or misattributed source this body of work has caught by hand, which is why every citation above was verified by downloading the document and grepping it.

If something here is wrong, email the studio and I will correct it in place with a note saying what changed.