[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20251114130417.1756230-4-dhowells@redhat.com>
Date: Fri, 14 Nov 2025 13:04:06 +0000
From: David Howells <dhowells@...hat.com>
To: Herbert Xu <herbert@...dor.apana.org.au>
Cc: David Howells <dhowells@...hat.com>,
Eric Biggers <ebiggers@...nel.org>,
Luis Chamberlain <mcgrof@...nel.org>,
Petr Pavlu <petr.pavlu@...e.com>,
Daniel Gomez <da.gomez@...nel.org>,
Sami Tolvanen <samitolvanen@...gle.com>,
"Jason A . Donenfeld" <Jason@...c4.com>,
Ard Biesheuvel <ardb@...nel.org>,
Stephan Mueller <smueller@...onox.de>,
Lukas Wunner <lukas@...ner.de>,
Ignat Korchagin <ignat@...udflare.com>,
linux-crypto@...r.kernel.org,
keyrings@...r.kernel.org,
linux-modules@...r.kernel.org,
linux-kernel@...r.kernel.org
Subject: [PATCH v8 3/9] mldsa: Add a simpler API
Add a simpler ML-DSA API to hide all the details of packing/unpacking keys
and signatures.
Signed-off-by: David Howells <dhowells@...hat.com>
---
Documentation/crypto/index.rst | 1 +
Documentation/crypto/mldsa.rst | 111 +++++++++++++++++++
include/crypto/mldsa.h | 34 ++++++
lib/crypto/mldsa/Makefile | 3 +-
lib/crypto/mldsa/crypto_mldsa.c | 4 +-
lib/crypto/mldsa/mldsa_api.c | 186 ++++++++++++++++++++++++++++++++
6 files changed, 335 insertions(+), 4 deletions(-)
create mode 100644 Documentation/crypto/mldsa.rst
create mode 100644 include/crypto/mldsa.h
create mode 100644 lib/crypto/mldsa/mldsa_api.c
diff --git a/Documentation/crypto/index.rst b/Documentation/crypto/index.rst
index 4ee667c446f9..4498fc92bfc5 100644
--- a/Documentation/crypto/index.rst
+++ b/Documentation/crypto/index.rst
@@ -28,3 +28,4 @@ for cryptographic use cases, as well as programming examples.
device_drivers/index
krb5
sha3
+ mldsa
diff --git a/Documentation/crypto/mldsa.rst b/Documentation/crypto/mldsa.rst
new file mode 100644
index 000000000000..3dcf9c0f1203
--- /dev/null
+++ b/Documentation/crypto/mldsa.rst
@@ -0,0 +1,111 @@
+.. SPDX-License-Identifier: GPL-2.0-or-later
+
+===========================
+ML-DSA Algorithm Collection
+===========================
+
+.. contents::
+
+ - Overview
+ - Library API
+ - References
+ - API Function Reference
+
+
+Overview
+========
+
+The ML-DSA algorithm, as specified in NIST FIPS-204 [1]_, is a "Post Quantum"
+asymmetric cipher/public key algorithm. It has digestion of the message to be
+signed built in to the algorithm, though options exist to do that separately
+(those aren't supported in the API presented here, however). The algorithm
+used to digest the message in this implementation is SHAKE256, though in theory
+other algorithms can be used too.
+
+This implementation only supports signature verification and does not support
+keypair generation or signing.
+
+Three strengths are provided:
+
+ - ML-DSA 44
+ - ML-DSA 65
+ - ML-DSA 87
+
+This document describes the ML-DSA library API.
+
+The algorithms are also available through the crypto_sig API, though
+`-EOPNOTSUPP` will be returned if any of the API functions involved in signing
+a message are invoked.
+
+
+Library API
+===========
+
+To use this::
+
+ #include <crypto/mldsa.h>
+
+must be included.
+
+To perform single-step verification of a signature, the following function can
+be used::
+
+ int mldsa_verify(enum mldsa_type type,
+ const void *pk, size_t pk_len,
+ const uint8_t *data, size_t data_len,
+ const void *sig, size_t sig_len);
+
+This takes an optional key type, public key, signature and the complete message
+as a single buffer. The type should be one of::
+
+ MLDSA_UNKNOWN
+ MLDSA_44
+ MLDSA_65
+ MLDSA_87
+
+It returns `-EINVAL` if the specified type (if known), the public key type and
+signature type don't all match. It return `-EBADMSG` if the computed signature
+doesn't match the supplied one.
+
+If, however, the message to be verified is split into multiple fragments, then
+the multi-step API must be used. Firstly, a context must be allocated::
+
+ struct mldsa_ctx *mldsa_ctx_alloc(enum mldsa_type type);
+
+this is type-specific as the size of the allocated state may vary by type.
+Then data can be added to the internal hash::
+
+ int mldsa_verify_update(struct mldsa_ctx *ctx,
+ const void *data, size_t data_len);
+
+And finally the signature verification can be performed::
+
+ int mldsa_verify_final(struct mldsa_ctx *ctx,
+ const void *pk, size_t pk_len,
+ const void *sig, size_t sig_len);
+
+This returns `-EINVAL` if the specified type (if known), the public key type
+and signature type don't all match. It return `-EBADMSG` if the computed
+signature doesn't match the supplied one.
+
+The context can be reset and used again (provided it's for a key of the same
+type)::
+
+ void mldsa_ctx_zeroize(struct mldsa_ctx *ctx);
+
+And finally, it can be freed::
+
+ void mldsa_ctx_free(struct mldsa_ctx *ctx);
+
+
+References
+==========
+
+.. [1] https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.204.pdf
+
+
+API Function Reference
+======================
+
+.. kernel-doc:: include/crypto/mldsa.h
+.. kernel-doc:: lib/crypto/mldsa/mldsa_api.c
diff --git a/include/crypto/mldsa.h b/include/crypto/mldsa.h
new file mode 100644
index 000000000000..e7aac97ac6fd
--- /dev/null
+++ b/include/crypto/mldsa.h
@@ -0,0 +1,34 @@
+/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
+/* Simple API for ML-DSA.
+ *
+ * Copyright (C) 2025 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@...hat.com)
+ *
+ * See also Documentation/crypto/mldsa.rst
+ */
+
+#ifndef _CRYPTO_MLDSA_H
+#define _CRYPTO_MLDSA_H
+
+struct mldsa_ctx;
+
+enum mldsa_type {
+ MLDSA_UNKNOWN, /* Unknown key type */
+ MLDSA_87, /* ML-DSA 87 */
+ MLDSA_65, /* ML-DSA 65 */
+ MLDSA_44, /* ML-DSA 44 */
+};
+
+int mldsa_verify(enum mldsa_type type,
+ const void *pk, size_t pk_len,
+ const uint8_t *data, size_t data_len,
+ const void *sig, size_t sig_len);
+struct mldsa_ctx *mldsa_ctx_alloc(enum mldsa_type type);
+int mldsa_verify_update(struct mldsa_ctx *ctx, const void *data, size_t data_len);
+int mldsa_verify_final(struct mldsa_ctx *ctx,
+ const void *pk, size_t pk_len,
+ const void *sig, size_t sig_len);
+void mldsa_ctx_zeroize(struct mldsa_ctx *ctx);
+void mldsa_ctx_free(struct mldsa_ctx *ctx);
+
+#endif /* _CRYPTO_MLDSA_H */
diff --git a/lib/crypto/mldsa/Makefile b/lib/crypto/mldsa/Makefile
index e24bc2b57b8d..75e260615d4a 100644
--- a/lib/crypto/mldsa/Makefile
+++ b/lib/crypto/mldsa/Makefile
@@ -4,7 +4,8 @@ mldsa-y += \
signature_domain_separation.o \
dilithium_api.o \
dilithium_zetas.o \
- dilithium_signature_helper.o
+ dilithium_signature_helper.o \
+ mldsa_api.o
mldsa-$(CONFIG_CRYPTO_LIB_MLDSA_87) += dilithium_87.o
mldsa-$(CONFIG_CRYPTO_LIB_MLDSA_65) += dilithium_65.o
diff --git a/lib/crypto/mldsa/crypto_mldsa.c b/lib/crypto/mldsa/crypto_mldsa.c
index 26cafeae6f0f..91350a828d94 100644
--- a/lib/crypto/mldsa/crypto_mldsa.c
+++ b/lib/crypto/mldsa/crypto_mldsa.c
@@ -28,9 +28,7 @@ enum dilithium_kernel_key_type {
};
struct dilithium_kernel_ctx {
- union {
- struct dilithium_pk pk;
- };
+ struct dilithium_pk pk;
enum dilithium_kernel_key_type key_type;
};
diff --git a/lib/crypto/mldsa/mldsa_api.c b/lib/crypto/mldsa/mldsa_api.c
new file mode 100644
index 000000000000..6925c5b0d6ee
--- /dev/null
+++ b/lib/crypto/mldsa/mldsa_api.c
@@ -0,0 +1,186 @@
+// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
+/* Simple API for ML-DSA.
+ *
+ * Copyright (C) 2025 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@...hat.com)
+ *
+ * See also Documentation/crypto/mldsa.rst
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <crypto/mldsa.h>
+#include "dilithium.h"
+
+struct mldsa_ctx {
+ struct dilithium_pk pk;
+ struct dilithium_sig sig;
+ struct dilithium_ctx *dilithium;
+ enum dilithium_type type;
+};
+
+/**
+ * mldsa_verify - All-in-one ML-DSA signature verification
+ * @type: Type of ML-DSA key
+ * @pk: Pointer to public key
+ * @pk_len: Length of public key
+ * @data: Pointer to signed data
+ * @data_len: Length of signed data
+ * @sig: Pointer to signature
+ * @sig_len: Length of signature
+ *
+ * Perform all the steps needed to verify an ML-DSA signature in one go. Only
+ * one data buffer may be provided. For multifragment messages, the
+ * alloc/update/final interface must be used instead.
+ *
+ * Return: 0 if signature could be verified correctly, -EBADMSG when signature
+ * cannot be verified and < 0 on other errors.
+ */
+int mldsa_verify(enum mldsa_type type,
+ const void *pk, size_t pk_len,
+ const uint8_t *data, size_t data_len,
+ const void *sig, size_t sig_len)
+{
+ struct mldsa_ctx *ctx;
+ int ret;
+
+ BUILD_BUG_ON((int)MLDSA_UNKNOWN != DILITHIUM_UNKNOWN ||
+ (int)MLDSA_44 != DILITHIUM_44 ||
+ (int)MLDSA_65 != DILITHIUM_65 ||
+ (int)MLDSA_87 != DILITHIUM_87);
+
+ ctx = kmalloc(sizeof(*ctx), GFP_KERNEL);
+ if (!ctx)
+ return -ENOMEM;
+
+ ret = dilithium_pk_load(&ctx->pk, pk, pk_len);
+ if (ret < 0)
+ goto out;
+ ret = dilithium_sig_load(&ctx->sig, sig, sig_len);
+ if (ret < 0)
+ goto out;
+
+ ret = -EINVAL;
+ if (type != MLDSA_UNKNOWN && (int)type != ctx->pk.dilithium_type)
+ goto out;
+
+ ret = dilithium_verify(&ctx->sig, data, data_len, &ctx->pk);
+out:
+ kfree_sensitive(ctx);
+ return ret;
+}
+EXPORT_SYMBOL(mldsa_verify);
+
+/**
+ * mldsa_ctx_alloc - Allocate ML-DSA context
+ * @type: The type of ML-DSA involved.
+ *
+ * Return: Pointer to the allocated context or error code on failure.
+ *
+ * Context: Process context. May sleep to allocate memory.
+ */
+struct mldsa_ctx *mldsa_ctx_alloc(enum mldsa_type type)
+{
+ struct mldsa_ctx *ctx;
+
+ if (type == MLDSA_UNKNOWN)
+ return ERR_PTR(-EINVAL);
+
+ ctx = kmalloc(sizeof(*ctx), GFP_KERNEL);
+ if (!ctx)
+ return ERR_PTR(-ENOMEM);
+
+ ctx->type = (int)type;
+ ctx->dilithium = dilithium_ctx_alloc_ahat(ctx->type);
+ if (!ctx->dilithium) {
+ kfree(ctx);
+ return ERR_PTR(-ENOMEM);
+ }
+
+ return ctx;
+}
+EXPORT_SYMBOL(mldsa_ctx_alloc);
+
+/**
+ * mldsa_verify_update - Add more data to an already initialized context
+ * @ctx: Pointer to an allocated ML-DSA context
+ * @data: Pointer to signed data
+ * @data_len: Length of signed data
+ *
+ * Add more signed data to the state in an allocated context. This can be use
+ * to provide data that is split into multiple fragments.
+ *
+ * Return: 0 (success) or < 0 on error
+ *
+ * Context: Process context. May sleep to allocate memory.
+ */
+int mldsa_verify_update(struct mldsa_ctx *ctx, const void *data, size_t data_len)
+{
+ return dilithium_verify_update(ctx->dilithium, data, data_len);
+}
+EXPORT_SYMBOL(mldsa_verify_update);
+
+/**
+ * mldsa_verify_final - Perform signature verification
+ * @ctx: Pointer to an allocated and updated ML-DSA context
+ * @pk: Pointer to public key
+ * @pk_len: Length of public key
+ * @sig: Pointer to signature
+ * @sig_len: Length of signature
+ *
+ * Finalise the state in the ML-DSA context and verify the signature. The
+ * caller must have allocated it and updated it with all the pieces of data.
+ * Note that this does not free the context, but does reset it.
+ *
+ * Return: 0 if signature could be verified correctly, -EBADMSG when the
+ * signature cannot be verified and < 0 on other errors.
+ *
+ * Context: Process context. May sleep to allocate memory.
+ */
+int mldsa_verify_final(struct mldsa_ctx *ctx,
+ const void *pk, size_t pk_len,
+ const void *sig, size_t sig_len)
+{
+ int ret;
+
+ ret = dilithium_pk_load(&ctx->pk, pk, pk_len);
+ if (ret < 0)
+ return ret;
+ ret = dilithium_sig_load(&ctx->sig, sig, sig_len);
+ if (ret < 0)
+ return ret;
+ if (ctx->type != ctx->pk.dilithium_type)
+ return -EINVAL;
+
+ ret = dilithium_verify_final(&ctx->sig, ctx->dilithium, &ctx->pk);
+ dilithium_ctx_zero(ctx->dilithium);
+ return ret;
+}
+EXPORT_SYMBOL(mldsa_verify_final);
+
+/**
+ * mldsa_ctx_zeroize - Resets an ML-DSA context
+ * @ctx: Context pointer
+ *
+ * Context: Any context.
+ */
+void mldsa_ctx_zeroize(struct mldsa_ctx *ctx)
+{
+ dilithium_ctx_zero(ctx->dilithium);
+ memset(&ctx->pk, 0, sizeof(ctx->pk));
+ memset(&ctx->sig, 0, sizeof(ctx->sig));
+}
+EXPORT_SYMBOL(mldsa_ctx_zeroize);
+
+/**
+ * mldsa_ctx_free - Clears and frees an ML-DSA context.
+ * @ctx: Context pointer
+ *
+ * Context: Any context.
+ */
+void mldsa_ctx_free(struct mldsa_ctx *ctx)
+{
+ dilithium_ctx_zero_free(ctx->dilithium);
+ kfree(ctx);
+}
+EXPORT_SYMBOL(mldsa_ctx_free);
Powered by blists - more mailing lists