diff --git a/.CMake/alg_support.cmake b/.CMake/alg_support.cmake index 9c7fc77d4b..0c17408e29 100644 --- a/.CMake/alg_support.cmake +++ b/.CMake/alg_support.cmake @@ -174,6 +174,7 @@ cmake_dependent_option(OQS_ENABLE_KEM_ml_kem_768 "" ON "OQS_ENABLE_KEM_ML_KEM" O cmake_dependent_option(OQS_ENABLE_KEM_ml_kem_1024 "" ON "OQS_ENABLE_KEM_ML_KEM" OFF) option(OQS_ENABLE_SIG_ML_DSA "Enable ml_dsa algorithm family" ON) +cmake_dependent_option(OQS_ENABLE_SIG_ML_DSA_RANDOMIZED_SIGNING "Enable randomized signing for ML-DSA" ON "OQS_ENABLE_SIG_ML_DSA" OFF) cmake_dependent_option(OQS_ENABLE_SIG_ml_dsa_44 "" ON "OQS_ENABLE_SIG_ML_DSA" OFF) cmake_dependent_option(OQS_ENABLE_SIG_ml_dsa_65 "" ON "OQS_ENABLE_SIG_ML_DSA" OFF) cmake_dependent_option(OQS_ENABLE_SIG_ml_dsa_87 "" ON "OQS_ENABLE_SIG_ML_DSA" OFF) diff --git a/CONFIGURE.md b/CONFIGURE.md index c73eb84889..20783b629c 100644 --- a/CONFIGURE.md +++ b/CONFIGURE.md @@ -64,6 +64,14 @@ For a full list of such options and their default values, consult [.CMake/alg_su **Default**: Unset. +### OQS_ENABLE_SIG_ML_DSA_RANDOMIZED_SIGNING + +Can be set to `ON` or `OFF`. When `ON`, ML-DSA signature algorithms are built with randomized signing enabled, resulting in non-deterministic signatures. When `OFF`, ML-DSA signature algorithms use deterministic signing. + +This option is only available if `OQS_ENABLE_SIG_ML_DSA` is `ON`. + +**Default**: `ON`. + ## OQS_ALGS_ENABLED A selected algorithm set is enabled. Possible values are "STD" selecting all algorithms standardized by NIST; "NIST_R4" selecting all algorithms evaluated in round 4 of the NIST PQC competition; "NIST_SIG_ONRAMP" selecting algorithms evaluated in the NIST PQC "onramp" standardization for additional signature schemes; "All" (or any other value) selecting all algorithms integrated into liboqs. Parameter setting "STD" minimizes library size but may require re-running code generator scripts in projects integrating `liboqs`; e.g., [oqs-provider](https://github.com/open-quantum-safe/oqs-provider) and [oqs-boringssl](https://github.com/open-quantum-safe/boringssl). diff --git a/scripts/copy_from_upstream/.CMake/alg_support.cmake/add_enable_by_alg.fragment b/scripts/copy_from_upstream/.CMake/alg_support.cmake/add_enable_by_alg.fragment index 62135d9d43..5b70f269f0 100644 --- a/scripts/copy_from_upstream/.CMake/alg_support.cmake/add_enable_by_alg.fragment +++ b/scripts/copy_from_upstream/.CMake/alg_support.cmake/add_enable_by_alg.fragment @@ -17,6 +17,9 @@ cmake_dependent_option(OQS_ENABLE_KEM_{{ family['name'] }}_{{ scheme['alias_sche option(OQS_ENABLE_SIG_{{ family['name']|upper }} "Enable {{ family['name'] }} algorithm family" OFF) {%- else %} option(OQS_ENABLE_SIG_{{ family['name']|upper }} "Enable {{ family['name'] }} algorithm family" ON) +{%- endif %} +{%- if family['name'] == "ml_dsa" %} +cmake_dependent_option(OQS_ENABLE_SIG_ML_DSA_RANDOMIZED_SIGNING "Enable randomized signing for ML-DSA" ON "OQS_ENABLE_SIG_ML_DSA" OFF) {%- endif %} {%- for scheme in family['schemes'] %} cmake_dependent_option(OQS_ENABLE_SIG_{{ family['name'] }}_{{ scheme['scheme'] }} "" ON "OQS_ENABLE_SIG_{{ family['name']|upper }}" OFF) diff --git a/scripts/copy_from_upstream/patches/pqcrystals-ml_dsa.patch b/scripts/copy_from_upstream/patches/pqcrystals-ml_dsa.patch index e82d5c1edb..344e8e1130 100644 --- a/scripts/copy_from_upstream/patches/pqcrystals-ml_dsa.patch +++ b/scripts/copy_from_upstream/patches/pqcrystals-ml_dsa.patch @@ -140,10 +140,18 @@ index 5163526..e9bff1e 100644 - architecture: x86_64 operating_systems: diff --git a/avx2/config.h b/avx2/config.h -index a9facc0..3944cb4 100644 +index a9facc0..da97994 100644 --- a/avx2/config.h +++ b/avx2/config.h -@@ -11,17 +11,17 @@ +@@ -2,7 +2,6 @@ + #define CONFIG_H + + //#define DILITHIUM_MODE 2 +-#define DILITHIUM_RANDOMIZED_SIGNING + //#define USE_RDPMC + //#define DBENCH + +@@ -11,17 +10,17 @@ #endif #if DILITHIUM_MODE == 2 @@ -520,10 +528,18 @@ index 8f3c3c5..fa49963 100644 #endif diff --git a/ref/config.h b/ref/config.h -index 98b8ccb..8008e11 100644 +index 98b8ccb..7d52ebc 100644 --- a/ref/config.h +++ b/ref/config.h -@@ -11,17 +11,17 @@ +@@ -2,7 +2,6 @@ + #define CONFIG_H + + //#define DILITHIUM_MODE 2 +-#define DILITHIUM_RANDOMIZED_SIGNING + //#define USE_RDPMC + //#define DBENCH + +@@ -11,17 +10,17 @@ #endif #if DILITHIUM_MODE == 2 diff --git a/scripts/copy_from_upstream/src/sig/family/CMakeLists.txt b/scripts/copy_from_upstream/src/sig/family/CMakeLists.txt index b9103baa19..10b31e78ee 100644 --- a/scripts/copy_from_upstream/src/sig/family/CMakeLists.txt +++ b/scripts/copy_from_upstream/src/sig/family/CMakeLists.txt @@ -46,6 +46,11 @@ if(OQS_ENABLE_SIG_{{ family }}_{{ scheme['scheme_c'] }}_{{ impl['name'] }}{%- if {%- if impl['compile_opts'] %} target_compile_options({{ family }}_{{ scheme['scheme'] }}_{{ impl['name'] }} PUBLIC {{ impl['compile_opts'] }}) {%- endif %} + {%- if family == 'ml_dsa' %} + if(OQS_ENABLE_SIG_ML_DSA_RANDOMIZED_SIGNING) + target_compile_options({{ family }}_{{ scheme['scheme'] }}_{{ impl['name'] }} PUBLIC -DDILITHIUM_RANDOMIZED_SIGNING) + endif() + {%- endif %} set(_{{ family|upper }}_OBJS ${_{{ family|upper }}_OBJS} $) endif() {%- endfor -%} diff --git a/src/sig/ml_dsa/CMakeLists.txt b/src/sig/ml_dsa/CMakeLists.txt index 37c1b373d7..731447f2db 100644 --- a/src/sig/ml_dsa/CMakeLists.txt +++ b/src/sig/ml_dsa/CMakeLists.txt @@ -11,6 +11,9 @@ if(OQS_ENABLE_SIG_ml_dsa_44) target_include_directories(ml_dsa_44_ref PRIVATE ${CMAKE_CURRENT_LIST_DIR}/pqcrystals-dilithium-standard_ml-dsa-44_ref) target_include_directories(ml_dsa_44_ref PRIVATE ${PROJECT_SOURCE_DIR}/src/common/pqclean_shims) target_compile_options(ml_dsa_44_ref PUBLIC -DDILITHIUM_MODE=2) + if(OQS_ENABLE_SIG_ML_DSA_RANDOMIZED_SIGNING) + target_compile_options(ml_dsa_44_ref PUBLIC -DDILITHIUM_RANDOMIZED_SIGNING) + endif() set(_ML_DSA_OBJS ${_ML_DSA_OBJS} $) endif() @@ -20,6 +23,9 @@ if(OQS_ENABLE_SIG_ml_dsa_44_avx2) target_include_directories(ml_dsa_44_avx2 PRIVATE ${PROJECT_SOURCE_DIR}/src/common/pqclean_shims) target_compile_options(ml_dsa_44_avx2 PRIVATE -mavx2 -mpopcnt) target_compile_options(ml_dsa_44_avx2 PUBLIC -DDILITHIUM_MODE=2) + if(OQS_ENABLE_SIG_ML_DSA_RANDOMIZED_SIGNING) + target_compile_options(ml_dsa_44_avx2 PUBLIC -DDILITHIUM_RANDOMIZED_SIGNING) + endif() set(_ML_DSA_OBJS ${_ML_DSA_OBJS} $) endif() @@ -29,6 +35,9 @@ if(OQS_ENABLE_SIG_ml_dsa_65) target_include_directories(ml_dsa_65_ref PRIVATE ${CMAKE_CURRENT_LIST_DIR}/pqcrystals-dilithium-standard_ml-dsa-65_ref) target_include_directories(ml_dsa_65_ref PRIVATE ${PROJECT_SOURCE_DIR}/src/common/pqclean_shims) target_compile_options(ml_dsa_65_ref PUBLIC -DDILITHIUM_MODE=3) + if(OQS_ENABLE_SIG_ML_DSA_RANDOMIZED_SIGNING) + target_compile_options(ml_dsa_65_ref PUBLIC -DDILITHIUM_RANDOMIZED_SIGNING) + endif() set(_ML_DSA_OBJS ${_ML_DSA_OBJS} $) endif() @@ -38,6 +47,9 @@ if(OQS_ENABLE_SIG_ml_dsa_65_avx2) target_include_directories(ml_dsa_65_avx2 PRIVATE ${PROJECT_SOURCE_DIR}/src/common/pqclean_shims) target_compile_options(ml_dsa_65_avx2 PRIVATE -mavx2 -mpopcnt) target_compile_options(ml_dsa_65_avx2 PUBLIC -DDILITHIUM_MODE=3) + if(OQS_ENABLE_SIG_ML_DSA_RANDOMIZED_SIGNING) + target_compile_options(ml_dsa_65_avx2 PUBLIC -DDILITHIUM_RANDOMIZED_SIGNING) + endif() set(_ML_DSA_OBJS ${_ML_DSA_OBJS} $) endif() @@ -47,6 +59,9 @@ if(OQS_ENABLE_SIG_ml_dsa_87) target_include_directories(ml_dsa_87_ref PRIVATE ${CMAKE_CURRENT_LIST_DIR}/pqcrystals-dilithium-standard_ml-dsa-87_ref) target_include_directories(ml_dsa_87_ref PRIVATE ${PROJECT_SOURCE_DIR}/src/common/pqclean_shims) target_compile_options(ml_dsa_87_ref PUBLIC -DDILITHIUM_MODE=5) + if(OQS_ENABLE_SIG_ML_DSA_RANDOMIZED_SIGNING) + target_compile_options(ml_dsa_87_ref PUBLIC -DDILITHIUM_RANDOMIZED_SIGNING) + endif() set(_ML_DSA_OBJS ${_ML_DSA_OBJS} $) endif() @@ -56,6 +71,9 @@ if(OQS_ENABLE_SIG_ml_dsa_87_avx2) target_include_directories(ml_dsa_87_avx2 PRIVATE ${PROJECT_SOURCE_DIR}/src/common/pqclean_shims) target_compile_options(ml_dsa_87_avx2 PRIVATE -mavx2 -mpopcnt) target_compile_options(ml_dsa_87_avx2 PUBLIC -DDILITHIUM_MODE=5) + if(OQS_ENABLE_SIG_ML_DSA_RANDOMIZED_SIGNING) + target_compile_options(ml_dsa_87_avx2 PUBLIC -DDILITHIUM_RANDOMIZED_SIGNING) + endif() set(_ML_DSA_OBJS ${_ML_DSA_OBJS} $) endif() diff --git a/src/sig/ml_dsa/pqcrystals-dilithium-standard_ml-dsa-44_avx2/config.h b/src/sig/ml_dsa/pqcrystals-dilithium-standard_ml-dsa-44_avx2/config.h index 3944cb4412..e95287e5f4 100644 --- a/src/sig/ml_dsa/pqcrystals-dilithium-standard_ml-dsa-44_avx2/config.h +++ b/src/sig/ml_dsa/pqcrystals-dilithium-standard_ml-dsa-44_avx2/config.h @@ -2,7 +2,6 @@ #define CONFIG_H //#define DILITHIUM_MODE 2 -#define DILITHIUM_RANDOMIZED_SIGNING //#define USE_RDPMC //#define DBENCH diff --git a/src/sig/ml_dsa/pqcrystals-dilithium-standard_ml-dsa-44_ref/config.h b/src/sig/ml_dsa/pqcrystals-dilithium-standard_ml-dsa-44_ref/config.h index 8008e11a92..73623fef56 100644 --- a/src/sig/ml_dsa/pqcrystals-dilithium-standard_ml-dsa-44_ref/config.h +++ b/src/sig/ml_dsa/pqcrystals-dilithium-standard_ml-dsa-44_ref/config.h @@ -2,7 +2,6 @@ #define CONFIG_H //#define DILITHIUM_MODE 2 -#define DILITHIUM_RANDOMIZED_SIGNING //#define USE_RDPMC //#define DBENCH diff --git a/src/sig/ml_dsa/pqcrystals-dilithium-standard_ml-dsa-65_avx2/config.h b/src/sig/ml_dsa/pqcrystals-dilithium-standard_ml-dsa-65_avx2/config.h index 3944cb4412..e95287e5f4 100644 --- a/src/sig/ml_dsa/pqcrystals-dilithium-standard_ml-dsa-65_avx2/config.h +++ b/src/sig/ml_dsa/pqcrystals-dilithium-standard_ml-dsa-65_avx2/config.h @@ -2,7 +2,6 @@ #define CONFIG_H //#define DILITHIUM_MODE 2 -#define DILITHIUM_RANDOMIZED_SIGNING //#define USE_RDPMC //#define DBENCH diff --git a/src/sig/ml_dsa/pqcrystals-dilithium-standard_ml-dsa-65_ref/config.h b/src/sig/ml_dsa/pqcrystals-dilithium-standard_ml-dsa-65_ref/config.h index 8008e11a92..73623fef56 100644 --- a/src/sig/ml_dsa/pqcrystals-dilithium-standard_ml-dsa-65_ref/config.h +++ b/src/sig/ml_dsa/pqcrystals-dilithium-standard_ml-dsa-65_ref/config.h @@ -2,7 +2,6 @@ #define CONFIG_H //#define DILITHIUM_MODE 2 -#define DILITHIUM_RANDOMIZED_SIGNING //#define USE_RDPMC //#define DBENCH diff --git a/src/sig/ml_dsa/pqcrystals-dilithium-standard_ml-dsa-87_avx2/config.h b/src/sig/ml_dsa/pqcrystals-dilithium-standard_ml-dsa-87_avx2/config.h index 3944cb4412..e95287e5f4 100644 --- a/src/sig/ml_dsa/pqcrystals-dilithium-standard_ml-dsa-87_avx2/config.h +++ b/src/sig/ml_dsa/pqcrystals-dilithium-standard_ml-dsa-87_avx2/config.h @@ -2,7 +2,6 @@ #define CONFIG_H //#define DILITHIUM_MODE 2 -#define DILITHIUM_RANDOMIZED_SIGNING //#define USE_RDPMC //#define DBENCH diff --git a/src/sig/ml_dsa/pqcrystals-dilithium-standard_ml-dsa-87_ref/config.h b/src/sig/ml_dsa/pqcrystals-dilithium-standard_ml-dsa-87_ref/config.h index 8008e11a92..73623fef56 100644 --- a/src/sig/ml_dsa/pqcrystals-dilithium-standard_ml-dsa-87_ref/config.h +++ b/src/sig/ml_dsa/pqcrystals-dilithium-standard_ml-dsa-87_ref/config.h @@ -2,7 +2,6 @@ #define CONFIG_H //#define DILITHIUM_MODE 2 -#define DILITHIUM_RANDOMIZED_SIGNING //#define USE_RDPMC //#define DBENCH diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 76b47492f8..436984e4d7 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -154,6 +154,9 @@ endif() add_executable(test_sig test_sig.c test_helpers.c) target_link_libraries(test_sig PRIVATE ${TEST_DEPS}) +if(OQS_ENABLE_SIG_ML_DSA_RANDOMIZED_SIGNING) + target_compile_definitions(test_sig PRIVATE OQS_ENABLE_SIG_ML_DSA_RANDOMIZED_SIGNING) +endif() if(CMAKE_SYSTEM_NAME STREQUAL "Windows" AND BUILD_SHARED_LIBS) # workaround for Windows .dll if(CMAKE_CROSSCOMPILING) diff --git a/tests/helpers.py b/tests/helpers.py index 077b4d428f..8fb115ed64 100644 --- a/tests/helpers.py +++ b/tests/helpers.py @@ -193,6 +193,17 @@ def available_use_options_by_name(): def is_use_option_enabled_by_name(name): return name in available_use_options_by_name() +def is_ml_dsa_randomized_signing_enabled(): + header = os.path.join(get_current_build_dir_name(), 'include', 'oqs', 'oqsconfig.h') + try: + with open(header) as fh: + for line in fh: + if line.strip() == "#define OQS_ENABLE_SIG_ML_DSA_RANDOMIZED_SIGNING": + return True + except Exception: + pass + return False + def get_kats(t): if kats[t] is None: with open(os.path.join('tests', 'KATs', t, 'kats.json'), 'r') as fp: diff --git a/tests/test_acvp_vectors.py b/tests/test_acvp_vectors.py index 7cc4240490..26f0893382 100644 --- a/tests/test_acvp_vectors.py +++ b/tests/test_acvp_vectors.py @@ -159,6 +159,9 @@ def test_acvp_vec_ml_dsa_sig_gen(sig_name): if variant["parameterSet"] == sig_name: variantFound = True for testCase in variant["tests"]: + # Skip randomized signature vectors if built in deterministic mode + if (not helpers.is_ml_dsa_randomized_signing_enabled()) and (not variant["deterministic"]): + pytest.skip("Skipping randomized signature vector test: implementation built in deterministic mode") sk = testCase["sk"] message = testCase["message"] signature = testCase["signature"] diff --git a/tests/test_kat.py b/tests/test_kat.py index dde7b02a78..3a10594633 100644 --- a/tests/test_kat.py +++ b/tests/test_kat.py @@ -27,6 +27,9 @@ def test_sig(sig_name): kats = helpers.get_kats("sig") # slh dsa will run ACVP vectors instead if ("SLH_DSA" in sig_name): pytest.skip('slhdsa not enabled for KATs') + # Skip ML-DSA KATs if randomized signing is not enabled + if sig_name in ["ML-DSA-44", "ML-DSA-65", "ML-DSA-87"] and not helpers.is_ml_dsa_randomized_signing_enabled(): + pytest.skip("Skipping ML-DSA KAT signature test: implementation built in deterministic mode") if not(helpers.is_sig_enabled_by_name(sig_name)): pytest.skip('Not enabled') output = helpers.run_subprocess( [helpers.path_to_executable('kat_sig'), sig_name], diff --git a/tests/test_kat_all.py b/tests/test_kat_all.py index 67354876f2..236f96e3fd 100644 --- a/tests/test_kat_all.py +++ b/tests/test_kat_all.py @@ -27,6 +27,9 @@ def test_sig(sig_name): kats = helpers.get_kats("sig") # slh dsa will run ACVP vectors instead if ("SLH_DSA" in sig_name): pytest.skip('slhdsa not enabled for KATs') + # Skip ML-DSA KATs if randomized signing is not enabled + if sig_name in ["ML-DSA-44", "ML-DSA-65", "ML-DSA-87"] and not helpers.is_ml_dsa_randomized_signing_enabled(): + pytest.skip("Skipping ML-DSA KAT signature test: implementation built in deterministic mode") if not(helpers.is_sig_enabled_by_name(sig_name)): pytest.skip('Not enabled') output = helpers.run_subprocess( [helpers.path_to_executable('kat_sig'), sig_name, '--all'], diff --git a/tests/test_sig.c b/tests/test_sig.c old mode 100644 new mode 100755 index 40a60f654c..13fee43110 --- a/tests/test_sig.c +++ b/tests/test_sig.c @@ -244,6 +244,110 @@ static OQS_STATUS sig_test_correctness(const char *method_name, bool bitflips_al return ret; } +static OQS_STATUS sig_test_repeat_signing(const char *method_name, bool is_randomized) { + OQS_SIG *sig = NULL; + uint8_t *public_key = NULL; + uint8_t *secret_key = NULL; + uint8_t *message = NULL; + size_t message_len = 100; + uint8_t *signature1 = NULL; + size_t signature1_len; + uint8_t *signature2 = NULL; + size_t signature2_len; + OQS_STATUS rc, ret = OQS_ERROR; + + sig = OQS_SIG_new(method_name); + if (sig == NULL) { + fprintf(stderr, "ERROR: OQS_SIG_new failed for %s\n", method_name); + return OQS_ERROR; + } + + printf("Testing %s signing for %s\n", is_randomized ? "randomized" : "deterministic", sig->method_name); + + public_key = OQS_MEM_malloc(sig->length_public_key); + secret_key = OQS_MEM_malloc(sig->length_secret_key); + message = OQS_MEM_malloc(message_len); + signature1 = OQS_MEM_malloc(sig->length_signature); + signature2 = OQS_MEM_malloc(sig->length_signature); + + if ((public_key == NULL) || (secret_key == NULL) || (message == NULL) || (signature1 == NULL) || (signature2 == NULL)) { + fprintf(stderr, "ERROR: OQS_MEM_malloc failed\n"); + goto err; + } + + OQS_randombytes(message, message_len); + + rc = OQS_SIG_keypair(sig, public_key, secret_key); + if (rc != OQS_SUCCESS) { + fprintf(stderr, "ERROR: OQS_SIG_keypair failed\n"); + goto err; + } + + rc = OQS_SIG_sign(sig, signature1, &signature1_len, message, message_len, secret_key); + if (rc != OQS_SUCCESS) { + fprintf(stderr, "ERROR: OQS_SIG_sign failed\n"); + goto err; + } + + rc = OQS_SIG_sign(sig, signature2, &signature2_len, message, message_len, secret_key); + if (rc != OQS_SUCCESS) { + fprintf(stderr, "ERROR: OQS_SIG_sign failed\n"); + goto err; + } + + if (signature1_len != signature2_len) { + fprintf(stderr, "ERROR: %s signing for %s produced signatures of different lengths (%zu vs %zu). This should not happen.\n", + is_randomized ? "Randomized" : "Deterministic", sig->method_name, signature1_len, signature2_len); + goto err; + } + + if (is_randomized) { + if (memcmp(signature1, signature2, signature1_len) == 0) { + fprintf(stderr, "ERROR: Two signatures of the same message are identical in randomized mode.\n"); + goto err; + } else { + printf("Two signatures of the same message are not identical, as expected for randomized mode.\n"); + } + } else { + if (memcmp(signature1, signature2, signature1_len) != 0) { + fprintf(stderr, "ERROR: Two signatures of the same message are NOT identical in deterministic mode.\n"); + goto err; + } else { + printf("Two signatures of the same message are identical, as expected for deterministic mode.\n"); + } + } + + rc = OQS_SIG_verify(sig, message, message_len, signature1, signature1_len, public_key); + if (rc != OQS_SUCCESS) { + fprintf(stderr, "ERROR: OQS_SIG_verify failed for signature 1\n"); + goto err; + } + + rc = OQS_SIG_verify(sig, message, message_len, signature2, signature2_len, public_key); + if (rc != OQS_SUCCESS) { + fprintf(stderr, "ERROR: OQS_SIG_verify failed for signature 2\n"); + goto err; + } + + printf("verification passes as expected\n"); + ret = OQS_SUCCESS; + goto cleanup; + +err: + ret = OQS_ERROR; + +cleanup: + if (secret_key) { + OQS_MEM_secure_free(secret_key, sig->length_secret_key); + } + OQS_MEM_insecure_free(public_key); + OQS_MEM_insecure_free(message); + OQS_MEM_insecure_free(signature1); + OQS_MEM_insecure_free(signature2); + OQS_SIG_free(sig); + + return ret; +} #ifdef OQS_ENABLE_TEST_CONSTANT_TIME static void TEST_SIG_randombytes(uint8_t *random_array, size_t bytes_to_read) { // We can't make direct calls to the system randombytes on some platforms, @@ -349,6 +453,17 @@ int main(int argc, char **argv) { } #endif + if (strncmp(alg_name, "ML-DSA", 6) == 0) { +#if defined(OQS_ENABLE_SIG_ML_DSA_RANDOMIZED_SIGNING) + rc = sig_test_repeat_signing(alg_name, true); +#else + rc = sig_test_repeat_signing(alg_name, false); +#endif + if (rc != OQS_SUCCESS) { + OQS_destroy(); + return EXIT_FAILURE; + } + } #if OQS_USE_PTHREADS && !defined(OQS_ENABLE_TEST_CONSTANT_TIME) #define MAX_LEN_SIG_NAME_ 64 // don't run algorithms with large stack usage in threads