Article summary — original

Cloudflare Workers Adds Experimental Post-Quantum Cryptography Support to Web Crypto Cloudflare Workers has introduced support for post-quantum-resistant algorithms within its Web Crypto API implementation under an opt-in compatibility flag, enabling developers to test ML-KEM and ML-DSA primitives directly in the runtime. Workers added support for ML-KEM (ML-KEM-768 and ML-KEM-1024) and ML-DSA (ML-DSA-44, ML-DSA-65, and ML-DSA-87) behind the `webcrypto_modern_algorithms` flag. The implementation is integrated into the open-source workerd runtime and backed by native BoringSSL primitives, avoiding the need for developers to bundle external JavaScript or WebAssembly crypto libraries. New helper methods including `getPublicKey()`, `SubtleCrypto.supports()`, and encapsulation/decapsulation APIs were introduced alongside the primitives. ML-KEM-512 and several other draft WICG algorithms—such as SHA-3, ChaCha20-Poly1305, cSHAKE, and TurboSHAKE—are excluded from this initial release. Post-Quantum Primitives in Web Crypto Developers preparing for the post-quantum transition can now access key encapsulation (ML-KEM) and digital signature (ML-DSA) algorithms directly through Workers' Web Crypto API. Supported algorithms include ML-KEM-768, ML-KEM-1024, ML-DSA-44, ML-DSA-65, and ML-DSA-87. ML-KEM-512 is excluded because it is not exposed by the version of BoringSSL used by Workers. Because the underlying specification remains an evolving W3C Web Incubator Community Group (WICG) draft, these capabilities are opt-in and gated behind the `webcrypto_modern_algorithms` compatibility flag. Runtime Integration and Helper APIs The feature integrates into Cloudflare's open-source workerd runtime using native BoringSSL primitives, accompanied by Web Platform Tests and updated TypeScript definitions. Native support allows downstream libraries—such as JOSE or HPKE implementations—to delegate cryptographic tasks directly to the runtime instead of bundling external JavaScript or WebAssembly libraries. The update also brings new helper methods, such as `getPublicKey()` for deriving public keys from loaded private keys, as well as `encapsulateBits()`, `decapsulateBits()`, `encapsulateKey()`, `decapsulateKey()`, and `SubtleCrypto.supports()`. Scope, Practical Trade-Offs, and Future Roadmap The release focuses strictly on ML-KEM, ML-DSA, JWK support, and helper APIs, deliberately leaving out other WICG-proposed algorithms such as SHA-3, cSHAKE, TurboSHAKE, and ChaCha20-Poly1305 for future review. Cloudflare cautions that while native runtime execution reduces application bundle sizes and improves performance, ML-DSA public keys and signatures remain significantly larger than classic counterparts like RSA or Ed25519, resulting in increased storage and wire-transfer sizes.

Article summary — zh

Cloudflare Workers 在 Web Crypto 中支持 ML-KEM 与 ML-DSA 等后量子加密算法 Cloudflare Workers 宣布在其 Web Crypto 实现中引入对 ML-KEM 和 ML-DSA 等抗后量子算法的支持,开发者无需再自行打包加密库即可直接在运行时中测试与验证后量子协议。 特性需通过 webcrypto_modern_algorithms 兼容性标志启用,底层由 workerd 和 BoringSSL 提供支持。 首批支持 ML-KEM-768/1024 与 ML-DSA-44/65/87,暂不支持 ML-KEM-512 及 SHA-3 等其他 WICG 提议算法。 新增了 getPublicKey() 等辅助 API,并已通过 panva/jose 与 panva/hpke 测试套件验证。 解决后量子加密生态的集成痛点 以往在 JavaScript 环境中尝试后量子密码学,开发者要么无法直接基于 Web Crypto 构建,要么需要通过 JS 或 WebAssembly 自行打包加密实现,导致应用体积膨胀且下游重复劳动。随着向抗量子密码过渡的紧迫性提升,在运行时中原生提供底层原语成为减少打包负担并推动协议(如 HPKE、OHTTP 及 JOSE)测试的关键。 首批支持的算法与底层实现范围 该功能基于 V8 运行时 workerd 的 Web Crypto 层,底层由 BoringSSL 原语支撑。目前具体支持 ML-KEM-768、ML-KEM-1024 密钥封装机制,以及 ML-DSA-44、ML-DSA-65、ML-DSA-87 签名算法;因 BoringSSL 版本未暴露,暂不支持 ML-KEM-512。此外,WICG 提议中的 SHA-3、ChaCha20-Poly1305、cSHAKE 等暂未纳入本次变更。 辅助 API 与实验性使用建议 实现中还包含了 getPublicKey() 辅助 API,便于直接从私钥导出公钥,减少跨库样板代码。由于 WICG 规范仍在制定中,相关能力目前必须通过 webcrypto_modern_algorithms 标志开启,且跨跨运行时使用时需先检测 API 是否存在;同时开发者需注意 ML-DSA 相比传统算法在公钥和签名体积上有显著增加。

