---
crypto/Kconfig | 10 ++++++++++
crypto/Makefile | 2 ++
2 files changed, 12 insertions(+)
diff --git a/crypto/Kconfig b/crypto/Kconfig
index bf8b8a60a0c0..45e376af02dc 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 093c56a45d3f..b181f8a54099 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
Meh. I forgot to git add crypto/mldsa.c.
David
---
diff --git a/crypto/Kconfig b/crypto/Kconfig
index bf8b8a60a0c0..45e376af02dc 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 093c56a45d3f..b181f8a54099 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");
> -----Original Message-----
> From: David Howells <dhowells@redhat.com>
> Sent: Monday, November 24, 2025 3:13 AM
> Subject: Re: [PATCH v10 5/8] crypto: Add ML-DSA crypto_sig support
...
> +++ b/crypto/mldsa.c
...
> +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 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;
> + }
In case there's any way userspace can trigger those, I'd rather
not have any WARN stack dumps.
On Mon, Nov 24, 2025 at 09:12:57AM +0000, David Howells wrote: > 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. > + */ Still not really sure what the point is. There's only one user of crypto_sig, and it could just call the ML-DSA functions directly. - Eric
Eric Biggers <ebiggers@kernel.org> wrote: > Still not really sure what the point is. There's only one user of > crypto_sig, and it could just call the ML-DSA functions directly. Is it your aim to kill off the crypto/ dir and all the (old) crypto API? Someone (not me) thought it worthwhile removing the akcipher algorithms out of crypto/asymmetric_keys/ and interfacing to them inside crypto_akcipher and crypto_sig. Anyway, I'll continue using crypto_sig as that provides module autoload capabilities - meaning we don't have to build all the algorithms into the base kernel. David
On Mon, Nov 24, 2025 at 6:25 PM David Howells <dhowells@redhat.com> wrote: > > Eric Biggers <ebiggers@kernel.org> wrote: > > > Still not really sure what the point is. There's only one user of > > crypto_sig, and it could just call the ML-DSA functions directly. > > Is it your aim to kill off the crypto/ dir and all the (old) crypto API? Probably entirely killing off the old API is going to be fraught because its abstraction has leaked out to userspace. But to the extent we can minimize its use over time, I think that's a good thing. Even for crypto usages that generalize to a few different ciphers of one variety or another, I think being explicit about which ciphers and having purpose-built dispatchers is usually a better route. Jason
Jason A. Donenfeld <Jason@zx2c4.com> wrote: > > > Still not really sure what the point is. There's only one user of > > > crypto_sig, and it could just call the ML-DSA functions directly. > > > > Is it your aim to kill off the crypto/ dir and all the (old) crypto API? > > Probably entirely killing off the old API is going to be fraught > because its abstraction has leaked out to userspace. But to the extent > we can minimize its use over time, I think that's a good thing. Even > for crypto usages that generalize to a few different ciphers of one > variety or another, I think being explicit about which ciphers and > having purpose-built dispatchers is usually a better route. How are you proposing handling the autoloading feature of the old API? David
On Mon, Nov 24, 2025 at 8:54 PM David Howells <dhowells@redhat.com> wrote: > > > > Still not really sure what the point is. There's only one user of > > > > crypto_sig, and it could just call the ML-DSA functions directly. > > > > > > Is it your aim to kill off the crypto/ dir and all the (old) crypto API? > > > > Probably entirely killing off the old API is going to be fraught > > because its abstraction has leaked out to userspace. But to the extent > > we can minimize its use over time, I think that's a good thing. Even > > for crypto usages that generalize to a few different ciphers of one > > variety or another, I think being explicit about which ciphers and > > having purpose-built dispatchers is usually a better route. > > How are you proposing handling the autoloading feature of the old API? I don't know. Not all features will have direct replacements. Not all usages will be replaced. Not all use cases benefit from being replaced. You asked if it was an "aim." I replied by telling you that I think killing it is going to be difficult, but that over time, usage will decline. I think that'll be a natural thing. For now, when something uses the library API, there's a pretty easy and obvious case to be made for it, as there are still such obvious low hanging use cases. I suppose in a while, we might run out of those perhaps. But that hasn't happened yet, I guess. Jason
On Mon, Nov 24, 2025 at 09:10:33PM +0100, Jason A. Donenfeld wrote: > On Mon, Nov 24, 2025 at 8:54 PM David Howells <dhowells@redhat.com> wrote: > > > > > Still not really sure what the point is. There's only one user of > > > > > crypto_sig, and it could just call the ML-DSA functions directly. > > > > > > > > Is it your aim to kill off the crypto/ dir and all the (old) crypto API? > > > > > > Probably entirely killing off the old API is going to be fraught > > > because its abstraction has leaked out to userspace. But to the extent > > > we can minimize its use over time, I think that's a good thing. Even > > > for crypto usages that generalize to a few different ciphers of one > > > variety or another, I think being explicit about which ciphers and > > > having purpose-built dispatchers is usually a better route. > > > > How are you proposing handling the autoloading feature of the old API? > > I don't know. Not all features will have direct replacements. Not all > usages will be replaced. Not all use cases benefit from being > replaced. You asked if it was an "aim." I replied by telling you that > I think killing it is going to be difficult, but that over time, usage > will decline. I think that'll be a natural thing. For now, when > something uses the library API, there's a pretty easy and obvious case > to be made for it, as there are still such obvious low hanging use > cases. I suppose in a while, we might run out of those perhaps. But > that hasn't happened yet, I guess. > > Jason +1 to what Jason said. The traditional API generally isn't going away. However, there's no need to add new functionality to it when the library is a better fit. The crypto_sig abstraction doesn't seem very helpful, since it was added only recently and has only one user (public_key). The traditional crypto API's dynamic loading by name also tends to be more harmful than helpful. Linux users and distros keep running into problems where algorithms aren't available in the initramfs when they should be, or where the slow generic code is used instead of the optimized code. The direct linking finally just fixes that. You may also still be thinking of the ML-DSA code as something heavyweight. I reduced it to under 4 KB of object code. It should also become the recommended algorithm anyway, right? Either way, 4 KB seems awfully small to be wanting to be dynamically loaded. Last year I shrunk the x86_64 AES-GCM code (which most Linux distros build in to avoid the dynamic loading issues) by over 200 KB. No one even seemed to care that much... We can add a lot of stuff before we're even back to where we were before that. - Eric
© 2016 - 2026 Red Hat, Inc.