The Go standard library has its own TLS implementation. It is not built on OpenSSL. It is not built on BoringSSL. The crypto/tls package, sitting alongside crypto/x509, crypto/elliptic, and crypto/ecdh, is a clean Go implementation maintained by the Go security team. That decision, made early in Go's history, made the language's network code easy to reason about and easy to deploy. It also means that Go's adoption of post-quantum cryptography happens on Go's release schedule, not OpenSSL's.
This article walks through what Go supports for post-quantum cryptography as of Go 1.24 and 1.25, where the implementation lives, and what the upcoming roadmap looks like.
How Go's TLS Stack Is Organized
Three packages do most of the work for Go TLS:
- crypto/tls: handshake state machine, record layer, cipher suite negotiation
- crypto/x509: certificate parsing and chain validation
- crypto/ecdh and crypto/ecdsa: classical elliptic curve primitives
Post-quantum primitives live in golang.org/x/crypto, which is the Go team's "extended" cryptography module. Algorithms graduate from x/crypto into the standard library after API stability and security review. ML-KEM landed in golang.org/x/crypto/mlkem in 2024. From there it was wired into crypto/tls for hybrid TLS handshakes.
For more on the underlying algorithm, see ML-KEM explained.
What Go Ships for Post-Quantum
The picture for Go 1.24 (released early 2025) and Go 1.25 (released August 2025) looks like this.
| Algorithm | Status in Go |
|---|---|
| ML-KEM-768 (FIPS 203) | golang.org/x/crypto/mlkem |
| X25519MLKEM768 hybrid | crypto/tls support, default-enabled in Go 1.24+ |
| ML-KEM-1024 | Implementation present |
| ML-DSA | Engineering in progress, x/crypto path |
| SLH-DSA | Not landed |
| FN-DSA | Not landed |
| HQC | Not landed |
| Hybrid certificates | Not present |
Go 1.23 introduced X25519Kyber768Draft00 for hybrid TLS (matching the early Chrome flag). Go 1.24 added X25519MLKEM768 aligned with the IETF draft and the FIPS 203 final algorithm. Go 1.24 enabled X25519MLKEM768 in the default tls.Config when negotiating with peers that advertise support.
Why Go Did It Themselves
Go's standard-library cryptography is a clean-room implementation deliberately. The Go security team has written publicly about the decision, captured in talks at GopherCon and posts at go.dev/blog. The reasons:
- Pure Go means no cgo bridges, which simplifies cross-compilation
- The Go memory model and race detector cover the crypto code uniformly
- Bugs in C-based libraries (Heartbleed, Lucky Thirteen) don't reach Go users
- The Go team has the engineering bandwidth to keep up with major algorithms
Post-quantum follows the same approach. The Go ML-KEM implementation in golang.org/x/crypto/mlkem is pure Go with optional architecture-specific assembly for performance hotspots. The implementation has been reviewed by Filippo Valsorda's mldsa65 and mlkem reference work and other independent crypto reviewers in Go's ecosystem.
How the Hybrid TLS Group Works in Go
When a Go server runs tls.Listen with default configuration, the server now advertises X25519MLKEM768 in the supported_groups extension during the TLS 1.3 handshake. If the client also supports this group, the handshake uses a hybrid key exchange.
In code, switching is automatic. Existing applications written against crypto/tls do not need to change. They get post-quantum protection on connections where the peer also supports it.
For tighter control, applications can set tls.Config.CurvePreferences to specify which groups are advertised. As of Go 1.24, the constants include:
- tls.X25519
- tls.X25519MLKEM768
- tls.CurveP256
- tls.CurveP384
- tls.CurveP521
Server administrators can prefer X25519MLKEM768 first by listing it at the head of CurvePreferences.
For deeper context on hybrid encryption mechanics, see hybrid encryption.
How Implementations Compare
Go's ML-KEM is one of several available open-source implementations. Compared to:
- BoringSSL: Go's implementation is in pure Go, BoringSSL's is in C with assembly. Performance is similar at the algorithmic level. BoringSSL has a slight edge in microbenchmarks on x86_64 due to mature AVX2 paths.
- liboqs: Go's implementation is purpose-built for the standard library. liboqs is a research-oriented library with broad algorithm coverage. Go does not depend on liboqs.
- AWS-LC (Amazon's BoringSSL fork): Similar performance to BoringSSL. Go does not depend on AWS-LC.
The interesting comparison for Go developers is rustls. Go and Rust both have ecosystems where applications avoid cgo/FFI and use pure-language crypto stacks. See Rust rustls PQC for the parallel story.
Performance Numbers
The Go team has not published authoritative public benchmarks for ML-KEM yet, but published Go ecosystem benchmarks indicate:
- ML-KEM-768 keypair generation: roughly 30-100 microseconds on a modern x86_64 server
- Encapsulation: similar magnitude
- Decapsulation: similar magnitude
The handshake-time impact in Go-based servers running X25519MLKEM768 is dominated by the additional 1 KB or so of payload, similar to what other libraries see. CPU cost is small relative to the network cost.
For more on the underlying constraints, see harvest now decrypt later.
ML-DSA in Go
ML-DSA (FIPS 204) is the next major piece. The work is happening in golang.org/x/crypto/mldsa. Once stabilized, it will land in the standard library and integrate into crypto/x509 for certificate parsing.
Several engineering decisions are being worked out:
- API shape for signing and verifying with ML-DSA-44, 65, and 87
- Integration with crypto.Signer interface so existing code that uses crypto.Signer can opt in
- Certificate format support, tracking the IETF LAMPS drafts for X.509 PQC signatures
Go's design pattern is that the standard library exposes algorithms behind generic interfaces (Signer, PublicKey, etc.) rather than per-algorithm bespoke APIs. ML-DSA is being shaped to fit that pattern.
For algorithm-level comparison, see ML-DSA vs SLH-DSA.
What Is Not in Go
Items intentionally not in Go's roadmap as of 2026:
- SLH-DSA: Larger signatures and slower verification make it less attractive for online TLS. Not on the immediate roadmap.
- FN-DSA / Falcon: Floating-point arithmetic dependency creates side-channel risk and platform-specific behavior. Not adopted.
- HQC: Not selected for default integration. Could appear in x/crypto for completeness, but unlikely in the standard library.
- Hybrid certificates: Awaiting IETF stabilization.
This list is conservative. Go's strategy is to ship the algorithms NIST has finalized and that have clear use cases in TLS and signing.
How Go's TLS State Machine Handles ML-KEM
At the protocol level, Go's TLS code in src/crypto/tls treats ML-KEM as another key exchange mechanism alongside the elliptic-curve based ones. The key share extension parsing dispatches on the negotiated group identifier. For X25519MLKEM768, the parser splits the incoming key share blob into the X25519 portion (32 bytes) and the ML-KEM-768 portion (1184 bytes), runs both key exchanges, and combines the resulting shared secrets per the IETF draft.
The combination is a SHA3-256 hash of the X25519 shared secret concatenated with the ML-KEM-768 shared secret, in the order specified by the draft. This combined value is then fed into TLS 1.3's HKDF extract step as the new master secret seed. From that point forward, the TLS handshake is identical to a classical TLS 1.3 handshake.
This separation is what lets Go (and other implementations) layer PQC into existing TLS code without rewriting the state machine. The cipher suite selection, the certificate verification, the Finished message exchange, all happen unchanged.
For a deeper dive into TLS 1.3 mechanics, see openssl PQC status 2026.
Go in Microservices and Container Workloads
Go is heavily used in container orchestration (Docker, Kubernetes, etcd, Consul, Nomad, Vault). These projects all use crypto/tls for their internal communications. As Go 1.24+ becomes the default for these projects, post-quantum TLS becomes default for cluster-internal communication.
This matters for harvest-now-decrypt-later threat modeling. A nation-state attacker collecting traffic between Kubernetes API servers and worker nodes today could not decrypt the captured data once a quantum computer arrives, if Go is on a recent version and post-quantum TLS is negotiated. The shift from classical to hybrid TLS in Go's standard library propagates into these projects on their normal release cadences.
Module-Level vs Standard-Library APIs
Go's preference is to graduate APIs from golang.org/x/crypto into the standard library only after the API has stabilized. This staging matters because:
- golang.org/x/crypto modules can break between minor versions, since the Go compatibility promise is weaker for x packages
- Standard-library packages have a stronger compatibility commitment, strict in 1.x lines
- Internal Google projects and large external Go consumers prefer standard library for stability
For ML-KEM specifically, the path was research code in x/crypto/mlkem, then refinement, then exposure through tls.X25519MLKEM768 in crypto/tls. The package golang.org/x/crypto/mlkem remains available for direct API use, but most users access ML-KEM through TLS.
For ML-DSA, expect a similar progression: x/crypto/mldsa, then incorporation into crypto/x509 for certificate handling, then standard library exposure.
Best Practices for Go Developers
For developers building TLS-based services in Go:
- Upgrade to Go 1.24 or later. ML-KEM hybrid TLS is enabled by default.
- Verify your peers also support hybrid groups. If you control both sides, this is automatic.
- Use crypto.Signer interfaces for signing code so you can swap to ML-DSA when it stabilizes.
- Plan for certificate size growth when ML-DSA reaches certificate verification. Server certificate chains will get larger.
For developers building libraries, expose algorithm parameters so users can pick ML-KEM-768 vs ML-KEM-1024 if they need higher security margins.
For a broader migration view, see AWS KMS quantum migration.
Go in Cloud-Native Ecosystem PQC Adoption
The CNCF (Cloud Native Computing Foundation) projects are largely written in Go. As Go's standard library adopts PQC, these projects gain it transparently:
- Kubernetes API server, kubelet, and controller manager use crypto/tls for cluster communication
- etcd uses crypto/tls for member-to-member and client communication
- Containerd, runc, and CRI-O use Go for container runtime work
- Prometheus, Grafana, and other observability tools use Go for HTTP servers
- Service meshes like Linkerd's data plane (formerly Linkerd2) use Go in places
The cumulative effect is that operators of Kubernetes clusters running Go 1.24+ binaries get post-quantum-protected internal communication once their nodes and operators are on recent Go versions. This is one of the broadest deployment vectors for PQC in production.
Verifying TLS Group Negotiation in Go Tests
For Go applications that want test coverage of PQC TLS negotiation, the crypto/tls package provides hooks. Test code can:
- Configure a tls.Config with specific CurvePreferences
- Negotiate a connection between a test server and client
- Inspect the resulting tls.ConnectionState to see which group was negotiated
This pattern is used in Go's own test suite for TLS and can be adopted by application test suites that need to verify post-quantum posture in CI.
For a broader testing context, see hybrid encryption.
Frequently Asked Questions
Does my Go web server use post-quantum TLS automatically?
If you are running Go 1.24 or later, your server advertises X25519MLKEM768 by default. Whether a given handshake uses it depends on the client. Modern Chrome, Firefox, and Go-based clients will negotiate it.
Can I disable post-quantum TLS in Go?
Yes. Set tls.Config.CurvePreferences to a list that excludes tls.X25519MLKEM768. This is mostly useful for compatibility with brittle middleboxes that cannot handle larger ClientHello messages.
Does golang.org/x/crypto/mlkem expose the raw KEM API?
Yes. Applications outside TLS can use ML-KEM directly from golang.org/x/crypto/mlkem for KEM-based protocols.
Is Go's ML-KEM implementation FIPS validated?
The Go cryptographic module follows the FIPS 203 specification. Go's BoringCrypto-based FIPS-validated builds are a separate distribution and follow CMVP timelines. Updated FIPS modules including ML-KEM are progressing through 2026.
Where can I read the Go source?
The repository is at go.googlesource.com/go (mirrored at github.com/golang/go). The post-quantum modules live in golang.org/x/crypto. TLS integration is in src/crypto/tls.
What if my Go version is too old?
Go 1.22 and earlier do not have native ML-KEM support. Upgrading is the cleanest fix. For projects pinned to older Go versions, third-party packages that wrap C libraries (cgo bindings to liboqs or AWS-LC) provide PQC primitives at the cost of cgo build complexity.
Does Go support stateful hash-based signatures like LMS?
LMS and HSS, defined in NIST SP 800-208, are not part of Go's standard library or x/crypto as of writing. Third-party packages provide LMS support for users who need it. The use case (firmware signing) is rare enough in Go's typical workloads that the standard library has not prioritized inclusion.
Can I use Go for PQC even when not building a TLS server?
Yes. golang.org/x/crypto/mlkem exposes the raw KEM API for use in custom protocols. Common patterns include using it for KEM-based session establishment outside TLS, file encryption with hybrid schemes, and message-level encryption in messaging applications.
Sources
- Go release notes, go.dev/doc/go1.23 and go.dev/doc/go1.24
- NIST FIPS 203 (Module-Lattice-Based Key-Encapsulation Mechanism), August 2024
- golang.org/x/crypto repository, github.com/golang/crypto
- IETF draft-kwiatkowski-tls-ecdhe-mlkem (X25519MLKEM768)
- Go security team posts at go.dev/blog
- Filippo Valsorda's reference implementations and posts at filippo.io
Related Articles
- What is post-quantum cryptography
- ML-KEM explained
- Hybrid encryption
- Rust rustls PQC
- Harvest now decrypt later
Protect Your Data Before Q-Day Arrives
QNSQY's NIST-standardized post-quantum encryption protects files against both current and quantum-era threats.