Skip to content

Commit 94311a7

Browse files
authored
Merge pull request #555 from pq-code-package/randomized
Remove `MLD_RANDOMIZED_SIGNING` configuration option and adjust ACVP tests
2 parents 056f91d + d493f9c commit 94311a7

16 files changed

+376
-81
lines changed

README.md

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ timing side channels through suitable barriers and constant-time patterns.
5454
mldsa-native is split into a _frontend_ and two _backends_ for arithmetic and FIPS202 / SHA3. The frontend is
5555
fixed, written in C, and covers all routines that are not critical to performance. The backends are flexible, take care of
5656
performance-sensitive routines, and can be implemented in C or native code (assembly/intrinsics); see
57-
[mldsa/native/api.h](mldsa/native/api.h) for the arithmetic backend and
57+
[mldsa/native/api.h](mldsa/native/api.h) for the arithmetic backend and
5858
[mldsa/fips202/native/api.h](mldsa/fips202/native/api.h) for the FIPS-202 backend. mldsa-native currently
5959
offers backends for C, AArch64, and x86_64 - if you'd like contribute new backends, please reach out or just open a PR.
6060

@@ -81,9 +81,11 @@ Yes. mldsa-native supports all three ML-DSA security levels (ML-DSA-44, ML-DSA-6
8181

8282
### Does mldsa-native use hedged or deterministic signing?
8383

84-
By default, mldsa-native uses the "hedged" signing variant as specified in FIPS 204 Section 3.4, with `MLD_RANDOMIZED_SIGNING` enabled in [mldsa/config.h](mldsa/config.h). The hedged variant uses both fresh randomness at signing time and precomputed randomness from the private key. This helps mitigate fault injection attacks and side-channel attacks while protecting against potential flaws in the random number generator.
84+
By default, mldsa-native uses the randomized "hedged" signing variant as specified in FIPS 204 Section 3.4. The hedged variant uses both fresh randomness at signing time and precomputed randomness from the private key. This helps mitigate fault injection attacks and side-channel attacks while protecting against potential flaws in the random number generator.
8585

86-
The deterministic variant can be enabled by undefining `MLD_RANDOMIZED_SIGNING`, but FIPS 204 warns that this should not be used on platforms where fault injection attacks and side-channel attacks are a concern, as the lack of fresh randomness makes fault attacks more difficult to mitigate.
86+
If you need the deterministic variant of ML-DSA, you can call `crypto_sign_signature_internal`
87+
directly with an all-zero `rnd` argument.
88+
However, note that FIPS 204 warns that this should not be used on platforms where fault injection attacks and side-channel attacks are a concern, as the lack of fresh randomness makes fault attacks more difficult to mitigate.
8789

8890
### Does mldsa-native support the external mu mode?
8991

@@ -106,7 +108,7 @@ Yes, you will be able to add custom backends for ML-DSA native arithmetic and/or
106108
## Have a Question?
107109

108110
If you think you have found a security bug in mldsa-native, please report the vulnerability through
109-
Github's [private vulnerability reporting](https://github.com/pq-code-package/mldsa-native/security).
111+
Github's [private vulnerability reporting](https://github.com/pq-code-package/mldsa-native/security).
110112
Please do **not** create a public GitHub issue.
111113

112114
If you have any other question / non-security related issue / feature request, please open a GitHub issue.

integration/liboqs/config_aarch64.h

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,6 @@
2424
#endif
2525
#endif /* !__ASSEMBLER__ */
2626

27-
28-
#define MLD_RANDOMIZED_SIGNING
29-
3027
/* Use OQS's FIPS202 via glue headers */
3128
#define MLD_CONFIG_FIPS202_CUSTOM_HEADER "../integration/liboqs/fips202_glue.h"
3229
#define MLD_CONFIG_FIPS202X4_CUSTOM_HEADER \

integration/liboqs/config_c.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,6 @@
2424
#endif
2525
#endif /* !__ASSEMBLER__ */
2626

27-
#define MLD_RANDOMIZED_SIGNING
28-
2927
/* Use OQS's FIPS202 via glue headers */
3028
#define MLD_CONFIG_FIPS202_CUSTOM_HEADER "../integration/liboqs/fips202_glue.h"
3129
#define MLD_CONFIG_FIPS202X4_CUSTOM_HEADER \

integration/liboqs/config_x86_64.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,6 @@
2424
#endif
2525
#endif /* !__ASSEMBLER__ */
2626

27-
#define MLD_RANDOMIZED_SIGNING
28-
2927
/* Use OQS's FIPS202 via glue headers */
3028
#define MLD_CONFIG_FIPS202_CUSTOM_HEADER "../integration/liboqs/fips202_glue.h"
3129
#define MLD_CONFIG_FIPS202X4_CUSTOM_HEADER \

mldsa/config.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,6 @@
2020
#ifndef MLD_CONFIG_H
2121
#define MLD_CONFIG_H
2222

23-
#define MLD_RANDOMIZED_SIGNING
24-
2523
/******************************************************************************
2624
* Name: MLD_CONFIG_PARAMETER_SET
2725
*

mldsa/sign.c

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -600,13 +600,10 @@ int crypto_sign_signature(uint8_t *sig, size_t *siglen, const uint8_t *m,
600600
pre[2 + i] = ctx[i];
601601
}
602602

603-
#ifdef MLD_RANDOMIZED_SIGNING
603+
/* Randomized variant of ML-DSA. If you need the deterministic variant,
604+
* call crypto_sign_signature_internal directly with all-zero rnd. */
604605
mld_randombytes(rnd, MLDSA_RNDBYTES);
605606
MLD_CT_TESTING_SECRET(rnd, sizeof(rnd));
606-
#else
607-
mld_memset(rnd, 0, MLDSA_RNDBYTES);
608-
#endif
609-
610607

611608
result = crypto_sign_signature_internal(sig, siglen, m, mlen, pre, 2 + ctxlen,
612609
rnd, sk, 0);
@@ -627,12 +624,10 @@ int crypto_sign_signature_extmu(uint8_t *sig, size_t *siglen,
627624
uint8_t rnd[MLDSA_RNDBYTES];
628625
int result;
629626

630-
#ifdef MLD_RANDOMIZED_SIGNING
627+
/* Randomized variant of ML-DSA. If you need the deterministic variant,
628+
* call crypto_sign_signature_internal directly with all-zero rnd. */
631629
mld_randombytes(rnd, MLDSA_RNDBYTES);
632630
MLD_CT_TESTING_SECRET(rnd, sizeof(rnd));
633-
#else
634-
mld_memset(rnd, 0, MLDSA_RNDBYTES);
635-
#endif
636631

637632
result = crypto_sign_signature_internal(sig, siglen, mu, MLDSA_CRHBYTES, NULL,
638633
0, rnd, sk, 1);

mldsa/sign.h

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -172,7 +172,9 @@ __contract__(
172172
/*************************************************
173173
* Name: crypto_sign_signature
174174
*
175-
* Description: Computes signature.
175+
* Description: Computes signature. This function implements the randomized
176+
* variant of ML-DSA. If you require the deterministic variant,
177+
* use crypto_sign_signature_internal directly.
176178
*
177179
* Arguments: - uint8_t *sig: pointer to output signature (of length
178180
* CRYPTO_BYTES)
@@ -186,7 +188,7 @@ __contract__(
186188
*
187189
* Returns 0 (success) or -1 (context string too long OR nonce exhaustion)
188190
*
189-
* Specification: Implements @[FIPS204 Algorithm 2 (ML-DSA.Sign)]
191+
* Specification: Implements @[FIPS204 Algorithm 2 (ML-DSA.Sign)].
190192
*
191193
**************************************************/
192194
MLD_MUST_CHECK_RETURN_VALUE
@@ -211,7 +213,9 @@ __contract__(
211213
/*************************************************
212214
* Name: crypto_sign_signature_extmu
213215
*
214-
* Description: Computes signature.
216+
* Description: Computes signature. This function implements the randomized
217+
* variant of ML-DSA. If you require the deterministic variant,
218+
* use crypto_sign_signature_internal directly.
215219
*
216220
* Arguments: - uint8_t *sig: pointer to output signature (of length
217221
* CRYPTO_BYTES)

test/acvp_client.py

Lines changed: 19 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -167,31 +167,35 @@ def run_sigGen_test(tg, tc):
167167

168168
assert tg["testType"] == "AFT"
169169

170-
# TODO: probably we want to handle handle the deterministic case differently
171-
if tg["deterministic"] is True:
172-
tc["rnd"] = "0" * 64
170+
is_deterministic = tg["deterministic"] is True
173171

174172
if tg["preHash"] == "preHash":
175173
assert len(tc["context"]) <= 2 * 255
176174

177175
# Use specialized SHAKE256 function that computes hash internally
178176
if tc["hashAlg"] == "SHAKE-256":
177+
target = (
178+
"sigGenPreHashShake256Deterministic"
179+
if is_deterministic
180+
else "sigGenPreHashShake256"
181+
)
179182
acvp_call = exec_prefix + [
180183
acvp_bin,
181-
"sigGenPreHashShake256",
184+
target,
182185
f"message={tc['message']}",
183186
f"context={tc['context']}",
184-
f"rnd={tc['rnd']}",
185187
f"sk={tc['sk']}",
186188
]
187189
else:
188190
ph = compute_hash(tc["message"], tc["hashAlg"])
191+
target = (
192+
"sigGenPreHashDeterministic" if is_deterministic else "sigGenPreHash"
193+
)
189194
acvp_call = exec_prefix + [
190195
acvp_bin,
191-
"sigGenPreHash",
196+
target,
192197
f"ph={ph}",
193198
f"context={tc['context']}",
194-
f"rng={tc['rnd']}",
195199
f"sk={tc['sk']}",
196200
f"hashAlg={tc['hashAlg']}",
197201
]
@@ -200,11 +204,11 @@ def run_sigGen_test(tg, tc):
200204
assert len(tc["context"]) <= 2 * 255
201205
assert len(tc["message"]) <= 2 * 65536
202206

207+
target = "sigGenDeterministic" if is_deterministic else "sigGen"
203208
acvp_call = exec_prefix + [
204209
acvp_bin,
205-
"sigGen",
210+
target,
206211
f"message={tc['message']}",
207-
f"rnd={tc['rnd']}",
208212
f"sk={tc['sk']}",
209213
f"context={tc['context']}",
210214
]
@@ -219,15 +223,19 @@ def run_sigGen_test(tg, tc):
219223
assert len(tc["message"]) <= 2 * 65536
220224
msg = tc["message"]
221225

226+
target = "sigGenInternalDeterministic" if is_deterministic else "sigGenInternal"
222227
acvp_call = exec_prefix + [
223228
acvp_bin,
224-
"sigGenInternal",
229+
target,
225230
f"message={msg}",
226-
f"rnd={tc['rnd']}",
227231
f"sk={tc['sk']}",
228232
f"externalMu={externalMu}",
229233
]
230234

235+
# Append rnd argument for randomized (non-deterministic) variant
236+
if not is_deterministic:
237+
acvp_call.append(f"rnd={tc['rnd']}")
238+
231239
result = subprocess.run(acvp_call, encoding="utf-8", capture_output=True)
232240
if result.returncode != 0:
233241
err("FAIL!")

0 commit comments

Comments
 (0)