[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20251017144311.817771-12-dhowells@redhat.com>
Date: Fri, 17 Oct 2025 15:42:55 +0100
From: David Howells <dhowells@...hat.com>
To: Eric Biggers <ebiggers@...nel.org>
Cc: David Howells <dhowells@...hat.com>,
"Jason A . Donenfeld" <Jason@...c4.com>,
Ard Biesheuvel <ardb@...nel.org>,
Herbert Xu <herbert@...dor.apana.org.au>,
Stephan Mueller <smueller@...onox.de>,
Lukas Wunner <lukas@...ner.de>,
Ignat Korchagin <ignat@...udflare.com>,
Luis Chamberlain <mcgrof@...nel.org>,
Petr Pavlu <petr.pavlu@...e.com>,
Daniel Gomez <da.gomez@...nel.org>,
Sami Tolvanen <samitolvanen@...gle.com>,
linux-crypto@...r.kernel.org,
keyrings@...r.kernel.org,
linux-modules@...r.kernel.org,
linux-kernel@...r.kernel.org
Subject: [PATCH v6 11/17] crypto: Add ML-DSA/Dilithium keypair generation support
Add generation of keypairs. I suspect we don't want to do this in the
kernel.
Signed-off-by: David Howells <dhowells@...hat.com>
cc: Stephan Mueller <smueller@...onox.de>
cc: Eric Biggers <ebiggers@...nel.org>
cc: Jason A. Donenfeld <Jason@...c4.com>
cc: Ard Biesheuvel <ardb@...nel.org>
cc: Herbert Xu <herbert@...dor.apana.org.au>
cc: linux-crypto@...r.kernel.org
---
crypto/ml_dsa/dilithium.h | 54 +++++++
crypto/ml_dsa/dilithium_44.h | 35 ++++
crypto/ml_dsa/dilithium_65.h | 35 ++++
crypto/ml_dsa/dilithium_87.h | 35 ++++
crypto/ml_dsa/dilithium_api.c | 92 +++++++++++
crypto/ml_dsa/dilithium_pack.h | 75 +++++++++
crypto/ml_dsa/dilithium_pct.h | 53 ++++++
crypto/ml_dsa/dilithium_polyvec.h | 20 +++
crypto/ml_dsa/dilithium_polyvec_c.h | 20 +++
crypto/ml_dsa/dilithium_signature_c.c | 24 +++
crypto/ml_dsa/dilithium_signature_c.h | 7 +
crypto/ml_dsa/dilithium_signature_impl.h | 195 +++++++++++++++++++++++
crypto/ml_dsa/dilithium_type.h | 22 +++
13 files changed, 667 insertions(+)
create mode 100644 crypto/ml_dsa/dilithium_pct.h
diff --git a/crypto/ml_dsa/dilithium.h b/crypto/ml_dsa/dilithium.h
index 6d4982164201..d2c9dac4967e 100644
--- a/crypto/ml_dsa/dilithium.h
+++ b/crypto/ml_dsa/dilithium.h
@@ -545,6 +545,60 @@ int dilithium_pk_ptr(uint8_t **dilithium_key, size_t *dilithium_key_len,
int dilithium_sig_ptr(uint8_t **dilithium_sig, size_t *dilithium_sig_len,
struct dilithium_sig *sig);
+/**
+ * @ingroup Dilithium
+ * @brief Generates Dilithium public and private key.
+ *
+ * @param [out] pk pointer to allocated output public key
+ * @param [out] sk pointer to allocated output private key
+ * @param [in] rng_ctx pointer to seeded random number generator context
+ * @param [in] dilithium_type type of the Dilithium key to generate
+ *
+ * @return 0 (success) or < 0 on error
+ */
+int dilithium_keypair(struct dilithium_pk *pk, struct dilithium_sk *sk,
+ struct crypto_rng *rng_ctx,
+ enum dilithium_type dilithium_type);
+
+/**
+ * @ingroup Dilithium
+ * @brief Generates Dilithium public and private key from a given seed.
+ *
+ * The idea of the function is the allowance of FIPS 204 to maintain the seed
+ * used to generate a key pair in lieu of maintaining a private key or the
+ * key pair (which used much more memory). The seed must be treated equally
+ * sensitive as a private key.
+ *
+ * The seed is generated by simply obtaining 32 bytes from a properly seeded
+ * DRNG, i.e. the same way as a symmetric key would be generated.
+ *
+ * @param [out] pk pointer to allocated output public key
+ * @param [out] sk pointer to allocated output private key
+ * @param [in] seed buffer with the seed data which must be exactly 32 bytes
+ * in size
+ * @param [in] seedlen length of the seed buffer
+ * @param [in] dilithium_type type of the Dilithium key to generate
+ *
+ * @return 0 (success) or < 0 on error
+ */
+int dilithium_keypair_from_seed(struct dilithium_pk *pk,
+ struct dilithium_sk *sk,
+ const uint8_t *seed, size_t seedlen,
+ enum dilithium_type dilithium_type);
+
+/**
+ * @brief Pairwise consistency check as per FIPS 140 IG
+ *
+ * This call should be invoked after generating a key pair in FIPS mode
+ *
+ * @param [in] pk Public key
+ * @param [in] sk Secret key
+ *
+ * @return 0 on success, < 0 on error
+ */
+int dilithium_pct(const struct dilithium_pk *pk,
+ const struct dilithium_sk *sk);
+
/**
* @ingroup Dilithium
* @brief Computes signature in one shot
diff --git a/crypto/ml_dsa/dilithium_44.h b/crypto/ml_dsa/dilithium_44.h
index 6490c83e7100..d5a03bbebb1a 100644
--- a/crypto/ml_dsa/dilithium_44.h
+++ b/crypto/ml_dsa/dilithium_44.h
@@ -195,6 +195,41 @@ static inline unsigned int dilithium_44_sig_size(void)
return sizeof_field(struct dilithium_44_sig, sig);
}
+/**
+ * @brief Generates Dilithium public and private key.
+ *
+ * @param [out] pk pointer to allocated output public key
+ * @param [out] sk pointer to allocated output private key
+ * @param [in] rng_ctx pointer to seeded random number generator context
+ *
+ * @return 0 (success) or < 0 on error
+ */
+int dilithium_44_keypair(struct dilithium_44_pk *pk, struct dilithium_44_sk *sk,
+ struct crypto_rng *rng_ctx);
+
+/**
+ * @brief Generates Dilithium public and private key from a given seed.
+ *
+ * The idea of the function is the allowance of FIPS 204 to maintain the seed
+ * used to generate a key pair in lieu of maintaining a private key or the
+ * key pair (which used much more memory). The seed must be treated equally
+ * sensitive as a private key.
+ *
+ * The seed is generated by simply obtaining 32 bytes from a properly seeded
+ * DRNG, i.e. the same way as a symmetric key would be generated.
+ *
+ * @param [out] pk pointer to allocated output public key
+ * @param [out] sk pointer to allocated output private key
+ * @param [in] seed buffer with the seed data which must be exactly 32 bytes
+ * in size
+ * @param [in] seedlen length of the seed buffer
+ *
+ * @return 0 (success) or < 0 on error
+ */
+int dilithium_44_keypair_from_seed(struct dilithium_44_pk *pk,
+ struct dilithium_44_sk *sk,
+ const uint8_t *seed, size_t seedlen);
+
/**
* @brief Computes ML-DSA signature in one shot
*
diff --git a/crypto/ml_dsa/dilithium_65.h b/crypto/ml_dsa/dilithium_65.h
index 0a36f7eed63e..d93fea2a8798 100644
--- a/crypto/ml_dsa/dilithium_65.h
+++ b/crypto/ml_dsa/dilithium_65.h
@@ -195,6 +195,41 @@ static inline unsigned int dilithium_65_sig_size(void)
return sizeof_field(struct dilithium_65_sig, sig);
}
+/**
+ * @brief Generates Dilithium public and private key.
+ *
+ * @param [out] pk pointer to allocated output public key
+ * @param [out] sk pointer to allocated output private key
+ * @param [in] rng_ctx pointer to seeded random number generator context
+ *
+ * @return 0 (success) or < 0 on error
+ */
+int dilithium_65_keypair(struct dilithium_65_pk *pk, struct dilithium_65_sk *sk,
+ struct crypto_rng *rng_ctx);
+
+/**
+ * @brief Generates Dilithium public and private key from a given seed.
+ *
+ * The idea of the function is the allowance of FIPS 204 to maintain the seed
+ * used to generate a key pair in lieu of maintaining a private key or the
+ * key pair (which used much more memory). The seed must be treated equally
+ * sensitive as a private key.
+ *
+ * The seed is generated by simply obtaining 32 bytes from a properly seeded
+ * DRNG, i.e. the same way as a symmetric key would be generated.
+ *
+ * @param [out] pk pointer to allocated output public key
+ * @param [out] sk pointer to allocated output private key
+ * @param [in] seed buffer with the seed data which must be exactly 32 bytes
+ * in size
+ * @param [in] seedlen length of the seed buffer
+ *
+ * @return 0 (success) or < 0 on error
+ */
+int dilithium_65_keypair_from_seed(struct dilithium_65_pk *pk,
+ struct dilithium_65_sk *sk,
+ const uint8_t *seed, size_t seedlen);
+
/**
* @brief Computes ML-DSA signature in one shot
*
diff --git a/crypto/ml_dsa/dilithium_87.h b/crypto/ml_dsa/dilithium_87.h
index eaed8e675383..69d9f03643d3 100644
--- a/crypto/ml_dsa/dilithium_87.h
+++ b/crypto/ml_dsa/dilithium_87.h
@@ -195,6 +195,41 @@ static inline unsigned int dilithium_87_sig_size(void)
return sizeof_field(struct dilithium_87_sig, sig);
}
+/**
+ * @brief Generates Dilithium public and private key.
+ *
+ * @param [out] pk pointer to allocated output public key
+ * @param [out] sk pointer to allocated output private key
+ * @param [in] rng_ctx pointer to seeded random number generator context
+ *
+ * @return 0 (success) or < 0 on error
+ */
+int dilithium_87_keypair(struct dilithium_87_pk *pk, struct dilithium_87_sk *sk,
+ struct crypto_rng *rng_ctx);
+
+/**
+ * @brief Generates Dilithium public and private key from a given seed.
+ *
+ * The idea of the function is the allowance of FIPS 204 to maintain the seed
+ * used to generate a key pair in lieu of maintaining a private key or the
+ * key pair (which used much more memory). The seed must be treated equally
+ * sensitive as a private key.
+ *
+ * The seed is generated by simply obtaining 32 bytes from a properly seeded
+ * DRNG, i.e. the same way as a symmetric key would be generated.
+ *
+ * @param [out] pk pointer to allocated output public key
+ * @param [out] sk pointer to allocated output private key
+ * @param [in] seed buffer with the seed data which must be exactly 32 bytes
+ * in size
+ * @param [in] seedlen length of the seed buffer
+ *
+ * @return 0 (success) or < 0 on error
+ */
+int dilithium_87_keypair_from_seed(struct dilithium_87_pk *pk,
+ struct dilithium_87_sk *sk,
+ const uint8_t *seed, size_t seedlen);
+
/**
* @brief Computes ML-DSA signature in one shot
*
diff --git a/crypto/ml_dsa/dilithium_api.c b/crypto/ml_dsa/dilithium_api.c
index 363984f01169..215ab5fd7195 100644
--- a/crypto/ml_dsa/dilithium_api.c
+++ b/crypto/ml_dsa/dilithium_api.c
@@ -29,6 +29,7 @@
#include <linux/export.h>
#include "dilithium.h"
+#include "dilithium_pct.h"
void dilithium_ctx_zero(struct dilithium_ctx *ctx)
{
@@ -405,6 +406,97 @@ int dilithium_sig_ptr(uint8_t **dilithium_sig,
}
EXPORT_SYMBOL(dilithium_sig_ptr);
+int dilithium_keypair(struct dilithium_pk *pk,
+ struct dilithium_sk *sk, struct crypto_rng *rng_ctx,
+ enum dilithium_type dilithium_type)
+{
+ if (!pk || !sk)
+ return -EINVAL;
+
+ switch (dilithium_type) {
+ case DILITHIUM_87:
+#ifdef CONFIG_CRYPTO_DILITHIUM_87
+ pk->dilithium_type = dilithium_type;
+ sk->dilithium_type = dilithium_type;
+ return dilithium_87_keypair(&pk->key.pk_87, &sk->key.sk_87,
+ rng_ctx);
+#else
+ return -EOPNOTSUPP;
+#endif
+ case DILITHIUM_65:
+#ifdef CONFIG_CRYPTO_DILITHIUM_65
+ pk->dilithium_type = dilithium_type;
+ sk->dilithium_type = dilithium_type;
+ return dilithium_65_keypair(&pk->key.pk_65, &sk->key.sk_65,
+ rng_ctx);
+#else
+ return -EOPNOTSUPP;
+#endif
+ case DILITHIUM_44:
+#ifdef CONFIG_CRYPTO_DILITHIUM_44
+ pk->dilithium_type = dilithium_type;
+ sk->dilithium_type = dilithium_type;
+ return dilithium_44_keypair(&pk->key.pk_44, &sk->key.sk_44,
+ rng_ctx);
+#else
+ return -EOPNOTSUPP;
+#endif
+ case DILITHIUM_UNKNOWN:
+ default:
+ return -EOPNOTSUPP;
+ }
+}
+EXPORT_SYMBOL(dilithium_keypair);
+
+int dilithium_keypair_from_seed(struct dilithium_pk *pk, struct dilithium_sk *sk,
+ const uint8_t *seed, size_t seedlen,
+ enum dilithium_type dilithium_type)
+{
+ if (!pk || !sk)
+ return -EINVAL;
+
+ switch (dilithium_type) {
+ case DILITHIUM_87:
+#ifdef CONFIG_CRYPTO_DILITHIUM_87
+ pk->dilithium_type = dilithium_type;
+ sk->dilithium_type = dilithium_type;
+ return dilithium_87_keypair_from_seed(
+ &pk->key.pk_87, &sk->key.sk_87, seed, seedlen);
+#else
+ return -EOPNOTSUPP;
+#endif
+ case DILITHIUM_65:
+#ifdef CONFIG_CRYPTO_DILITHIUM_65
+ pk->dilithium_type = dilithium_type;
+ sk->dilithium_type = dilithium_type;
+ return dilithium_65_keypair_from_seed(
+ &pk->key.pk_65, &sk->key.sk_65, seed, seedlen);
+#else
+ return -EOPNOTSUPP;
+#endif
+ case DILITHIUM_44:
+#ifdef CONFIG_CRYPTO_DILITHIUM_44
+ pk->dilithium_type = dilithium_type;
+ sk->dilithium_type = dilithium_type;
+ return dilithium_44_keypair_from_seed(
+ &pk->key.pk_44, &sk->key.sk_44, seed, seedlen);
+#else
+ return -EOPNOTSUPP;
+#endif
+ case DILITHIUM_UNKNOWN:
+ default:
+ return -EOPNOTSUPP;
+ }
+}
+EXPORT_SYMBOL(dilithium_keypair_from_seed);
+
+int dilithium_pct(const struct dilithium_pk *pk,
+ const struct dilithium_sk *sk)
+{
+ return _dilithium_pct_fips(pk, sk);
+}
+EXPORT_SYMBOL(dilithium_pct);
+
int dilithium_sign(struct dilithium_sig *sig,
const uint8_t *m, size_t mlen,
const struct dilithium_sk *sk,
diff --git a/crypto/ml_dsa/dilithium_pack.h b/crypto/ml_dsa/dilithium_pack.h
index e17c6256a16d..152aafd1df30 100644
--- a/crypto/ml_dsa/dilithium_pack.h
+++ b/crypto/ml_dsa/dilithium_pack.h
@@ -30,6 +30,21 @@
/*******************************************************************************
* Pack / Unpack public key
******************************************************************************/
+static inline void pack_pk_rho(struct dilithium_pk *pk,
+ const uint8_t rho[DILITHIUM_SEEDBYTES])
+{
+ memcpy(pk->pk, rho, DILITHIUM_SEEDBYTES);
+}
+
+static inline void pack_pk_t1(struct dilithium_pk *pk, const polyveck *t1)
+{
+ unsigned int i;
+ uint8_t *pubkey = pk->pk + DILITHIUM_SEEDBYTES;
+
+ for (i = 0; i < DILITHIUM_K; ++i)
+ polyt1_pack(pubkey + i * DILITHIUM_POLYT1_PACKEDBYTES,
+ &t1->vec[i]);
+}
static inline void unpack_pk_rho(uint8_t rho[DILITHIUM_SEEDBYTES],
const struct dilithium_pk *pk)
@@ -50,6 +65,66 @@ static inline void unpack_pk_t1(polyveck *t1, const struct dilithium_pk *pk)
/*******************************************************************************
* Pack / Unpack secret key
******************************************************************************/
+static inline void pack_sk_rho(struct dilithium_sk *sk,
+ const uint8_t rho[DILITHIUM_SEEDBYTES])
+{
+ memcpy(sk->sk, rho, DILITHIUM_SEEDBYTES);
+}
+
+static inline void pack_sk_key(struct dilithium_sk *sk,
+ const uint8_t key[DILITHIUM_SEEDBYTES])
+{
+ memcpy(sk->sk + DILITHIUM_SEEDBYTES, key, DILITHIUM_SEEDBYTES);
+}
+
+static inline void pack_sk_tr(struct dilithium_sk *sk,
+ const uint8_t tr[DILITHIUM_TRBYTES])
+{
+ memcpy(sk->sk + 2 * DILITHIUM_SEEDBYTES, tr, DILITHIUM_TRBYTES);
+}
+
+static inline void pack_sk_s1(struct dilithium_sk *sk, const polyvecl *s1)
+{
+ unsigned int i;
+ uint8_t *seckey =
+ sk->sk + 2 * DILITHIUM_SEEDBYTES + DILITHIUM_TRBYTES;
+
+ for (i = 0; i < DILITHIUM_L; ++i)
+ polyeta_pack(seckey + i * DILITHIUM_POLYETA_PACKEDBYTES,
+ &s1->vec[i]);
+}
+
+static inline void pack_sk_s2(struct dilithium_sk *sk, const polyveck *s2)
+{
+ unsigned int i;
+ uint8_t *seckey = sk->sk + 2 * DILITHIUM_SEEDBYTES +
+ DILITHIUM_TRBYTES +
+ DILITHIUM_L * DILITHIUM_POLYETA_PACKEDBYTES;
+
+ for (i = 0; i < DILITHIUM_K; ++i)
+ polyeta_pack(seckey + i * DILITHIUM_POLYETA_PACKEDBYTES,
+ &s2->vec[i]);
+}
+
+static inline void pack_sk_t0(struct dilithium_sk *sk, const polyveck *t0)
+{
+ unsigned int i;
+ uint8_t *seckey = sk->sk + 2 * DILITHIUM_SEEDBYTES +
+ DILITHIUM_TRBYTES +
+ DILITHIUM_L * DILITHIUM_POLYETA_PACKEDBYTES +
+ DILITHIUM_K * DILITHIUM_POLYETA_PACKEDBYTES;
+
+ for (i = 0; i < DILITHIUM_K; ++i)
+ polyt0_pack(seckey + i * DILITHIUM_POLYT0_PACKEDBYTES,
+ &t0->vec[i]);
+}
+
+static inline void unpack_sk_rho(uint8_t rho[DILITHIUM_SEEDBYTES],
+ const struct dilithium_sk *sk)
+{
+ memcpy(rho, sk->sk, DILITHIUM_SEEDBYTES);
+}
+
static inline void unpack_sk_key(uint8_t key[DILITHIUM_SEEDBYTES],
const struct dilithium_sk *sk)
{
diff --git a/crypto/ml_dsa/dilithium_pct.h b/crypto/ml_dsa/dilithium_pct.h
new file mode 100644
index 000000000000..d153e5a95dd1
--- /dev/null
+++ b/crypto/ml_dsa/dilithium_pct.h
@@ -0,0 +1,53 @@
+/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
+/*
+ * Copyright (C) 2024 - 2025, Stephan Mueller <smueller@...onox.de>
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF
+ * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+ * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ */
+
+#ifndef DILITHIUM_PCT_H
+#define DILITHIUM_PCT_H
+
+#include "fips_mode.h"
+#include "small_stack_support.h"
+
+static inline int _dilithium_pct_fips(const struct dilithium_pk *pk,
+ const struct dilithium_sk *sk)
+{
+ struct workspace {
+ uint8_t m[32];
+ struct dilithium_sig sig;
+ };
+ int ret;
+ LC_DECLARE_MEM(ws, struct workspace, sizeof(uint64_t));
+
+ ret = dilithium_sign(&ws->sig, ws->m, sizeof(ws->m), sk,
+ lc_seeded_rng);
+ if (ret < 0)
+ goto out;
+ ret = dilithium_verify(&ws->sig, ws->m, sizeof(ws->m), pk);
+out:
+ LC_RELEASE_MEM(ws);
+ return ret;
+}
+
+static inline int dilithium_pct_fips(const struct dilithium_pk *pk,
+ const struct dilithium_sk *sk)
+{
+ FIPS140_PCT_LOOP(_dilithium_pct_fips(pk, sk))
+
+ return 0;
+}
+
+#endif /* DILITHIUM_PCT_H */
diff --git a/crypto/ml_dsa/dilithium_polyvec.h b/crypto/ml_dsa/dilithium_polyvec.h
index 7e428e3becfd..609df0769f5c 100644
--- a/crypto/ml_dsa/dilithium_polyvec.h
+++ b/crypto/ml_dsa/dilithium_polyvec.h
@@ -269,6 +269,26 @@ static inline int polyveck_chknorm(const polyveck *v, int32_t bound)
return 0;
}
+/**
+ * @brief polyveck_power2round - For all coefficients a of polynomials in vector
+ * of length K, compute a0, a1 such that
+ * a mod^+ Q = a1*2^D + a0 with
+ * -2^{D-1} < a0 <= 2^{D-1}. Assumes coefficients
+ * to be standard representatives.
+ *
+ * @param [out] v1 pointer to output vector of polynomials with coefficients a1
+ * @param [in] v0 pointer to output vector of polynomials with coefficients a0
+ * @param [in] v pointer to input vector
+ */
+static inline void polyveck_power2round(polyveck *v1, polyveck *v0,
+ const polyveck *v)
+{
+ unsigned int i;
+
+ for (i = 0; i < DILITHIUM_K; ++i)
+ poly_power2round(&v1->vec[i], &v0->vec[i], &v->vec[i]);
+}
+
/**
* @brief polyveck_decompose - For all coefficients a of polynomials in vector
* of length K, compute high and low bits a0, a1
diff --git a/crypto/ml_dsa/dilithium_polyvec_c.h b/crypto/ml_dsa/dilithium_polyvec_c.h
index 0f8c2d914e4d..1628e3217cbc 100644
--- a/crypto/ml_dsa/dilithium_polyvec_c.h
+++ b/crypto/ml_dsa/dilithium_polyvec_c.h
@@ -19,6 +19,16 @@
#ifndef DILITHIUM_POLYVEC_C_H
#define DILITHIUM_POLYVEC_C_H
+static inline void
+polyvecl_uniform_eta(polyvecl *v, const uint8_t seed[DILITHIUM_CRHBYTES],
+ uint16_t nonce, void *ws_buf)
+{
+ unsigned int i;
+
+ for (i = 0; i < DILITHIUM_L; ++i)
+ poly_uniform_eta(&v->vec[i], seed, cpu_to_le16(nonce++), ws_buf);
+}
+
static inline void
polyvecl_uniform_gamma1(polyvecl *v, const uint8_t seed[DILITHIUM_CRHBYTES],
uint16_t nonce, void *ws_buf)
@@ -32,6 +42,16 @@ polyvecl_uniform_gamma1(polyvecl *v, const uint8_t seed[DILITHIUM_CRHBYTES],
ws_buf);
}
+static inline void
+polyveck_uniform_eta(polyveck *v, const uint8_t seed[DILITHIUM_CRHBYTES],
+ uint16_t nonce, void *ws_buf)
+{
+ unsigned int i;
+
+ for (i = 0; i < DILITHIUM_K; ++i)
+ poly_uniform_eta(&v->vec[i], seed, cpu_to_le16(nonce++), ws_buf);
+}
+
/**
* @brief expand_mat - Implementation of ExpandA. Generates matrix A with
* uniformly random coefficients a_{i,j} by performing
diff --git a/crypto/ml_dsa/dilithium_signature_c.c b/crypto/ml_dsa/dilithium_signature_c.c
index a4a9d0bfdd37..ebaab0db7fda 100644
--- a/crypto/ml_dsa/dilithium_signature_c.c
+++ b/crypto/ml_dsa/dilithium_signature_c.c
@@ -37,6 +37,18 @@
#include "dilithium_pack.h"
#include "dilithium_signature_impl.h"
+int dilithium_keypair_from_seed_c(struct dilithium_pk *pk, struct dilithium_sk *sk,
+ const uint8_t *seed, size_t seedlen)
+{
+ return dilithium_keypair_from_seed_impl(pk, sk, seed, seedlen);
+}
+
+int dilithium_keypair_c(struct dilithium_pk *pk,
+ struct dilithium_sk *sk, struct crypto_rng *rng_ctx)
+{
+ return dilithium_keypair_impl(pk, sk, rng_ctx);
+}
+
int dilithium_sign_c(struct dilithium_sig *sig,
const uint8_t *m, size_t mlen,
const struct dilithium_sk *sk,
@@ -105,6 +117,18 @@ int dilithium_verify_final_c(const struct dilithium_sig *sig,
return dilithium_verify_final_impl(sig, ctx, pk);
}
+int dilithium_keypair_from_seed(struct dilithium_pk *pk, struct dilithium_sk *sk,
+ const uint8_t *seed, size_t seedlen)
+{
+ return dilithium_keypair_from_seed_c(pk, sk, seed, seedlen);
+}
+
+int dilithium_keypair(struct dilithium_pk *pk,
+ struct dilithium_sk *sk, struct crypto_rng *rng_ctx)
+{
+ return dilithium_keypair_c(pk, sk, rng_ctx);
+}
+
int dilithium_sign(struct dilithium_sig *sig,
const uint8_t *m, size_t mlen,
const struct dilithium_sk *sk,
diff --git a/crypto/ml_dsa/dilithium_signature_c.h b/crypto/ml_dsa/dilithium_signature_c.h
index a7d20cd49672..eab4d5e8c686 100644
--- a/crypto/ml_dsa/dilithium_signature_c.h
+++ b/crypto/ml_dsa/dilithium_signature_c.h
@@ -21,6 +21,13 @@
#include "dilithium_type.h"
+int dilithium_keypair_c(struct dilithium_pk *pk,
+ struct dilithium_sk *sk,
+ struct crypto_rng *rng_ctx);
+int dilithium_keypair_from_seed_c(struct dilithium_pk *pk,
+ struct dilithium_sk *sk,
+ const uint8_t *seed, size_t seedlen);
+
int dilithium_sign_c(struct dilithium_sig *sig, const uint8_t *m,
size_t mlen, const struct dilithium_sk *sk,
struct crypto_rng *rng_ctx);
diff --git a/crypto/ml_dsa/dilithium_signature_impl.h b/crypto/ml_dsa/dilithium_signature_impl.h
index 1f0ec0f7c27c..1682f64b6877 100644
--- a/crypto/ml_dsa/dilithium_signature_impl.h
+++ b/crypto/ml_dsa/dilithium_signature_impl.h
@@ -31,6 +31,7 @@
#include "dilithium_type.h"
#include "dilithium_debug.h"
#include "dilithium_pack.h"
+#include "dilithium_pct.h"
#include "dilithium_signature_impl.h"
#include "signature_domain_separation.h"
#include "small_stack_support.h"
@@ -52,6 +53,200 @@
#define WS_POLY_UNIFORM_BUF_SIZE \
(_WS_POLY_UNIFORM_BUF_SIZE * LC_POLY_UNIFOR_BUF_SIZE_MULTIPLIER)
+static int dilithium_keypair_from_seed_impl(struct dilithium_pk *pk,
+ struct dilithium_sk *sk,
+ const uint8_t *seed,
+ size_t seedlen);
+
+static int dilithium_keypair_impl(struct dilithium_pk *pk,
+ struct dilithium_sk *sk,
+ struct crypto_rng *rng_ctx)
+{
+ struct workspace {
+ union {
+ polyvecl s1, s1hat;
+ } s1;
+ union {
+ polyvecl mat[DILITHIUM_K];
+ polyveck t0;
+ } matrix;
+ polyveck s2, t1;
+ uint8_t seedbuf[2 * DILITHIUM_SEEDBYTES +
+ DILITHIUM_CRHBYTES];
+ union {
+ poly polyvecl_pointwise_acc_montgomery_buf;
+ uint8_t poly_uniform_buf[WS_POLY_UNIFORM_BUF_SIZE];
+ uint8_t poly_uniform_eta_buf[POLY_UNIFORM_ETA_BYTES];
+ uint8_t tr[DILITHIUM_TRBYTES];
+ } tmp;
+ };
+ static const uint8_t dimension[2] = { DILITHIUM_K, DILITHIUM_L };
+ const uint8_t *rho, *rhoprime, *key;
+ int ret;
+ struct shake256_ctx shake256_ctx;
+ LC_DECLARE_MEM(ws, struct workspace, sizeof(uint64_t));
+
+ if (WARN_ON_ONCE(!pk) ||
+ WARN_ON_ONCE(!sk)) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ /* Get randomness for rho, rhoprime and key */
+ ret = crypto_rng_generate(rng_ctx, NULL, 0, ws->seedbuf,
+ DILITHIUM_SEEDBYTES);
+ if (ret < 0)
+ goto out;
+ dilithium_print_buffer(ws->seedbuf, DILITHIUM_SEEDBYTES,
+ "Keygen - Seed");
+
+ shake256_init(&shake256_ctx);
+ shake256_update(&shake256_ctx, ws->seedbuf, DILITHIUM_SEEDBYTES);
+ shake256_update(&shake256_ctx, dimension, sizeof(dimension));
+ shake256_squeeze(&shake256_ctx, ws->seedbuf, sizeof(ws->seedbuf));
+ shake256_clear(&shake256_ctx);
+
+ rho = ws->seedbuf;
+ dilithium_print_buffer(ws->seedbuf, DILITHIUM_SEEDBYTES,
+ "Keygen - RHO");
+ pack_pk_rho(pk, rho);
+ pack_sk_rho(sk, rho);
+
+ /*
+ * Timecop: RHO' is a random number which is enlarged to sample the
+ * vectors S1 and S2 from. The sampling operation is not considered
+ * relevant for the side channel operation as (a) an attacker does not
+ * have access to the random number and (b) only the result after the
+ * sampling operation of S1 and S2 is released.
+ */
+ rhoprime = rho + DILITHIUM_SEEDBYTES;
+ dilithium_print_buffer(rhoprime, DILITHIUM_CRHBYTES,
+ "Keygen - RHOPrime");
+
+ key = rhoprime + DILITHIUM_CRHBYTES;
+ dilithium_print_buffer(key, DILITHIUM_SEEDBYTES, "Keygen - Key");
+
+ /* Timecop: key goes into the secret key */
+ poison(key, DILITHIUM_SEEDBYTES);
+
+ pack_sk_key(sk, key);
+
+ /* Sample short vectors s1 and s2 */
+
+ polyvecl_uniform_eta(&ws->s1.s1, rhoprime, 0,
+ ws->tmp.poly_uniform_eta_buf);
+ polyveck_uniform_eta(&ws->s2, rhoprime, DILITHIUM_L,
+ ws->tmp.poly_uniform_eta_buf);
+
+ /* Timecop: s1 and s2 are secret */
+ poison(&ws->s1.s1, sizeof(polyvecl));
+ poison(&ws->s2, sizeof(polyveck));
+
+ dilithium_print_polyvecl(&ws->s1.s1,
+ "Keygen - S1 L x N matrix after ExpandS:");
+ dilithium_print_polyveck(&ws->s2,
+ "Keygen - S2 K x N matrix after ExpandS:");
+
+ pack_sk_s1(sk, &ws->s1.s1);
+ pack_sk_s2(sk, &ws->s2);
+
+ polyvecl_ntt(&ws->s1.s1hat);
+ dilithium_print_polyvecl(&ws->s1.s1hat,
+ "Keygen - S1 L x N matrix after NTT:");
+
+ /* Expand matrix */
+ polyvec_matrix_expand(ws->matrix.mat, rho, ws->tmp.poly_uniform_buf);
+ dilithium_print_polyvecl_k(
+ ws->matrix.mat, "Keygen - MAT K x L x N matrix after ExpandA:");
+
+ polyvec_matrix_pointwise_montgomery(
+ &ws->t1, ws->matrix.mat, &ws->s1.s1hat,
+ &ws->tmp.polyvecl_pointwise_acc_montgomery_buf);
+ dilithium_print_polyveck(&ws->t1,
+ "Keygen - T K x N matrix after A*NTT(s1):");
+
+ polyveck_reduce(&ws->t1);
+ dilithium_print_polyveck(
+ &ws->t1, "Keygen - T K x N matrix reduce after A*NTT(s1):");
+
+ polyveck_invntt_tomont(&ws->t1);
+ dilithium_print_polyveck(&ws->t1,
+ "Keygen - T K x N matrix after NTT-1:");
+
+ /* Add error vector s2 */
+ polyveck_add(&ws->t1, &ws->t1, &ws->s2);
+ dilithium_print_polyveck(&ws->t1,
+ "Keygen - T K x N matrix after add S2:");
+
+ /* Extract t1 and write public key */
+ polyveck_caddq(&ws->t1);
+ dilithium_print_polyveck(&ws->t1, "Keygen - T K x N matrix caddq:");
+
+ polyveck_power2round(&ws->t1, &ws->matrix.t0, &ws->t1);
+ dilithium_print_polyveck(&ws->matrix.t0,
+ "Keygen - T0 K x N matrix after power2round:");
+ dilithium_print_polyveck(&ws->t1,
+ "Keygen - T1 K x N matrix after power2round:");
+
+ pack_sk_t0(sk, &ws->matrix.t0);
+ pack_pk_t1(pk, &ws->t1);
+ dilithium_print_buffer(pk->pk, DILITHIUM_PUBLICKEYBYTES,
+ "Keygen - PK after pkEncode:");
+
+ /* Compute H(rho, t1) and write secret key */
+ shake256(pk->pk, sizeof(pk->pk), ws->tmp.tr, sizeof(ws->tmp.tr));
+ dilithium_print_buffer(ws->tmp.tr, sizeof(ws->tmp.tr), "Keygen - TR:");
+ pack_sk_tr(sk, ws->tmp.tr);
+
+ dilithium_print_buffer(sk->sk, DILITHIUM_SECRETKEYBYTES,
+ "Keygen - SK:");
+
+ /* Timecop: pk and sk are not relevant for side-channels any more. */
+ unpoison(pk->pk, sizeof(pk->pk));
+ unpoison(sk->sk, sizeof(sk->sk));
+
+ ret = dilithium_pct_fips(pk, sk);
+
+out:
+ LC_RELEASE_MEM(ws);
+ return ret;
+}
+
+static int dilithium_keypair_from_seed_impl(struct dilithium_pk *pk,
+ struct dilithium_sk *sk,
+ const uint8_t *seed,
+ size_t seedlen)
+{
+ struct crypto_rng *rng;
+ int ret;
+
+ if (seedlen != DILITHIUM_SEEDBYTES)
+ return -EINVAL;
+
+ rng = crypto_alloc_rng("stdrng", 0, 0);
+ if (IS_ERR(rng))
+ return PTR_ERR(rng);
+
+ ret = crypto_rng_seedsize(rng);
+ if (ret < 0)
+ goto out;
+ if (seedlen != ret) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ /* Set the seed that the key generation can pull via the RNG. */
+ ret = crypto_rng_reset(rng, seed, seedlen);
+ if (ret < 0)
+ goto out;
+
+ /* Generate the key pair from the seed. */
+ ret = dilithium_keypair_impl(pk, sk, rng);
+
+out:
+ return ret;
+}
+
static int dilithium_sign_internal_ahat(struct dilithium_sig *sig,
const struct dilithium_sk *sk,
struct dilithium_ctx *ctx,
diff --git a/crypto/ml_dsa/dilithium_type.h b/crypto/ml_dsa/dilithium_type.h
index f9f7ffa2cd38..cc2664b62048 100644
--- a/crypto/ml_dsa/dilithium_type.h
+++ b/crypto/ml_dsa/dilithium_type.h
@@ -63,6 +63,8 @@
* The following defines simply allow duplicate compilation of the
* respective functions.
*/
+#define dilithium_keypair DILITHIUM_F(keypair)
+#define dilithium_keypair_from_seed DILITHIUM_F(keypair_from_seed)
#define dilithium_sign DILITHIUM_F(sign)
#define dilithium_sign_ctx DILITHIUM_F(sign_ctx)
#define dilithium_sign_init DILITHIUM_F(sign_init)
@@ -74,6 +76,8 @@
#define dilithium_verify_update DILITHIUM_F(verify_update)
#define dilithium_verify_final DILITHIUM_F(verify_final)
+#define dilithium_keypair_c DILITHIUM_F(keypair_c)
+#define dilithium_keypair_from_seed_c DILITHIUM_F(keypair_from_seed_c)
#define dilithium_sign_c DILITHIUM_F(sign_c)
#define dilithium_sign_ctx_c DILITHIUM_F(sign_ctx_c)
#define dilithium_sign_init_c DILITHIUM_F(sign_init_c)
@@ -85,6 +89,10 @@
#define dilithium_verify_update_c DILITHIUM_F(verify_update_c)
#define dilithium_verify_final_c DILITHIUM_F(verify_final_c)
+#define dilithium_keypair_tester DILITHIUM_F(keypair_tester)
+#define dilithium_siggen_tester DILITHIUM_F(siggen_tester)
+#define dilithium_sigver_tester DILITHIUM_F(sigver_tester)
+
#define ntt DILITHIUM_F(ntt)
#define invntt_tomont DILITHIUM_F(invntt_tomont)
#define poly_chknorm DILITHIUM_F(poly_chknorm)
@@ -152,6 +160,8 @@
#define decompose_avx DILITHIUM_F(decompose_avx)
#define make_hint_avx DILITHIUM_F(make_hint_avx)
#define use_hint_avx DILITHIUM_F(use_hint_avx)
+#define dilithium_keypair_avx2 DILITHIUM_F(keypair_avx2)
+#define dilithium_keypair_from_seed_avx2 DILITHIUM_F(keypair_from_seed_avx2)
#define dilithium_sign_avx2 DILITHIUM_F(sign_avx2)
#define dilithium_sign_ctx_avx2 DILITHIUM_F(sign_ctx_avx2)
#define dilithium_sign_init_avx2 DILITHIUM_F(sign_init_avx2)
@@ -179,6 +189,9 @@
DILITHIUM_F(poly_pointwise_montgomery_armv8)
#define polyvecl_pointwise_acc_montgomery_armv8 \
DILITHIUM_F(polyvecl_pointwise_acc_montgomery_armv8)
+#define dilithium_keypair_armv8 DILITHIUM_F(keypair_armv8)
+#define dilithium_keypair_from_seed_armv8 \
+ DILITHIUM_F(keypair_from_seed_armv8)
#define dilithium_sign_armv8 DILITHIUM_F(sign_armv8)
#define dilithium_sign_ctx_armv8 DILITHIUM_F(sign_ctx_armv8)
#define dilithium_sign_init_armv8 DILITHIUM_F(sign_init_armv8)
@@ -200,6 +213,9 @@
#define poly_uniform_armv7 DILITHIUM_F(poly_uniform_armv7)
#define armv7_poly_reduce_asm DILITHIUM_F(armv7_poly_reduce_asm)
#define armv7_rej_uniform_asm DILITHIUM_F(armv7_rej_uniform_asm)
+#define dilithium_keypair_armv7 DILITHIUM_F(keypair_armv7)
+#define dilithium_keypair_from_seed_armv7 \
+ DILITHIUM_F(keypair_from_seed_armv7)
#define dilithium_sign_armv7 DILITHIUM_F(sign_armv7)
#define dilithium_sign_ctx_armv7 DILITHIUM_F(sign_ctx_armv7)
#define dilithium_sign_init_armv7 DILITHIUM_F(sign_init_armv7)
@@ -212,6 +228,9 @@
#define dilithium_verify_final_armv7 DILITHIUM_F(verify_final_armv7)
/* RISCV 64 ASM Implementation */
+#define dilithium_keypair_riscv64 DILITHIUM_F(keypair_riscv64)
+#define dilithium_keypair_from_seed_riscv64 \
+ DILITHIUM_F(keypair_from_seed_riscv64)
#define dilithium_sign_riscv64 DILITHIUM_F(sign_riscv64)
#define dilithium_sign_ctx_riscv64 DILITHIUM_F(sign_ctx_riscv64)
#define dilithium_sign_init_riscv64 DILITHIUM_F(sign_init_riscv64)
@@ -234,6 +253,9 @@
#define dilithium_poly_reduce_rv64im DILITHIUM_F(poly_reduce_rv64im)
/* RISCV 64 RVV Implementation */
+#define dilithium_keypair_riscv64_rvv DILITHIUM_F(keypair_riscv64_rvv)
+#define dilithium_keypair_from_seed_riscv64_rvv \
+ DILITHIUM_F(keypair_from_seed_riscv64_rvv)
#define dilithium_sign_riscv64_rvv DILITHIUM_F(sign_riscv64_rvv)
#define dilithium_sign_ctx_riscv64_rvv DILITHIUM_F(sign_ctx_riscv64_rvv)
#define dilithium_sign_init_riscv64_rvv DILITHIUM_F(sign_init_riscv64_rvv)
Powered by blists - more mailing lists