Why Meta is moving TLS to post-quantum cryptography

Public-key cryptosystems such as RSA, Diffie-Hellman, and elliptic curve cryptography (ECC) are the backbone of internet security today. A sufficiently large quantum computer running Shor’s algorithm would efficiently break all of them. While such machines do not yet exist, the “store now, decrypt later” (SNDL) attack is already a practical concern: adversaries can intercept and store encrypted traffic today, with the intention of decrypting it once a quantum computer is available.

Post-quantum cryptography (PQC) aims to address this threat with algorithms that are resistant to quantum attacks, at the cost of greater communication bandwidth than classical counterparts. NIST is nearing publication of its PQC standards, and Meta cryptographers have contributed to the process by co-authoring the BIKE and Classic McEliece submissions and co-editing the ISO/IEC 14888-4 standard.

A staged hybrid migration

Meta has formed a workgroup to migrate its infrastructure and user-facing applications to PQC, a multi-year effort. The first priority was protecting components vulnerable to SNDL attacks where Meta controls both endpoints. Internal communication traffic was the most sensitive use case meeting those conditions, making it the initial migration target.

Given that new cryptosystems carry interoperability and security risks, Meta has chosen a hybrid key exchange approach for TLS that combines classical algorithms with a PQC algorithm, ensuring protection against existing and future attacks. For its deployment, Meta selected Kyber with X25519 in a hybrid setting, using Kyber768 by default and Kyber512 in cases where larger parameterizations would have a prohibitive performance impact.

Meta’s TLS library, Fizz, was built for high security, reliability, and performance and previously helped standardize TLS 1.3 (RFC 8446). To enable PQC, Fizz incorporates liboqs, an open source library implementing PQC key encapsulation and signature mechanisms including Kyber, along with hybrid key exchange functionality that combines liboqs mechanisms with existing classical ones.

Packet size and TLS resumption

One primary challenge is size: Kyber768 public keys are 1184 bytes, close to the typical TCP/IPv6 maximum segment size (MSS) of 1440 bytes. While this is acceptable for a full TLS handshake, it becomes problematic during TLS resumption. Meta performs Ephemeral Diffie-Hellman key exchange on resumption for forward secrecy, plus adds a 200–300 byte pre-shared key (PSK) for authentication. Combined with up to 200 bytes of remaining ClientHello fields, the resumption ClientHello exceeds the MSS for a single packet.

Figure 1: ClientHello size, when including ECDHE keyshares and PSK, will exceed MSS.

This has significant impact given the widespread use of TCP Fast Open (TFO) for internal traffic. With TFO, the ClientHello used to fit entirely in the TCP SYN packet, letting the server prepare its ServerHello immediately after SYN-ACK. When the ClientHello is too large for the first packet, TFO proceeds but sends only part of the ClientHello. The client must wait for the TCP handshake to finish before transmitting the remainder, then wait again for the ServerHello — adding an extra round trip time (RTT) before application data can flow.

Post-quantum readiness at Meta
Figure 2: Left: TLS handshake with TFO done in same round trip as TCP handshake. Right: ClientHello exceeds MSS of one packet, one round trip added to finish TLS handshake.

After evaluating alternatives, Meta chose to use Kyber512 for internal communications affected by this problem in the interim. Its 800-byte public keys help fit the ClientHello into a single TCP packet, while still being considered secure by NIST. Future improvements to MTU or adopting QUIC — which permits multiple initial packets — may allow larger ClientHellos without an extra RTT.

A multi-threading race condition in liboqs

After rolling out hybrid key exchange fleet-wide, an internal team began experiencing intermittent segmentation faults, with liboqs code prominent in the stack trace.

#0  0x0000000000000000 in ?? ()
#1  <signal handler called>
#2  0x0000000000000000 in ?? ()
#3  0x0000556ea1ed5eac in keccak_x4_inc_absorb.constprop ()

The root cause was a race condition in the Keccak_Dispatch function: Keccak_Initialize_ptr was set before other function pointers, while the caller checks Keccak_Initialize_ptr to decide whether to invoke the dispatch. In multithreaded execution, one thread could set Keccak_Initialize_ptr and pause, letting another thread see it as non-zero, skip the dispatch, and then call still-zero function pointers. The identical issue existed in Keccak_X4_Dispatch.

Although liboqs has broad adoption, Meta appears to have been the first to report this issue, likely due to the scale of its trial deployment. The fix calls Keccak_Dispatch with pthread_once on POSIX platforms; the patch has been submitted and merged upstream.

Cross-domain resumption thrashing

The hybrid key exchange rollout was progressive, driven by the client — first across data centers, then within data centers. TLS sessions are scoped internally by “service” name, allowing clients to resume sessions across hosts in the same service. That means a client can request resumption from a classical-key server to a hybrid-key server or vice versa.

During resumption, clients send only the minimally required default keyshares — the keyshare for the previously negotiated named group. If a client negotiated a classical named group with one server and then resumes with a server expecting a hybrid named group, the client advertises the hybrid group but sends only the classical keyshare. The server then needs to reply with a HelloRetryRequest to obtain the hybrid keyshare, costing an extra RTT.

Meta’s solution splits each service into two TLS session scopes: one for classical key exchange and one for hybrid. Each scope consistently uses a single named group, avoiding keyshare thrashing. The tradeoff is higher session ticket storage, which has been acceptable since tickets are only a few hundred bytes.

Computational cost observations

During initial rollout with the hybrid named group X25519_kyber768, CPU cycles increased by roughly 40 percent. Despite appearing unfavorable, that result actually suggests Kyber768 alone performs faster than X25519 — consistent with findings from others in the field.

Deployment status and path forward

Meta has deployed post-quantum hybrid key exchange for most internal service communications as protection against the SNDL threat. These tend to be within Meta’s internal network and fully under its control, making them the logical first target while awaiting the finalized NIST PQC standards.

Extending this to external public internet traffic introduces additional challenges: dependency on browsers’ and crypto libraries’ PQC readiness, and higher communication bandwidth from larger payloads. Meta will continue hardening its systems in coordination with industry standardization and broader browser adoption, planning to share further updates as that work progresses.