Skip to content

Commit 7c0e326

Browse files
committed
Add build option for randomized ML-DSA signing
Signed-off-by: M-AlNoaimi <[email protected]>
1 parent b02d0c9 commit 7c0e326

File tree

4 files changed

+116
-1
lines changed

4 files changed

+116
-1
lines changed

.CMake/alg_support.cmake

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,7 @@ cmake_dependent_option(OQS_ENABLE_KEM_ml_kem_768 "" ON "OQS_ENABLE_KEM_ML_KEM" O
174174
cmake_dependent_option(OQS_ENABLE_KEM_ml_kem_1024 "" ON "OQS_ENABLE_KEM_ML_KEM" OFF)
175175

176176
option(OQS_ENABLE_SIG_ML_DSA "Enable ml_dsa algorithm family" ON)
177+
cmake_dependent_option(OQS_ENABLE_SIG_ML_DSA_RANDOMIZED_SIGNING "Enable randomized signing for ML-DSA" OFF "OQS_ENABLE_SIG_ML_DSA" OFF)
177178
cmake_dependent_option(OQS_ENABLE_SIG_ml_dsa_44 "" ON "OQS_ENABLE_SIG_ML_DSA" OFF)
178179
cmake_dependent_option(OQS_ENABLE_SIG_ml_dsa_65 "" ON "OQS_ENABLE_SIG_ML_DSA" OFF)
179180
cmake_dependent_option(OQS_ENABLE_SIG_ml_dsa_87 "" ON "OQS_ENABLE_SIG_ML_DSA" OFF)

CONFIGURE.md

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,13 @@ To enable `XMSS` stateful signature, set `OQS_ENABLE_SIG_STFL_XMSS` to `ON`, the
6262

6363
For a full list of such options and their default values, consult [.CMake/alg_support.cmake](https://github.com/open-quantum-safe/liboqs/blob/master/.CMake/alg_support.cmake).
6464

65-
**Default**: Unset.
65+
### OQS_ENABLE_SIG_ML_DSA_RANDOMIZED_SIGNING
66+
67+
Can be set to `ON` or `OFF`. When `ON`, ML-DSA signature algorithms are built with randomized signing enabled, resulting in non-deterministic signatures (randomized seed/nonce per signature).
68+
69+
This option is only available if `OQS_ENABLE_SIG_ML_DSA` is `ON`.
70+
71+
**Default**: `OFF`.
6672

6773
## OQS_ALGS_ENABLED
6874

scripts/copy_from_upstream/.CMake/alg_support.cmake/add_enable_by_alg.fragment

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,9 @@ cmake_dependent_option(OQS_ENABLE_KEM_{{ family['name'] }}_{{ scheme['alias_sche
1717
option(OQS_ENABLE_SIG_{{ family['name']|upper }} "Enable {{ family['name'] }} algorithm family" OFF)
1818
{%- else %}
1919
option(OQS_ENABLE_SIG_{{ family['name']|upper }} "Enable {{ family['name'] }} algorithm family" ON)
20+
{%- endif %}
21+
{%- if family['name'] == "ml_dsa" %}
22+
cmake_dependent_option(OQS_ENABLE_SIG_ML_DSA_RANDOMIZED_SIGNING "Enable randomized signing for ML-DSA" OFF "OQS_ENABLE_SIG_ML_DSA" OFF)
2023
{%- endif %}
2124
{%- for scheme in family['schemes'] %}
2225
cmake_dependent_option(OQS_ENABLE_SIG_{{ family['name'] }}_{{ scheme['scheme'] }} "" ON "OQS_ENABLE_SIG_{{ family['name']|upper }}" OFF)

tests/test_sig.c

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -244,6 +244,101 @@ static OQS_STATUS sig_test_correctness(const char *method_name, bool bitflips_al
244244
return ret;
245245
}
246246

247+
#if defined(OQS_ENABLE_SIG_ML_DSA_RANDOMIZED_SIGNING)
248+
// Test that two signatures of the same message are different.
249+
static OQS_STATUS sig_test_randomized_signing(const char *method_name) {
250+
OQS_SIG *sig = NULL;
251+
uint8_t *public_key = NULL;
252+
uint8_t *secret_key = NULL;
253+
uint8_t *message = NULL;
254+
size_t message_len = 100;
255+
uint8_t *signature1 = NULL;
256+
size_t signature1_len;
257+
uint8_t *signature2 = NULL;
258+
size_t signature2_len;
259+
OQS_STATUS rc, ret = OQS_ERROR;
260+
261+
sig = OQS_SIG_new(method_name);
262+
if (sig == NULL) {
263+
// ML-DSA is not enabled, so we can't test it.
264+
return OQS_SUCCESS;
265+
}
266+
267+
printf("Testing randomized signing for %s\n", sig->method_name);
268+
269+
public_key = OQS_MEM_malloc(sig->length_public_key);
270+
secret_key = OQS_MEM_malloc(sig->length_secret_key);
271+
message = OQS_MEM_malloc(message_len);
272+
signature1 = OQS_MEM_malloc(sig->length_signature);
273+
signature2 = OQS_MEM_malloc(sig->length_signature);
274+
275+
if ((public_key == NULL) || (secret_key == NULL) || (message == NULL) || (signature1 == NULL) || (signature2 == NULL)) {
276+
fprintf(stderr, "ERROR: OQS_MEM_malloc failed\n");
277+
goto err;
278+
}
279+
280+
OQS_randombytes(message, message_len);
281+
282+
rc = OQS_SIG_keypair(sig, public_key, secret_key);
283+
if (rc != OQS_SUCCESS) {
284+
fprintf(stderr, "ERROR: OQS_SIG_keypair failed\n");
285+
goto err;
286+
}
287+
288+
rc = OQS_SIG_sign(sig, signature1, &signature1_len, message, message_len, secret_key);
289+
if (rc != OQS_SUCCESS) {
290+
fprintf(stderr, "ERROR: OQS_SIG_sign failed\n");
291+
goto err;
292+
}
293+
294+
rc = OQS_SIG_sign(sig, signature2, &signature2_len, message, message_len, secret_key);
295+
if (rc != OQS_SUCCESS) {
296+
fprintf(stderr, "ERROR: OQS_SIG_sign failed\n");
297+
goto err;
298+
}
299+
300+
if (signature1_len != signature2_len) {
301+
printf("Signatures have different lengths, so they are not identical.\n");
302+
} else if (memcmp(signature1, signature2, signature1_len) == 0) {
303+
fprintf(stderr, "ERROR: Two signatures of the same message are identical.\n");
304+
goto err;
305+
} else {
306+
printf("Two signatures of the same message are not identical, as expected.\n");
307+
}
308+
309+
rc = OQS_SIG_verify(sig, message, message_len, signature1, signature1_len, public_key);
310+
if (rc != OQS_SUCCESS) {
311+
fprintf(stderr, "ERROR: OQS_SIG_verify failed for signature 1\n");
312+
goto err;
313+
}
314+
315+
rc = OQS_SIG_verify(sig, message, message_len, signature2, signature2_len, public_key);
316+
if (rc != OQS_SUCCESS) {
317+
fprintf(stderr, "ERROR: OQS_SIG_verify failed for signature 2\n");
318+
goto err;
319+
}
320+
321+
printf("verification passes as expected\n");
322+
ret = OQS_SUCCESS;
323+
goto cleanup;
324+
325+
err:
326+
ret = OQS_ERROR;
327+
328+
cleanup:
329+
if (secret_key) {
330+
OQS_MEM_secure_free(secret_key, sig->length_secret_key);
331+
}
332+
OQS_MEM_insecure_free(public_key);
333+
OQS_MEM_insecure_free(message);
334+
OQS_MEM_insecure_free(signature1);
335+
OQS_MEM_insecure_free(signature2);
336+
OQS_SIG_free(sig);
337+
338+
return ret;
339+
}
340+
#endif
341+
247342
#ifdef OQS_ENABLE_TEST_CONSTANT_TIME
248343
static void TEST_SIG_randombytes(uint8_t *random_array, size_t bytes_to_read) {
249344
// We can't make direct calls to the system randombytes on some platforms,
@@ -349,6 +444,16 @@ int main(int argc, char **argv) {
349444
}
350445
#endif
351446

447+
#if defined(OQS_ENABLE_SIG_ML_DSA_RANDOMIZED_SIGNING)
448+
if (strncmp(alg_name, "ML-DSA", 6) == 0) {
449+
rc = sig_test_randomized_signing(alg_name);
450+
if (rc != OQS_SUCCESS) {
451+
OQS_destroy();
452+
return EXIT_FAILURE;
453+
}
454+
}
455+
#endif
456+
352457
#if OQS_USE_PTHREADS && !defined(OQS_ENABLE_TEST_CONSTANT_TIME)
353458
#define MAX_LEN_SIG_NAME_ 64
354459
// don't run algorithms with large stack usage in threads

0 commit comments

Comments
 (0)