Saved original article

Today, Cloudflare Workers is adding support for post-quantum-resistant algorithms within Web Crypto. These are defined in [Modern Algorithms in the Web Cryptography API](https://wicg.github.io/webcrypto-modern-algos/) draft [community group report](https://www.w3.org/standards/types/#reports), and include: `encapsulateBits()`, `decapsulateBits()`, `encapsulateKey()`, and `decapsulateKey()``getPublicKey()``SubtleCrypto.supports()` For developers preparing for the post-quantum transition, these opt-in Web Crypto APIs make it easier to experiment with ML-KEM and ML-DSA without bundling a separate cryptographic implementation. They do not provide a full migration path, but rather building blocks that can be used to validate your integration. This support is available behind the `webcrypto_modern_algorithms` compatibility flag while the specification is still moving. [Web Crypto](https://developer.mozilla.org/en-US/docs/Web/API/Web_Crypto_API) is one of those APIs you only notice when it lacks the primitive you need. If you want to experiment with newer post-quantum algorithms in a JavaScript environment, it’s hard. You either cannot build the protocol directly on top of Web Crypto, or you bring your own cryptography implementation in JavaScript or WebAssembly. Neither option is ideal. They put the burden of selecting and maintaining cryptographic implementations on implementers, who see their applications get larger as they bundle cryptographic code. And this is work that needs to be reproduced for all downstream libraries. As the ecosystem needs to transition to post-quantum-resistant algorithms [sooner than expected](https://blog.cloudflare.com/post-quantum-roadmap/), we [cannot wait](https://blog.cloudflare.com/ml-dsa-will-have-to-do/) for better post-quantum algorithms. Developers need access to these primitives now so they can test, evaluate, and improve post-quantum integrations. In this post, we’ll explain how you can implement these primitives today, and start to prepare your applications for the post-quantum era. Here is what ML-KEM looks like in Workers. One side has a public key. The other side encapsulates a shared secret to that public key. The holder of the private key decapsulates it and gets the same secret. There is no encryption in that snippet yet. ML-KEM gives both sides shared key material. Protocols such as Hybrid Public Key Encryption ([HPKE](https://www.rfc-editor.org/rfc/rfc9180.html)) then feed that material into a key schedule and an AEAD such as the AES-GCM algorithm. ML-DSA is closer to what most developers have already seen with Ed25519 or ECDSA: generate a key pair, sign bytes, verify bytes. These examples are deliberately small. They are not protocols. They are the JavaScript hooks for cryptographic primitives that protocols need. Post-quantum migration is not one switch. It is a lot of protocols, libraries, services, and deployment environments learning how to use different primitives. Some of that work is already visible in TLS and SSH. OpenSSH added [support for mlkem768x25519](https://www.openssh.org/pq.html) in 2024. HPKE has a [draft for post-quantum and hybrid KEMs](https://datatracker.ietf.org/doc/html/draft-ietf-hpke-pq-05) ongoing at the IETF. The IETF published [RFC 9964](https://www.rfc-editor.org/rfc/rfc9964.html) for ML-DSA in JOSE, as well as an [adopted draft](https://datatracker.ietf.org/doc/draft-ietf-jose-hpke-pq-pqt/) for JWE using PQ & PQ/T HPKE. HTTP Message Signatures can use [different signature algorithms](https://www.iana.org/assignments/http-message-signature/http-message-signature.xhtml), as long as the signer and verifier agree on how to produce and verify the signature. To support all these on Cloudflare Workers, developers needed support for the underlying cryptographic primitives within Web Crypto. Without it, a Workers developer could still experiment with post-quantum code, but they had to bundle a separate implementation. That is useful for portability and for early experiments, but it is not where we want every production application to end up. Signed JSON Web Tokens (JWTs) are a familiar example that protect using JSON Web Signatures (JWS). With a [panva/jose](https://github.com/panva/jose) library that maps ML-DSA-\* algorithms to Web Crypto, the application code is as follows: JWTs are only one example. The larger point is that libraries can delegate ML-DSA operations to the runtime instead of carrying their own implementation for every environment. With Workers supporting ML-DSA natively, libraries can delegate signing to the runtime rather than shipping their own implementation. ML-KEM is a key encapsulation mechanism. On its own, it gives two parties shared key material. HPKE turns that into a complete encryption construction by adding a key schedule and an AEAD. Libraries such as [panva/hpke](https://github.com/panva/hpke) are already structured around Web Crypto and runtime support. With the Workers runtime exposing ML-KEM, HPKE implementations can use the native primitive where available. This is the shape we want for protocols such as [OHTTP](https://datatracker.ietf.org/doc/html/rfc9458) as well (which we’ve [discussed before](https://blog.cloudflare.com/stronger-than-a-promise-proving-oblivious-http-privacy-properties/)). OHTTP uses HPKE. If HPKE can use a post-quantum KEM through Web Crypto, then that peer can start discussing migrating to a ciphersuite that supports these primitives. Libraries may require runtime-specific integration changes. Here, `HPKE.CipherSuite` selects implementations according to the algorithms available in the runtime. Several protocols need to publish or derive a public key after loading a private key. Previously, this often meant keeping both around or doing format-specific work. The new `getPublicKey()` helper does the direct thing: For ML-KEM, the usage is different because public keys encapsulate and private keys decapsulate: This is a small API that aims to remove code used a lot across libraries that deal with public key cryptography. Because the API is not yet supported across runtimes, libraries should check for it instead of assuming it exists everywhere. Libraries that run across Workers, [Node.js](https://github.com/nodejs/node), [Deno](https://github.com/denoland/deno/), browsers, and other Web-interoperable runtimes need this kind of check. It also helps when only part of the modern algorithms proposal is implemented. The initial Workers implementation supports ML-KEM-768 as a KEM and ML-DSA-44 as a signature algorithm. All require the `webcrypto_modern_algorithms` flag to [be set](https://developers.cloudflare.com/workers/configuration/compatibility-flags/). For completeness, we also support ML-KEM-1024, ML-DSA-65, and ML-DSA-87. ML-KEM-512 is not supported because the BoringSSL version used by Workers does not expose it. Rather than add a separate implementation just for that variant, we are starting with the algorithms available through the native crypto library. The most recent list of supported algorithms can always be found on our [developer documentation](https://developers.cloudflare.com/workers/runtime-apis/web-crypto/). Workers run on [workerd](https://github.com/cloudflare/workerd). It’s an [open-source runtime](https://blog.cloudflare.com/workerd-open-source-workers-runtime/) built on V8. The implementation adds ML-KEM and ML-DSA support to workerd's Web Crypto layer, backed by BoringSSL primitives. This change also adds [Web Platform Tests](https://web-platform-tests.org/) for the modern algorithms API surface, Workers-specific tests for compatibility flag behavior, and TypeScript definitions under the new Workers types. We split this out from a [larger proposal](https://github.com/cloudflare/workerd/pull/6403) from [panva](https://github.com/panva/). The change discussed in this blog, which is the first part of the modern Web Crypto algorithm specification, focuses on ML-KEM, ML-DSA, helper APIs, and JWK support. Other algorithms from the W3C Web Incubator Community Group (WICG) proposal, such as SHA-3, cSHAKE, TurboSHAKE, and ChaCha20-Poly1305, are not part of this initial change. That smaller scope makes review easier. It also gives library authors something concrete to test before the whole modern algorithms proposal is implemented. Note that ML-DSA public keys and signatures are [substantially larger](https://blog.cloudflare.com/ml-dsa-will-have-to-do/#the-signature-algorithms) than RSA or Ed25519. The integration of these algorithms in the runtime improves performance and reduces the need for bundling. However, it does not change the reality that the size of keys, signatures, or ciphertext is increasing, on the wire or when stored. The [WICG proposal](https://wicg.github.io/webcrypto-modern-algos/) covers more than ML-KEM and ML-DSA. We have not implemented the following from the original contribution by Filip Skokan in [cloudflare/workerd#6403](https://github.com/cloudflare/workerd/pull/6403), which will need further review. This includes the SHA-3 hash function, ChaCha20-Poly1305 AEAD (discussion about XChaCha20-Poly1305 in [wicg/webcrypto-modern-algos#1](https://github.com/WICG/webcrypto-modern-algos/issues/1)), cSHAKE, TurboSHAKE, and HPKE (discussed in [wicg/webcrypto-modern-algos#2](https://github.com/WICG/webcrypto-modern-algos/issues/2)). An implementation has already been tested against [panva/hpke](https://github.com/panva/hpke) and [panva/jose](https://github.com/panva/jose) test suites to verify the implementation. There is also a practical question about when this should become default, rather than opt-in. For now, all these algorithms are gated behind a compatibility flag. The API is based on a draft, and we want feedback from library authors before treating it as stable. This change does not make every protocol post-quantum by itself. It gives Workers developers and library authors the primitives they were missing: ML-KEM for key encapsulation, ML-DSA for signatures, and helper APIs that make those primitives usable through Web Crypto. If you maintain a library that currently bundles its own post-quantum implementation, this is a good time to try the native API and tell us what does not fit. The fastest way to find the rough edges is to put real protocol code on top of it. All the details are in [our changelog](https://developers.cloudflare.com/changelog/). We would like to thank Filip Skokan for the original contribution and iterations, Felix Hanau, James Snell, Bas Westerbaan, and Peter Wu for reviewing the code, and Daniel Huigens for co-authoring the specification work this implementation follows.