Skip to content

Post-Quantum Cryptography (PQC) support#720

Open
karel-m wants to merge 6 commits intodevelopfrom
pr/pqc1
Open

Post-Quantum Cryptography (PQC) support#720
karel-m wants to merge 6 commits intodevelopfrom
pr/pqc1

Conversation

@karel-m
Copy link
Copy Markdown
Member

@karel-m karel-m commented Apr 12, 2026

This pull request introduces an initial proposal for Post-Quantum Cryptography (PQC) support

It adds support for the following NIST PQC standards:

  • FIPS 203: Module-Lattice-Based Key Encapsulation Mechanism (ML-KEM)
  • FIPS 204: Module-Lattice-Based Digital Signature Standard (ML-DSA)
  • FIPS 205: Stateless Hash-Based Digital Signature Standard (SLH-DSA)

Further details on the standards can be found here: https://csrc.nist.gov/projects/post-quantum-cryptography#pqc-standards

The implementation is based on the official reference implementations (all of them public domain):

I also considered adding support for NTRU Prime (as currently used for hybrid kex in OpenSSH 9), but it appears that the OpenSSH project is planning to move to ML-KEM in version 10. Therefore, I kept only the NIST PQC stuff.

A new public API has been introduced in: src/headers/tomcrypt_pqc.h The aim was to keep the interface simple/compact (unfortunately PQC itself is far from being simple/compact), while aligning with existing LTC design patterns.

At present, the test coverage is limited to basic functional checks:

  • key generation + encapsulation + decapsulation (ML-KEM)
  • key generation + signing + verification (ML-DSA, SLH-DSA)

MISSING: Official NIST test vectors still need to be identified (ACVP?) and added to the test suite.

MISSING: Interoperability with other crypto libraries was not tested at all.

MISSING: Functions for key import/export currently handle only raw data; sooner or later PKCS#8 (for privkeys) and/or SPKI/X.509 (for pubkeys) will be probably needed.

IMPORTANT: The code in this initial PR is very lightly tested and is not suitable for production use.

This change is intended as a first step towards PQC support and is open for discussion, review, and further improvements.

Checklist

  • documentation is added or updated
  • tests are added or updated

@karel-m karel-m requested a review from sjaeckel April 12, 2026 15:17
@karel-m karel-m mentioned this pull request Apr 12, 2026
5 tasks
@karel-m
Copy link
Copy Markdown
Member Author

karel-m commented Apr 12, 2026

As for key formats, there are some very recent standards:

  • RFC 9935 (March 2026) defines ML-KEM in X.509/PKIX, including subject public keys and private keys.
  • RFC 9909 (December 2025) defines SLH-DSA in X.509/PKIX, including public keys, signatures and private keys.
  • RFC 9881 (October 2025) defines ML-DSA for X.509 certificates and CRLs, including subject public keys, signatures and private keys.

It looks doable with the infrastructure we have in LTC, but quite a lot of work. It may be worth creating a separate PR.

@VA1DER
Copy link
Copy Markdown

VA1DER commented Apr 13, 2026

I don't know what OpenSSH's plan is for hybridizing any or all of these, but sntrup761x25519 was a very, very good idea in that it is provably at least as secure as both. There are still questions about the FIPS PQ algos' classic security. I would encourage dialog with the OpenSSH project to replicate this great idea. And with Jan Mojžíš of TinySSH who was, I understand, the driver behind that idea originally. Curve448 would be a great primitive to use for this, as it has some support already in several implementations (and in OpenSSL).

Secondly, does your implementation include the 256-bit (classic-strength) versions of these? ML-KEM-1024 & ML-DSA-87?

@karel-m
Copy link
Copy Markdown
Member Author

karel-m commented Apr 14, 2026

We support all parameter sets defined in NIST FIPS 203:

  • ML-KEM-512 = LTC_MLKEM_512
  • ML-KEM-768 = LTC_MLKEM_768
  • ML-KEM-1024 = LTC_MLKEM_1024

We also support all parameter sets defined in NIST FIPS 204:

  • ML-DSA-44 = LTC_MLDSA_44
  • ML-DSA-65 = LTC_MLDSA_65
  • ML-DSA-87 = LTC_MLDSA_87

And all from NIST FIPS 205:

  • SLH-DSA-SHAKE-128s = LTC_SLHDSA_SHAKE_128S
  • SLH-DSA-SHAKE-128f = LTC_SLHDSA_SHAKE_128F
  • SLH-DSA-SHAKE-192s = LTC_SLHDSA_SHAKE_192S
  • SLH-DSA-SHAKE-192f = LTC_SLHDSA_SHAKE_192F
  • SLH-DSA-SHAKE-256s = LTC_SLHDSA_SHAKE_256S
  • SLH-DSA-SHAKE-256f = LTC_SLHDSA_SHAKE_256F
  • SLH-DSA-SHA2-128s = LTC_SLHDSA_SHA2_128S
  • SLH-DSA-SHA2-128f = LTC_SLHDSA_SHA2_128F
  • SLH-DSA-SHA2-192s = LTC_SLHDSA_SHA2_192S
  • SLH-DSA-SHA2-192f = LTC_SLHDSA_SHA2_192F
  • SLH-DSA-SHA2-256s = LTC_SLHDSA_SHA2_256S
  • SLH-DSA-SHA2-256f = LTC_SLHDSA_SHA2_256F

So yes, this includes the higher-security parameter sets such as ML-KEM-1024 and ML-DSA-87.

As for OpenSSh see https://www.openssh.org/releasenotes.html it looks as they already switched the default to mlkem768x25519-sha256 in OpenSSH 9.9.

On adding further algorithms such as NTRU Prime 761, our preference is to follow widely adopted standards. NIST remains a credible standards body (even if some people see it negatively for geopolitical reasons). In the past, we added a few algorithms that were close to becoming standards but never quite got there and that usually created extra maintenance work.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants