Skip to content

Commit 7f83418

Browse files
committed
ML-DSA: add external Mu support
Signed-off-by: Stephan Mueller <smueller@chronox.de>
1 parent 949334c commit 7f83418

21 files changed

+175883
-107
lines changed

CHANGES.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
Changes 1.2.1-prerelease
1+
Changes 1.3.0-prerelease
22
* Allow CPU entropy sources to be used as seed sources with meson option "seedsource=cpu"
33

44
* Ensure full clean run on vintage system without AVX2 (thanks to "David C. Rankin" <drankinatty@gmail.com>)
@@ -13,6 +13,8 @@ Changes 1.2.1-prerelease
1313

1414
* *Full FIPS 140 compliance*: Invoke PCT, add integrity test for ELF compilations, enable FIPS compilation by default
1515

16+
* ML-DSA: add external-mu support; new API: lc_dilithium_ctx_external_mu
17+
1618
Changes 1.2.0
1719
* Locking für seeded_rng added to avoid requiring the caller providing a lock
1820

leancrypto.spec

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
#
66

77
Name: leancrypto
8-
Version: 1.2.1
8+
Version: 1.3.0
99
Release: 1.1
1010
Summary: Cryptographic library with stack-only support and PQC-safe algorithms
1111
License: GPL-2.0 OR BSD-2-Clause

linux_kernel/Kbuild.version

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
# Version Number of Leancrypto
22
#
3-
ccflags-y += -DMAJVERSION=1 -DMINVERSION=2 -DPATCHLEVEL=1
3+
ccflags-y += -DMAJVERSION=1 -DMINVERSION=3 -DPATCHLEVEL=0

