On Tue, Jan 20, 2026 at 02:50:47PM +0000, David Howells wrote: > Add verify-only public key crypto support for ML-DSA so that the > X.509/PKCS#7 signature verification code, as used by module signing, > amongst other things, can make use of it through the common crypto_sig API. > > Signed-off-by: David Howells <[email protected]> > cc: Eric Biggers <[email protected]> > cc: Lukas Wunner <[email protected]> > cc: Ignat Korchagin <[email protected]> > cc: Stephan Mueller <[email protected]> > cc: Herbert Xu <[email protected]> > cc: [email protected] > cc: [email protected] > --- > crypto/Kconfig | 10 +++ > crypto/Makefile | 2 + > crypto/mldsa.c | 201 ++++++++++++++++++++++++++++++++++++++++++++++++ > 3 files changed, 213 insertions(+) > create mode 100644 crypto/mldsa.c > > diff --git a/crypto/Kconfig b/crypto/Kconfig > index 12a87f7cf150..8dd5c6660c5a 100644 > --- a/crypto/Kconfig > +++ b/crypto/Kconfig > @@ -344,6 +344,16 @@ config CRYPTO_ECRDSA > One of the Russian cryptographic standard algorithms (called GOST > algorithms). Only signature verification is implemented. > > +config CRYPTO_MLDSA > + tristate "ML-DSA (Module-Lattice-Based Digital Signature Algorithm)" > + select CRYPTO_SIG > + select CRYPTO_LIB_MLDSA > + select CRYPTO_LIB_SHA3 > + help > + ML-DSA (Module-Lattice-Based Digital Signature Algorithm) (FIPS-204). > + > + Only signature verification is implemented. > + > endmenu > > menu "Block ciphers" > diff --git a/crypto/Makefile b/crypto/Makefile > index 23d3db7be425..267d5403045b 100644 > --- a/crypto/Makefile > +++ b/crypto/Makefile > @@ -60,6 +60,8 @@ ecdsa_generic-y += ecdsa-p1363.o > ecdsa_generic-y += ecdsasignature.asn1.o > obj-$(CONFIG_CRYPTO_ECDSA) += ecdsa_generic.o > > +obj-$(CONFIG_CRYPTO_MLDSA) += mldsa.o > + > crypto_acompress-y := acompress.o > crypto_acompress-y += scompress.o > obj-$(CONFIG_CRYPTO_ACOMP2) += crypto_acompress.o > diff --git a/crypto/mldsa.c b/crypto/mldsa.c > new file mode 100644 > index 000000000000..2146c774b5ca > --- /dev/null > +++ b/crypto/mldsa.c > @@ -0,0 +1,201 @@ > +// SPDX-License-Identifier: GPL-2.0-or-later > +/* > + * crypto_sig wrapper around ML-DSA library. > + */ > +#include <linux/init.h> > +#include <linux/module.h> > +#include <crypto/internal/sig.h> > +#include <crypto/mldsa.h> > + > +struct crypto_mldsa_ctx { > + u8 pk[MAX(MAX(MLDSA44_PUBLIC_KEY_SIZE, > + MLDSA65_PUBLIC_KEY_SIZE), > + MLDSA87_PUBLIC_KEY_SIZE)]; > + unsigned int pk_len; > + enum mldsa_alg strength; > + u8 key_set; > +}; > + > +static int crypto_mldsa_sign(struct crypto_sig *tfm, > + const void *msg, unsigned int msg_len, > + void *sig, unsigned int sig_len) > +{ > + return -EOPNOTSUPP; > +} > + > +static int crypto_mldsa_verify(struct crypto_sig *tfm, > + const void *sig, unsigned int sig_len, > + const void *msg, unsigned int msg_len) > +{ > + const struct crypto_mldsa_ctx *ctx = crypto_sig_ctx(tfm); > + > + if (unlikely(!ctx->key_set)) > + return -EINVAL; > + > + return mldsa_verify(ctx->strength, sig, sig_len, msg, msg_len, > + ctx->pk, ctx->pk_len); > +} > + > +static unsigned int crypto_mldsa_key_size(struct crypto_sig *tfm) > +{ > + struct crypto_mldsa_ctx *ctx = crypto_sig_ctx(tfm); > + > + switch (ctx->strength) { > + case MLDSA44: > + return MLDSA44_PUBLIC_KEY_SIZE; > + case MLDSA65: > + return MLDSA65_PUBLIC_KEY_SIZE; > + case MLDSA87: > + return MLDSA87_PUBLIC_KEY_SIZE; > + default: > + WARN_ON_ONCE(1); > + return 0; > + } > +} > + > +static int crypto_mldsa_set_pub_key(struct crypto_sig *tfm, > + const void *key, unsigned int keylen) > +{ > + struct crypto_mldsa_ctx *ctx = crypto_sig_ctx(tfm); > + unsigned int expected_len = crypto_mldsa_key_size(tfm); > + > + if (keylen != expected_len) > + return -EINVAL; > + > + ctx->pk_len = keylen; > + memcpy(ctx->pk, key, keylen); > + ctx->key_set = true; > + return 0; > +} > + > +static int crypto_mldsa_set_priv_key(struct crypto_sig *tfm, > + const void *key, unsigned int keylen) > +{ > + return -EOPNOTSUPP; > +} > + > +static unsigned int crypto_mldsa_max_size(struct crypto_sig *tfm) > +{ > + struct crypto_mldsa_ctx *ctx = crypto_sig_ctx(tfm); > + > + switch (ctx->strength) { > + case MLDSA44: > + return MLDSA44_SIGNATURE_SIZE; > + case MLDSA65: > + return MLDSA65_SIGNATURE_SIZE; > + case MLDSA87: > + return MLDSA87_SIGNATURE_SIZE; > + default: > + WARN_ON_ONCE(1); > + return 0; > + } > +} > + > +static int crypto_mldsa44_alg_init(struct crypto_sig *tfm) > +{ > + struct crypto_mldsa_ctx *ctx = crypto_sig_ctx(tfm); > + > + ctx->strength = MLDSA44; > + ctx->key_set = false; > + return 0; > +} > + > +static int crypto_mldsa65_alg_init(struct crypto_sig *tfm) > +{ > + struct crypto_mldsa_ctx *ctx = crypto_sig_ctx(tfm); > + > + ctx->strength = MLDSA65; > + ctx->key_set = false; > + return 0; > +} > + > +static int crypto_mldsa87_alg_init(struct crypto_sig *tfm) > +{ > + struct crypto_mldsa_ctx *ctx = crypto_sig_ctx(tfm); > + > + ctx->strength = MLDSA87; > + ctx->key_set = false; > + return 0; > +} > + > +static void crypto_mldsa_alg_exit(struct crypto_sig *tfm) > +{ > +} > + > +static struct sig_alg crypto_mldsa_algs[] = { > + { > + .sign = crypto_mldsa_sign, > + .verify = crypto_mldsa_verify, > + .set_pub_key = crypto_mldsa_set_pub_key, > + .set_priv_key = crypto_mldsa_set_priv_key, > + .key_size = crypto_mldsa_key_size, > + .max_size = crypto_mldsa_max_size, > + .init = crypto_mldsa44_alg_init, > + .exit = crypto_mldsa_alg_exit, > + .base.cra_name = "mldsa44", > + .base.cra_driver_name = "mldsa44-lib", > + .base.cra_ctxsize = sizeof(struct crypto_mldsa_ctx), > + .base.cra_module = THIS_MODULE, > + .base.cra_priority = 5000, > + }, { > + .sign = crypto_mldsa_sign, > + .verify = crypto_mldsa_verify, > + .set_pub_key = crypto_mldsa_set_pub_key, > + .set_priv_key = crypto_mldsa_set_priv_key, > + .key_size = crypto_mldsa_key_size, > + .max_size = crypto_mldsa_max_size, > + .init = crypto_mldsa65_alg_init, > + .exit = crypto_mldsa_alg_exit, > + .base.cra_name = "mldsa65", > + .base.cra_driver_name = "mldsa65-lib", > + .base.cra_ctxsize = sizeof(struct crypto_mldsa_ctx), > + .base.cra_module = THIS_MODULE, > + .base.cra_priority = 5000, > + }, { > + .sign = crypto_mldsa_sign, > + .verify = crypto_mldsa_verify, > + .set_pub_key = crypto_mldsa_set_pub_key, > + .set_priv_key = crypto_mldsa_set_priv_key, > + .key_size = crypto_mldsa_key_size, > + .max_size = crypto_mldsa_max_size, > + .init = crypto_mldsa87_alg_init, > + .exit = crypto_mldsa_alg_exit, > + .base.cra_name = "mldsa87", > + .base.cra_driver_name = "mldsa87-lib", > + .base.cra_ctxsize = sizeof(struct crypto_mldsa_ctx), > + .base.cra_module = THIS_MODULE, > + .base.cra_priority = 5000, > + }, > +}; > + > +static int __init mldsa_init(void) > +{ > + int ret, i; > + > + for (i = 0; i < ARRAY_SIZE(crypto_mldsa_algs); i++) { > + ret = crypto_register_sig(&crypto_mldsa_algs[i]); > + if (ret < 0) > + goto error; > + } > + return 0; > + > +error: > + pr_err("Failed to register (%d)\n", ret); > + for (i--; i >= 0; i--) > + crypto_unregister_sig(&crypto_mldsa_algs[i]); > + return ret; > +} > +module_init(mldsa_init); > + > +static void mldsa_exit(void) > +{ > + for (int i = 0; i < ARRAY_SIZE(crypto_mldsa_algs); i++) > + crypto_unregister_sig(&crypto_mldsa_algs[i]); > +} > +module_exit(mldsa_exit); > + > +MODULE_LICENSE("GPL"); > +MODULE_DESCRIPTION("Crypto API support for ML-DSA signature verification"); > +MODULE_ALIAS_CRYPTO("mldsa44"); > +MODULE_ALIAS_CRYPTO("mldsa65"); > +MODULE_ALIAS_CRYPTO("mldsa87"); >
Went through it, not much else to say, as it just binds the callbacks: Reviewed-by: Jarkko Sakkinen <[email protected]> BR, Jarkko
