Skip to content

Experiment with post-quantum cryptography today

Experiment with post-quantum cryptography today

Practically all data sent over the Internet today is at risk in the future if a sufficiently large and stable quantum computer is created. Anyone who captures data now could decrypt it.

Luckily, there is a solution: we can switch to so-called post-quantum (PQ) cryptography, which is designed to be secure against attacks of quantum computers. After a six-year worldwide selection process, in July 2022, NIST announced they will standardize Kyber, a post-quantum key agreement scheme. The standard will be ready in 2024, but we want to help drive the adoption of post-quantum cryptography.

Today we have added support for the X25519Kyber512Draft00 and X25519Kyber768Draft00 hybrid post-quantum key agreements to a number of test domains, including

Do you want to experiment with post-quantum on your test website for free? Mail to enroll your test website, but read the fine-print below.

What does it mean to enable post-quantum on your website?

If you enroll your website to the post-quantum beta, we will add support for these two extra key agreements alongside the existing classical encryption schemes such as X25519. If your browser doesn’t support these post-quantum key agreements (and none at the time of writing do), then your browser will continue working with a classically secure, but not quantum-resistant, connection.

Then how to test it?

We have open-sourced a fork of BoringSSL and Go that has support for these post-quantum key agreements. With those and an enrolled test domain, you can check how your application performs with post-quantum key exchanges. We are working on support for more libraries and languages.

What to look for?

Kyber and classical key agreements such as X25519 have different performance characteristics: Kyber requires less computation, but has bigger keys and requires a bit more RAM to compute. It could very well make the connection faster if used on its own.

We are not using Kyber on its own though, but are using hybrids. That means we are doing both an X25519 and Kyber key agreement such that the connection is still classically secure if either is broken. That also means that connections will be a bit slower. In our experiments, the difference is very small, but it’s best to check for yourself.

The fine-print

Cloudflare’s post-quantum cryptography support is a beta service for experimental use only. Enabling post-quantum on your website will subject the website to Cloudflare’s Beta Services terms and will impact other Cloudflare services on the website as described below.

No stability or support guarantees

Over the coming months, both Kyber and the way it’s integrated into TLS will change for several reasons, including:

  • Kyber will see small, but backward-incompatible changes in the coming months.
  • We want to be compatible with other early adopters and will change our integration accordingly.
  • As, together with the cryptography community, we find issues, we will add workarounds in our integration.
  • We will update our forks accordingly, but cannot guarantee any long-term stability or continued support. PQ support may become unavailable at any moment. We will post updates on

    Features in enrolled domains

    For the moment, we are running enrolled zones on a slightly different infrastructure for which not all features, notably QUIC, are available.

    With that out of the way, it’s…

    Demo time!


    With the following commands build our fork of BoringSSL and create a TLS connection with using the compiled bssl tool. Note that we do not enable the post-quantum key agreements by default, so you have to pass the -curves flag.

    $ git clone
    $ cd boringssl-pq && mkdir build && cd build && cmake .. -Gninja && ninja 
    $ ./tool/bssl client -connect -server-name -curves Xyber512D00
    	Connecting to [2606:4700:7::a29f:8a55]:443
      Version: TLSv1.3
      Resumed session: no
      Cipher: TLS_AES_128_GCM_SHA256
      ECDHE curve: X25519Kyber512Draft00
      Signature algorithm: ecdsa_secp256r1_sha256
      Secure renegotiation: yes
      Extended master secret: yes
      Next protocol negotiated: 
      ALPN protocol: 
      OCSP staple: no
      SCT list: no
      Early data: no
      Encrypted ClientHello: no
      Cert subject: CN = *
      Cert issuer: C = US, O = Let's Encrypt, CN = E1


    Our Go fork doesn’t enable the post-quantum key agreement by default. The following simple Go program enables PQ by default for the http package and GETs

    ​​package main
    import (
    func main() {
      http.DefaultTransport.(*http.Transport).TLSClientConfig = &tls.Config{
        CurvePreferences: []tls.CurveID{tls.X25519Kyber512Draft00, tls.X25519},
        CFEventHandler: func(ev tls.CFEvent) {
          switch e := ev.(type) {
          case tls.CFEventTLS13HRR:
          case tls.CFEventTLS13NegotiatedKEX:
            switch e.KEX {
            case tls.X25519Kyber512Draft00:
              fmt.Printf("Used X25519Kyber512Draft00n")
              fmt.Printf("Used %dn", e.KEX)
      if _, err := http.Get(""); err != nil {

    To run we need to compile our Go fork:

    $ git clone
    $ cd go/src && ./all.bash
    $ ../bin/go run path/to/example.go
    Used X25519Kyber512Draft00

    On the wire

    So what does this look like on the wire? With Wireshark we can capture the packet flow. First a non-post quantum HTTP/2 connection with X25519:

    This is a normal TLS 1.3 handshake: the client sends a ClientHello with an X25519 keyshare, which fits in a single packet. In return, the server sends its own 32 byte X25519 keyshare. It also sends various other messages, such as the certificate chain, which requires two packets in total.

    Let’s check out Kyber:

    As you can see the ClientHello is a bit bigger, but still fits within a single packet. The response takes three packets now, instead of two, because of the larger server keyshare.

    Under the hood

    Want to add client support yourself? We are using a hybrid of X25519 and Kyber version 3.02. We are writing out the details of the latter in version 00 of this CRFG IETF draft, hence the name. We are using TLS group identifiers 0xfe30 and 0xfe31 for X25519Kyber512Draft00 and X25519Kyber768Draft00 respectively.

    There are some differences between our Go and BoringSSL forks that are interesting to compare.

    • Our Go fork uses our fast AVX2 optimized implementation of Kyber from CIRCL. In contrast, our BoringSSL fork uses the simpler portable reference implementation. Without the AVX2 optimisations it’s easier to evaluate. The downside is that it’s slower. Don’t be mistaken: it is still very fast, but you can check yourself.
    • Our Go fork only sends one keyshare. If the server doesn’t support it, it will respond with a HelloRetryRequest message and the client will fallback to one the server does support. This adds a roundtrip.
      Our BoringSSL fork, on the other hand, will send two keyshares: the post-quantum hybrid and a classical one (if a classical key agreement is still enabled). If the server doesn’t recognize the first, it will be able to use the second. In this way we avoid a roundtrip if the server does not support the post-quantum key agreement.

    Looking ahead

    The quantum future is here. In the coming years the Internet will move to post-quantum cryptography. Today we are offering our customers the tools to get a headstart and test post-quantum key agreements. We love to hear your feedback: e-mail it to

    This is just a small, but important first step. We will continue our efforts to move towards a secure and private quantum-secure Internet. Much more to come — watch this space.

    Source:: CloudFlare