meson.build

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
# Patchlevel Version: API / ABI compatible, no functional changes, no
1212
# enhancements, bug fixes only.
1313
project('leancrypto', 'c',
14-
version: '1.2.1',
14+
version: '1.3.0',
1515
default_options: [
1616
'warning_level=3',
1717
'optimization=3',

ml-dsa/api/lc_dilithium.h

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -274,6 +274,25 @@ void lc_dilithium_ctx_hash(struct lc_dilithium_ctx *ctx,
274274
void lc_dilithium_ctx_userctx(struct lc_dilithium_ctx *ctx,
275275
const uint8_t *userctx, size_t userctxlen);
276276

277+
/**
278+
* @ingroup Dilithium
279+
* @brief Specify the optional external mu value.
280+
*
281+
* \note If the external mu is specified, the signature generation /
282+
* verification APIs do not require a message. In this case, the message buffer
283+
* can be set to NULL.
284+
*
285+
* \note If both a message and an external mu are provided, the external mu
286+
* takes precedence.
287+
*
288+
* @param [in] ctx Dilithium context
289+
* @param [in] external_mu User context string
290+
* @param [in] external_mu_len Size of the user context string
291+
*/
292+
void lc_dilithium_ctx_external_mu(struct lc_dilithium_ctx *ctx,
293+
const uint8_t *external_mu,
294+
size_t external_mu_len);
295+
277296
/**
278297
* @ingroup Dilithium
279298
* @brief Invalidate the expanded key that potentially is stored in the context.

ml-dsa/api/lc_dilithium_size.h.in

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,16 @@ struct lc_dilithium_ctx {
221221
void *ahat;
222222
unsigned short ahat_size;
223223

224+
/**
225+
* @brief Pointer to the external mu.
226+
*
227+
* If set, the signature operation will use the provided mu instead of
228+
* the message. In this case, the message pointer to the signature
229+
* generation or verification can be NULL.
230+
*/
231+
const uint8_t *external_mu;
232+
size_t external_mu_len;
233+
224234
/**
225235
* @brief Is the Composite-ML-DSA operation wanted? If yes, set the
226236
* NIST category here
@@ -284,7 +294,9 @@ struct lc_dilithium_ctx {
284294
(name)->userctx = NULL; \
285295
(name)->composite_ml_dsa = 0; \
286296
(name)->ahat = NULL; \
287-
(name)->ahat_size = 0
297+
(name)->ahat_size = 0; \
298+
(name)->external_mu = NULL; \
299+
(name)->external_mu_len = 0;
288300
#endif
289301
/// \endcond
290302

ml-dsa/src/avx2/dilithium_signature_avx2.c

Lines changed: 67 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -326,9 +326,26 @@ static int lc_dilithium_sign_avx2_internal(struct lc_dilithium_sig *sig,
326326
mu = rnd + LC_DILITHIUM_RNDBYTES;
327327
rhoprime = mu + LC_DILITHIUM_CRHBYTES;
328328

329-
/* Compute CRH(tr, msg) */
330-
lc_hash_set_digestsize(hash_ctx, LC_DILITHIUM_CRHBYTES);
331-
lc_hash_final(hash_ctx, mu);
329+
/*
330+
* If the external mu is provided, use this verbatim, otherwise
331+
* calculate the mu value.
332+
*/
333+
if (ctx->external_mu) {
334+
if (ctx->external_mu_len != LC_DILITHIUM_CRHBYTES)
335+
return -EINVAL;
336+
memcpy(mu, ctx->external_mu, LC_DILITHIUM_CRHBYTES);
337+
} else {
338+
/*
339+
* Set the digestsize - for SHA512 this is a noop, for SHAKE256,
340+
* it sets the value. The BUILD_BUG_ON is to check that the
341+
* SHA-512 output size is identical to the expected length.
342+
*/
343+
BUILD_BUG_ON(LC_DILITHIUM_CRHBYTES != LC_SHA3_512_SIZE_DIGEST);
344+
345+
/* Compute CRH(tr, msg) */
346+
lc_hash_set_digestsize(hash_ctx, LC_DILITHIUM_CRHBYTES);
347+
lc_hash_final(hash_ctx, mu);
348+
}
332349

333350
if (rng_ctx) {
334351
CKINT(lc_rng_generate(rng_ctx, NULL, 0, rnd,
@@ -515,25 +532,31 @@ LC_INTERFACE_FUNCTION(int, lc_dilithium_sign_ctx_avx2,
515532
uint8_t tr[LC_DILITHIUM_TRBYTES];
516533
int ret = 0;
517534
static int tested = 0;
518-
struct lc_hash_ctx *hash_ctx;
519535

520536
/* rng_ctx is allowed to be NULL as handled below */
521-
if (!sig || !m || !sk || !ctx)
537+
if (!sig || !sk || !ctx)
538+
return -EINVAL;
539+
/* Either the message or the external mu must be provided */
540+
if (!m && !ctx->external_mu)
522541
return -EINVAL;
523542

524543
dilithium_siggen_tester(&tested, "Dilithium Siggen AVX2",
525544
lc_dilithium_sign_ctx_avx2);
526545

527546
unpack_sk_tr_avx2(tr, sk);
528547

529-
/* Compute mu = CRH(tr, msg) */
530-
hash_ctx = &ctx->dilithium_hash_ctx;
531-
lc_hash_init(hash_ctx);
532-
lc_hash_update(hash_ctx, tr, LC_DILITHIUM_TRBYTES);
533-
CKINT(signature_domain_separation(
534-
&ctx->dilithium_hash_ctx, ctx->ml_dsa_internal,
535-
ctx->dilithium_prehash_type, ctx->userctx, ctx->userctxlen, m,
536-
mlen, LC_DILITHIUM_NIST_CATEGORY, !!ctx->composite_ml_dsa));
548+
if (m) {
549+
/* Compute mu = CRH(tr, msg) */
550+
struct lc_hash_ctx *hash_ctx = &ctx->dilithium_hash_ctx;
551+
552+
lc_hash_init(hash_ctx);
553+
lc_hash_update(hash_ctx, tr, LC_DILITHIUM_TRBYTES);
554+
CKINT(signature_domain_separation(
555+
&ctx->dilithium_hash_ctx, ctx->ml_dsa_internal,
556+
ctx->dilithium_prehash_type, ctx->userctx,
557+
ctx->userctxlen, m, mlen, LC_DILITHIUM_NIST_CATEGORY,
558+
!!ctx->composite_ml_dsa));
559+
}
537560

538561
ret = lc_dilithium_sign_avx2_internal(sig, ctx, sk, rng_ctx);
539562

@@ -653,9 +676,6 @@ static int lc_dilithium_verify_avx2_internal(const struct lc_dilithium_sig *sig,
653676

654677
row = ws->rowbuf;
655678

656-
lc_hash_set_digestsize(hash_ctx, LC_DILITHIUM_CRHBYTES);
657-
lc_hash_final(hash_ctx, ws->mu);
658-
659679
/* Expand challenge */
660680
poly_challenge_avx(&ws->c, sig->sig);
661681
poly_ntt_avx(&ws->c);
@@ -720,9 +740,23 @@ static int lc_dilithium_verify_avx2_internal(const struct lc_dilithium_sig *sig,
720740
}
721741
}
722742

723-
/* Call random oracle and verify challenge */
724-
lc_hash_init(hash_ctx);
725-
lc_hash_update(hash_ctx, ws->mu, LC_DILITHIUM_CRHBYTES);
743+
if (ctx->external_mu) {
744+
if (ctx->external_mu_len != LC_DILITHIUM_CRHBYTES)
745+
return -EINVAL;
746+
747+
/* Call random oracle and verify challenge */
748+
lc_hash_init(hash_ctx);
749+
lc_hash_update(hash_ctx, ctx->external_mu,
750+
LC_DILITHIUM_CRHBYTES);
751+
} else {
752+
lc_hash_set_digestsize(hash_ctx, LC_DILITHIUM_CRHBYTES);
753+
lc_hash_final(hash_ctx, ws->mu);
754+
755+
/* Call random oracle and verify challenge */
756+
lc_hash_init(hash_ctx);
757+
lc_hash_update(hash_ctx, ws->mu, LC_DILITHIUM_CRHBYTES);
758+
}
759+
726760
lc_hash_update(hash_ctx, ws->buf.coeffs,
727761
LC_DILITHIUM_K * LC_DILITHIUM_POLYW1_PACKEDBYTES);
728762
lc_hash_set_digestsize(hash_ctx, LC_DILITHIUM_CTILDE_BYTES);
@@ -747,9 +781,11 @@ LC_INTERFACE_FUNCTION(int, lc_dilithium_verify_ctx_avx2,
747781
uint8_t tr[LC_DILITHIUM_TRBYTES];
748782
int ret = 0;
749783
static int tested = 0;
750-
struct lc_hash_ctx *hash_ctx;
751784

752-
if (!sig || !m || !pk || !ctx)
785+
if (!sig || !pk || !ctx)
786+
return -EINVAL;
787+
/* Either the message or the external mu must be provided */
788+
if (!m && !ctx->external_mu)
753789
return -EINVAL;
754790

755791
dilithium_sigver_tester(&tested, "Dilithium Sigver AVX2",
@@ -759,13 +795,16 @@ LC_INTERFACE_FUNCTION(int, lc_dilithium_verify_ctx_avx2,
759795
lc_xof(lc_shake256, pk->pk, LC_DILITHIUM_PUBLICKEYBYTES, tr,
760796
LC_DILITHIUM_TRBYTES);
761797

762-
hash_ctx = &ctx->dilithium_hash_ctx;
763-
lc_hash_init(hash_ctx);
764-
lc_hash_update(hash_ctx, tr, LC_DILITHIUM_TRBYTES);
765-
CKINT(signature_domain_separation(
766-
&ctx->dilithium_hash_ctx, ctx->ml_dsa_internal,
767-
ctx->dilithium_prehash_type, ctx->userctx, ctx->userctxlen, m,
768-
mlen, LC_DILITHIUM_NIST_CATEGORY, !!ctx->composite_ml_dsa));
798+
if (m) {
799+
struct lc_hash_ctx *hash_ctx = &ctx->dilithium_hash_ctx;
800+
lc_hash_init(hash_ctx);
801+
lc_hash_update(hash_ctx, tr, LC_DILITHIUM_TRBYTES);
802+
CKINT(signature_domain_separation(
803+
&ctx->dilithium_hash_ctx, ctx->ml_dsa_internal,
804+
ctx->dilithium_prehash_type, ctx->userctx,
805+
ctx->userctxlen, m, mlen, LC_DILITHIUM_NIST_CATEGORY,
806+
!!ctx->composite_ml_dsa));
807+
}
769808

770809
ret = lc_dilithium_verify_avx2_internal(sig, pk, ctx);
771810

ml-dsa/src/dilithium_api.c

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,16 @@ LC_INTERFACE_FUNCTION(void, lc_dilithium_ctx_userctx,
118118
}
119119
}
120120

121+
LC_INTERFACE_FUNCTION(void, lc_dilithium_ctx_external_mu,
122+
struct lc_dilithium_ctx *ctx, const uint8_t *external_mu,
123+
size_t external_mu_len)
124+
{
125+
if (ctx) {
126+
ctx->external_mu = external_mu;
127+
ctx->external_mu_len = external_mu_len;
128+
}
129+
}
130+
121131
LC_INTERFACE_FUNCTION(void, lc_dilithium_ctx_drop_ahat,
122132
struct lc_dilithium_ctx *ctx)
123133
{

0 commit comments

Comments
 (0)