From 77538a1d6f8999a4c2914e9d954957cd1e2b1a3f Mon Sep 17 00:00:00 2001 From: Spencer Wilson Date: Wed, 20 Dec 2023 15:29:04 -0500 Subject: [PATCH] All KATs passing with new PRNG abstraction --- src/common/rand/rand_nist.c | 25 +++--- src/common/rand/rand_nist.h | 10 +-- tests/CMakeLists.txt | 6 +- tests/kat_kem.c | 170 ++++-------------------------------- tests/kat_sig.c | 58 +++++------- tests/test_helpers.c | 163 ++++++++++++++++++++++++++++++++++ tests/test_helpers.h | 44 ++++++++++ 7 files changed, 270 insertions(+), 206 deletions(-) create mode 100644 tests/test_helpers.c create mode 100644 tests/test_helpers.h diff --git a/src/common/rand/rand_nist.c b/src/common/rand/rand_nist.c index 5c41fff257..66475bd28b 100644 --- a/src/common/rand/rand_nist.c +++ b/src/common/rand/rand_nist.c @@ -11,7 +11,7 @@ NIST-developed software is expressly provided "AS IS." NIST MAKES NO WARRANTY OF You are solely responsible for determining the appropriateness of using and distributing the software and you assume all risks associated with its use, including but not limited to the risks and costs of program errors, compliance with applicable laws, damage to or loss of data, programs or equipment, and the unavailability or interruption of operation. This software is not intended to be used in any situation where a failure could cause risk of injury or damage to property. The software developed by NIST employees is not subject to copyright protection within the United States. */ // SPDX-License-Identifier: Unknown -// Modified for liboqs by Douglas Stebila +// Modified for liboqs by Douglas Stebila and Spencer Wilson // #include @@ -38,7 +38,6 @@ typedef struct { } AES256_CTR_DRBG_struct; static AES256_CTR_DRBG_struct DRBG_ctx; -static AES256_CTR_DRBG_struct DRBG_ctx_backup; static void AES256_CTR_DRBG_Update(unsigned char *provided_data, unsigned char *Key, unsigned char *V); #ifdef OQS_USE_OPENSSL @@ -128,16 +127,22 @@ void OQS_randombytes_nist_kat(unsigned char *x, size_t xlen) { DRBG_ctx.reseed_counter++; } -void OQS_randombytes_nist_kat_save_state(void) { - memcpy(DRBG_ctx_backup.Key, DRBG_ctx.Key, 32); - memcpy(DRBG_ctx_backup.V, DRBG_ctx.V, 16); - DRBG_ctx_backup.reseed_counter = DRBG_ctx.reseed_counter; +OQS_API void OQS_randombytes_nist_kat_get_state(void *out) { + AES256_CTR_DRBG_struct *out_state = (AES256_CTR_DRBG_struct *)out; + if (out_state != NULL) { + memcpy(out_state->Key, DRBG_ctx.Key, sizeof(DRBG_ctx.Key)); + memcpy(out_state->V, DRBG_ctx.V, sizeof(DRBG_ctx.V)); + out_state->reseed_counter = DRBG_ctx.reseed_counter; + } } -void OQS_randombytes_nist_kat_restore_state(void) { - memcpy(DRBG_ctx.Key, DRBG_ctx_backup.Key, 32); - memcpy(DRBG_ctx.V, DRBG_ctx_backup.V, 16); - DRBG_ctx.reseed_counter = DRBG_ctx_backup.reseed_counter; +OQS_API void OQS_randombytes_nist_kat_set_state(const void *in) { + AES256_CTR_DRBG_struct *in_state = (AES256_CTR_DRBG_struct *)in; + if (in_state != NULL) { + memcpy(DRBG_ctx.Key, in_state->Key, sizeof(DRBG_ctx.Key)); + memcpy(DRBG_ctx.V, in_state->V, sizeof(DRBG_ctx.V)); + DRBG_ctx.reseed_counter = in_state->reseed_counter; + } } static void AES256_CTR_DRBG_Update(unsigned char *provided_data, unsigned char *Key, unsigned char *V) { diff --git a/src/common/rand/rand_nist.h b/src/common/rand/rand_nist.h index 4921b4302a..aeb32327b5 100644 --- a/src/common/rand/rand_nist.h +++ b/src/common/rand/rand_nist.h @@ -29,15 +29,13 @@ void OQS_randombytes_nist_kat_init_256bit(const uint8_t *entropy_input, const ui void OQS_randombytes_nist_kat(uint8_t *random_array, size_t bytes_to_read); /** - * Saves the state of the NIST DRBG, allowing it to be recovered later. - * Calls to this function overwrite previously saved state; hence, only - * the most recently saved state can be restored. + * Writes the current state of the NIST DRBG into the provided memory. */ -void OQS_randombytes_nist_kat_save_state(void); +void OQS_randombytes_nist_kat_get_state(void *out); /** - * Restores the most recently saved NIST DRBG state. + * Overwrites the current state of the NIST DRBG from the provided memory. */ -void OQS_randombytes_nist_kat_restore_state(void); +void OQS_randombytes_nist_kat_set_state(const void *in); #endif // OQS_RAND_NIST_H diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 20c2eebd5f..e0ff5c25d8 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -62,7 +62,7 @@ endif() add_executable(example_kem example_kem.c) target_link_libraries(example_kem PRIVATE ${TEST_DEPS}) -add_executable(kat_kem kat_kem.c) +add_executable(kat_kem kat_kem.c test_helpers.c) target_link_libraries(kat_kem PRIVATE ${TEST_DEPS}) add_executable(test_kem test_kem.c) @@ -80,8 +80,8 @@ set(KEM_TESTS example_kem kat_kem test_kem test_kem_mem speed_kem) add_executable(example_sig example_sig.c) target_link_libraries(example_sig PRIVATE ${TEST_DEPS}) -add_executable(kat_sig kat_sig.c) -target_link_libraries(kat_sig PRIVATE ${TEST_DEPS}) +add_executable(kat_sig kat_sig.c test_helpers.c) +target_link_libraries(kat_sig PRIVATE ${API_TEST_DEPS}) add_executable(test_sig test_sig.c) target_link_libraries(test_sig PRIVATE ${TEST_DEPS}) diff --git a/tests/kat_kem.c b/tests/kat_kem.c index fd1ed12d09..a858868590 100644 --- a/tests/kat_kem.c +++ b/tests/kat_kem.c @@ -16,141 +16,9 @@ #include #include -#include "system_info.c" - -#define HQC_PRNG_DOMAIN 1 - -OQS_SHA3_shake256_inc_ctx shake_prng_state = { NULL }; -OQS_SHA3_shake256_inc_ctx shake_prng_state_backup = { NULL }; - -/* Displays hexadecimal strings */ -static void OQS_print_hex_string(const char *label, const uint8_t *str, size_t len) { - printf("%-20s (%4zu bytes): ", label, len); - for (size_t i = 0; i < (len); i++) { - printf("%02X", str[i]); - } - printf("\n"); -} - -static void fprintBstr(FILE *fp, const char *S, const uint8_t *A, size_t L) { - size_t i; - fprintf(fp, "%s", S); - for (i = 0; i < L; i++) { - fprintf(fp, "%02X", A[i]); - } - if (L == 0) { - fprintf(fp, "00"); - } - fprintf(fp, "\n"); -} - -static int is_mceliece(const char *method_name) { - return ( !strcmp(method_name, OQS_KEM_alg_classic_mceliece_348864) - || !strcmp(method_name, OQS_KEM_alg_classic_mceliece_348864f) - || !strcmp(method_name, OQS_KEM_alg_classic_mceliece_460896) - || !strcmp(method_name, OQS_KEM_alg_classic_mceliece_460896f) - || !strcmp(method_name, OQS_KEM_alg_classic_mceliece_6688128) - || !strcmp(method_name, OQS_KEM_alg_classic_mceliece_6688128f) - || !strcmp(method_name, OQS_KEM_alg_classic_mceliece_6960119) - || !strcmp(method_name, OQS_KEM_alg_classic_mceliece_6960119f) - || !strcmp(method_name, OQS_KEM_alg_classic_mceliece_8192128) - || !strcmp(method_name, OQS_KEM_alg_classic_mceliece_8192128f) ); -} - -/* HQC-specific functions */ -static inline bool is_hqc(const char *method_name) { - return (0 == strcmp(method_name, OQS_KEM_alg_hqc_128)) - || (0 == strcmp(method_name, OQS_KEM_alg_hqc_192)) - || (0 == strcmp(method_name, OQS_KEM_alg_hqc_256)); -} - -static void HQC_randombytes_init(const uint8_t *entropy_input, const uint8_t *personalization_string) { - uint8_t domain = HQC_PRNG_DOMAIN; - if (shake_prng_state.ctx != NULL) { - OQS_SHA3_shake256_inc_ctx_reset(&shake_prng_state); - } else { - OQS_SHA3_shake256_inc_init(&shake_prng_state); - } - OQS_SHA3_shake256_inc_absorb(&shake_prng_state, entropy_input, 48); - if (personalization_string != NULL) { - OQS_SHA3_shake256_inc_absorb(&shake_prng_state, personalization_string, 48); - } - OQS_SHA3_shake256_inc_absorb(&shake_prng_state, &domain, 1); - OQS_SHA3_shake256_inc_finalize(&shake_prng_state); -} - -static void HQC_randombytes(uint8_t *random_array, size_t bytes_to_read) { - OQS_SHA3_shake256_inc_squeeze(random_array, bytes_to_read, &shake_prng_state); -} - -static void HQC_randombytes_save_state(void) { - // initialize backup if necessary - if (shake_prng_state_backup.ctx == NULL) { - OQS_SHA3_shake256_inc_init(&shake_prng_state_backup); - } - OQS_SHA3_shake256_inc_ctx_clone(&shake_prng_state_backup, &shake_prng_state); -} - -static void HQC_randombytes_restore_state(void) { - OQS_SHA3_shake256_inc_ctx_clone(&shake_prng_state, &shake_prng_state_backup); -} - -static void HQC_randombytes_free(void) { - if (shake_prng_state.ctx != NULL) { - OQS_SHA3_shake256_inc_ctx_release(&shake_prng_state); - shake_prng_state.ctx = NULL; - } - if (shake_prng_state_backup.ctx != NULL) { - OQS_SHA3_shake256_inc_ctx_release(&shake_prng_state_backup); - shake_prng_state_backup.ctx = NULL; - } -} - -static void NIST_randombytes_free(void) {} - -typedef struct { - void (*init)(const uint8_t *, const uint8_t *); - void (*save_state)(void); - void (*restore_state)(void); - void (*free)(void); -} KAT_PRNG; - -// Initialize function pointers and set up OQS_randombytes -static KAT_PRNG *KAT_PRNG_new(const char *method_name) { - KAT_PRNG *prng; - - prng = malloc(sizeof(KAT_PRNG)); - if (prng != NULL) { - if (is_hqc(method_name)) { - // set up randombytes - OQS_randombytes_custom_algorithm(&HQC_randombytes); - prng->init = &HQC_randombytes_init; - prng->save_state = &HQC_randombytes_save_state; - prng->restore_state = &HQC_randombytes_restore_state; - prng->free = &HQC_randombytes_free; - } else { - // set NIST algs - if (OQS_randombytes_switch_algorithm(OQS_RAND_alg_nist_kat) == OQS_SUCCESS) { - prng->init = &OQS_randombytes_nist_kat_init_256bit; - prng->save_state = &OQS_randombytes_nist_kat_save_state; - prng->restore_state = &OQS_randombytes_nist_kat_restore_state; - prng->free = &NIST_randombytes_free; - } else { - OQS_MEM_insecure_free(prng); - prng = NULL; - } - } - } - return prng; -} +#include "test_helpers.h" -// Clean up memory -static void KAT_PRNG_free(KAT_PRNG *prng) { - if (prng != NULL) { - prng->free(); - } - OQS_MEM_insecure_free(prng); -} +#include "system_info.c" static OQS_STATUS kem_kat(const char *method_name, bool all) { @@ -166,7 +34,12 @@ static OQS_STATUS kem_kat(const char *method_name, bool all) { OQS_STATUS rc, ret = OQS_ERROR; int rv; int max_count; - KAT_PRNG *prng = NULL; + OQS_KAT_PRNG *prng; + + prng = OQS_KAT_PRNG_new(method_name); + if (prng == NULL) { + goto err; + } kem = OQS_KEM_new(method_name); if (kem == NULL) { @@ -174,16 +47,11 @@ static OQS_STATUS kem_kat(const char *method_name, bool all) { goto algo_not_enabled; } - prng = KAT_PRNG_new(method_name); - if (prng == NULL) { - goto err; - } - for (uint8_t i = 0; i < 48; i++) { entropy_input[i] = i; } - prng->init(entropy_input, NULL); + OQS_KAT_PRNG_seed(prng, entropy_input, NULL); fh = stdout; @@ -197,31 +65,31 @@ static OQS_STATUS kem_kat(const char *method_name, bool all) { goto err; } - max_count = all ? ( is_mceliece(method_name) ? 10 : 100 ) : 1; + max_count = all ? prng->max_kats : 1; for (int count = 0; count < max_count; ++count) { fprintf(fh, "count = %d\n", count); OQS_randombytes(seed, 48); - fprintBstr(fh, "seed = ", seed, 48); + OQS_fprintBstr(fh, "seed = ", seed, 48); - prng->save_state(); - prng->init(seed, NULL); + OQS_KAT_PRNG_save_state(prng); + OQS_KAT_PRNG_seed(prng, seed, NULL); rc = OQS_KEM_keypair(kem, public_key, secret_key); if (rc != OQS_SUCCESS) { fprintf(stderr, "[kat_kem] %s ERROR: OQS_KEM_keypair failed!\n", method_name); goto err; } - fprintBstr(fh, "pk = ", public_key, kem->length_public_key); - fprintBstr(fh, "sk = ", secret_key, kem->length_secret_key); + OQS_fprintBstr(fh, "pk = ", public_key, kem->length_public_key); + OQS_fprintBstr(fh, "sk = ", secret_key, kem->length_secret_key); rc = OQS_KEM_encaps(kem, ciphertext, shared_secret_e, public_key); if (rc != OQS_SUCCESS) { fprintf(stderr, "[kat_kem] %s ERROR: OQS_KEM_encaps failed!\n", method_name); goto err; } - fprintBstr(fh, "ct = ", ciphertext, kem->length_ciphertext); - fprintBstr(fh, "ss = ", shared_secret_e, kem->length_shared_secret); + OQS_fprintBstr(fh, "ct = ", ciphertext, kem->length_ciphertext); + OQS_fprintBstr(fh, "ss = ", shared_secret_e, kem->length_shared_secret); // The NIST program generates KAT response files with a trailing newline. if (count != max_count - 1) { @@ -242,7 +110,7 @@ static OQS_STATUS kem_kat(const char *method_name, bool all) { goto err; } - prng->restore_state(); + OQS_KAT_PRNG_restore_state(prng); } ret = OQS_SUCCESS; @@ -264,7 +132,7 @@ static OQS_STATUS kem_kat(const char *method_name, bool all) { OQS_MEM_insecure_free(public_key); OQS_MEM_insecure_free(ciphertext); OQS_KEM_free(kem); - KAT_PRNG_free(prng); + OQS_KAT_PRNG_free(prng); return ret; } diff --git a/tests/kat_sig.c b/tests/kat_sig.c index fdea3ae8c4..f6654972e2 100644 --- a/tests/kat_sig.c +++ b/tests/kat_sig.c @@ -15,28 +15,9 @@ #include #include -#include "system_info.c" +#include "test_helpers.h" -/* Displays hexadecimal strings */ -void OQS_print_hex_string(const char *label, const uint8_t *str, size_t len) { - printf("%-20s (%4zu bytes): ", label, len); - for (size_t i = 0; i < (len); i++) { - printf("%02X", str[i]); - } - printf("\n"); -} - -void fprintBstr(FILE *fp, const char *S, const uint8_t *A, size_t L) { - size_t i; - fprintf(fp, "%s", S); - for (i = 0; i < L; i++) { - fprintf(fp, "%02X", A[i]); - } - if (L == 0) { - fprintf(fp, "00"); - } - fprintf(fp, "\n"); -} +#include "system_info.c" static inline uint16_t UINT16_TO_BE(const uint16_t x) { union { @@ -262,8 +243,13 @@ OQS_STATUS sig_kat(const char *method_name, bool all) { size_t signature_len = 0; size_t signed_msg_len = 0; OQS_STATUS rc, ret = OQS_ERROR; - // int rv; - size_t max_count; + OQS_KAT_PRNG *prng = NULL; + int max_count; + + prng = OQS_KAT_PRNG_new(method_name); + if (prng == NULL) { + goto err; + } sig = OQS_SIG_new(method_name); if (sig == NULL) { @@ -275,12 +261,11 @@ OQS_STATUS sig_kat(const char *method_name, bool all) { entropy_input[i] = i; } - OQS_randombytes_custom_algorithm(&OQS_randombytes_nist_kat); - OQS_randombytes_nist_kat_init_256bit(entropy_input, NULL); + OQS_KAT_PRNG_seed(prng, entropy_input, NULL); fh = stdout; - max_count = all ? 100 : 1; + max_count = all ? prng->max_kats : 1; public_key = malloc(sig->length_public_key); secret_key = malloc(sig->length_secret_key); @@ -292,27 +277,27 @@ OQS_STATUS sig_kat(const char *method_name, bool all) { goto err; } - for (size_t count = 0; count < max_count; ++count) { - fprintf(fh, "count = %zu\n", count); + for (int count = 0; count < max_count; ++count) { + fprintf(fh, "count = %d\n", count); OQS_randombytes(seed, 48); - fprintBstr(fh, "seed = ", seed, 48); + OQS_fprintBstr(fh, "seed = ", seed, 48); msg_len = 33 * (count + 1); fprintf(fh, "mlen = %zu\n", msg_len); OQS_randombytes(msg, msg_len); - fprintBstr(fh, "msg = ", msg, msg_len); + OQS_fprintBstr(fh, "msg = ", msg, msg_len); - OQS_randombytes_nist_kat_save_state(); - OQS_randombytes_nist_kat_init_256bit(seed, NULL); + OQS_KAT_PRNG_save_state(prng); + OQS_KAT_PRNG_seed(prng, seed, NULL); rc = OQS_SIG_keypair(sig, public_key, secret_key); if (rc != OQS_SUCCESS) { fprintf(stderr, "[kat_sig] %s ERROR: OQS_SIG_keypair failed!\n", method_name); goto err; } - fprintBstr(fh, "pk = ", public_key, sig->length_public_key); - fprintBstr(fh, "sk = ", secret_key, sig->length_secret_key); + OQS_fprintBstr(fh, "pk = ", public_key, sig->length_public_key); + OQS_fprintBstr(fh, "sk = ", secret_key, sig->length_secret_key); rc = OQS_SIG_sign(sig, signature, &signature_len, msg, msg_len, secret_key); if (rc != OQS_SUCCESS) { @@ -326,7 +311,7 @@ OQS_STATUS sig_kat(const char *method_name, bool all) { goto err; } fprintf(fh, "smlen = %zu\n", signed_msg_len); - fprintBstr(fh, "sm = ", signed_msg, signed_msg_len); + OQS_fprintBstr(fh, "sm = ", signed_msg, signed_msg_len); OQS_MEM_secure_free(signed_msg, signed_msg_len); @@ -341,7 +326,7 @@ OQS_STATUS sig_kat(const char *method_name, bool all) { goto err; } - OQS_randombytes_nist_kat_restore_state(); + OQS_KAT_PRNG_restore_state(prng); } ret = OQS_SUCCESS; @@ -362,6 +347,7 @@ OQS_STATUS sig_kat(const char *method_name, bool all) { OQS_MEM_insecure_free(signature); OQS_MEM_insecure_free(msg); OQS_SIG_free(sig); + OQS_KAT_PRNG_free(prng); return ret; } diff --git a/tests/test_helpers.c b/tests/test_helpers.c new file mode 100644 index 0000000000..291fd87e55 --- /dev/null +++ b/tests/test_helpers.c @@ -0,0 +1,163 @@ +#include + +#include "test_helpers.h" +#include + +#define HQC_PRNG_DOMAIN 1 + +/* HQC PRNG implementation */ + +// State for HQC PRNG. Analogue of DRBG_ctx in rand/rand_nist.c +static OQS_SHA3_shake256_inc_ctx hqc_prng_state = { NULL }; + +// Allocate the state. +static void hqc_prng_new(void) { + OQS_SHA3_shake256_inc_init(&hqc_prng_state); +} + +// entropy_input must have length 48. +// If personalization_string is non-null, its length must also be 48. +static void hqc_prng_seed(const uint8_t *entropy_input, const uint8_t *personalization_string) { + uint8_t domain = HQC_PRNG_DOMAIN; + // reset state + OQS_SHA3_shake256_inc_ctx_reset(&hqc_prng_state); + OQS_SHA3_shake256_inc_absorb(&hqc_prng_state, entropy_input, 48); + if (personalization_string != NULL) { + OQS_SHA3_shake256_inc_absorb(&hqc_prng_state, personalization_string, 48); + } + OQS_SHA3_shake256_inc_absorb(&hqc_prng_state, &domain, 1); + OQS_SHA3_shake256_inc_finalize(&hqc_prng_state); +} + +// random_array must have length bytes_to_read. +static void hqc_prng_randombytes(uint8_t *random_array, size_t bytes_to_read) { + OQS_SHA3_shake256_inc_squeeze(random_array, bytes_to_read, &hqc_prng_state); +} + +static void hqc_prng_get_state(void *out) { + OQS_SHA3_shake256_inc_ctx_clone((OQS_SHA3_shake256_inc_ctx *)out, &hqc_prng_state); +} + +static void hqc_prng_set_state(const void *in) { + OQS_SHA3_shake256_inc_ctx_clone(&hqc_prng_state, (OQS_SHA3_shake256_inc_ctx *)in); +} + +static void hqc_prng_free(void *saved_state) { + OQS_SHA3_shake256_inc_ctx *hqc_saved_state = (OQS_SHA3_shake256_inc_ctx *)saved_state; + if (hqc_saved_state != NULL) { + OQS_SHA3_shake256_inc_ctx_release(hqc_saved_state); + } + if (hqc_prng_state.ctx != NULL) { + OQS_SHA3_shake256_inc_ctx_release(&hqc_prng_state); + hqc_prng_state.ctx = NULL; + } +} + +/* Additional NIST DRBG implementation */ +static void nist_drbg_free(void *saved_state) {} + +/* Helpers for identifying algorithms */ +static int is_mceliece(const char *method_name) { + return ( !strcmp(method_name, OQS_KEM_alg_classic_mceliece_348864) + || !strcmp(method_name, OQS_KEM_alg_classic_mceliece_348864f) + || !strcmp(method_name, OQS_KEM_alg_classic_mceliece_460896) + || !strcmp(method_name, OQS_KEM_alg_classic_mceliece_460896f) + || !strcmp(method_name, OQS_KEM_alg_classic_mceliece_6688128) + || !strcmp(method_name, OQS_KEM_alg_classic_mceliece_6688128f) + || !strcmp(method_name, OQS_KEM_alg_classic_mceliece_6960119) + || !strcmp(method_name, OQS_KEM_alg_classic_mceliece_6960119f) + || !strcmp(method_name, OQS_KEM_alg_classic_mceliece_8192128) + || !strcmp(method_name, OQS_KEM_alg_classic_mceliece_8192128f) ); +} + +static int is_hqc(const char *method_name) { + return (0 == strcmp(method_name, OQS_KEM_alg_hqc_128)) + || (0 == strcmp(method_name, OQS_KEM_alg_hqc_192)) + || (0 == strcmp(method_name, OQS_KEM_alg_hqc_256)); +} + +/* OQS_KAT_PRNG interface implementation */ + +OQS_KAT_PRNG *OQS_KAT_PRNG_new(const char *method_name) { + OQS_KAT_PRNG *prng = malloc(sizeof(OQS_KAT_PRNG)); + if (prng != NULL) { + prng->max_kats = is_mceliece(method_name) ? 10 : 100; + if (is_hqc(method_name)) { + // set randombytes function + OQS_randombytes_custom_algorithm(&hqc_prng_randombytes); + // reset the PRNG + hqc_prng_new(); + // initialize saved state + OQS_SHA3_shake256_inc_init(&prng->saved_state.hqc_state); + // TODO set callbacks + prng->seed = &hqc_prng_seed; + prng->get_state = &hqc_prng_get_state; + prng->set_state = &hqc_prng_set_state; + prng->free = &hqc_prng_free; + } else { + // set randombytes function + if (OQS_randombytes_switch_algorithm(OQS_RAND_alg_nist_kat) == OQS_SUCCESS) { + // TODO set callbacks + prng->seed = &OQS_randombytes_nist_kat_init_256bit; + prng->get_state = &OQS_randombytes_nist_kat_get_state; + prng->set_state = &OQS_randombytes_nist_kat_set_state; + prng->free = &nist_drbg_free; + } else { + OQS_MEM_insecure_free(prng); + prng = NULL; + } + } + } + return prng; +} + +// entropy_input must have length 48. +// If personalization_string is non-null, its length must also be 48. +void OQS_KAT_PRNG_seed(OQS_KAT_PRNG *prng, const uint8_t *entropy_input, const uint8_t *personalization_string) { + if (prng != NULL) { + prng->seed(entropy_input, personalization_string); + } +} + +void OQS_KAT_PRNG_save_state(OQS_KAT_PRNG *prng) { + if (prng != NULL) { + prng->get_state(&prng->saved_state); + } +} + +void OQS_KAT_PRNG_restore_state(OQS_KAT_PRNG *prng) { + if (prng != NULL) { + prng->set_state(&prng->saved_state); + } +} + +void OQS_KAT_PRNG_free(OQS_KAT_PRNG *prng) { + if (prng != NULL) { + // saved_state needs to be handled dynamically + prng->free(&prng->saved_state); + } + OQS_MEM_insecure_free(prng); +} + + +/* Displays hexadecimal strings */ +void OQS_print_hex_string(const char *label, const uint8_t *str, size_t len) { + printf("%-20s (%4zu bytes): ", label, len); + for (size_t i = 0; i < (len); i++) { + printf("%02X", str[i]); + } + printf("\n"); +} + +void OQS_fprintBstr(FILE *fp, const char *S, const uint8_t *A, size_t L) { + size_t i; + fprintf(fp, "%s", S); + for (i = 0; i < L; i++) { + fprintf(fp, "%02X", A[i]); + } + if (L == 0) { + fprintf(fp, "00"); + } + fprintf(fp, "\n"); +} + diff --git a/tests/test_helpers.h b/tests/test_helpers.h new file mode 100644 index 0000000000..cd34f696be --- /dev/null +++ b/tests/test_helpers.h @@ -0,0 +1,44 @@ +#ifndef OQS_TEST_HELPERS_H +#define OQS_TEST_HELPERS_H + +#include +#include +#include + +#include + +typedef union { + OQS_SHA3_shake256_inc_ctx hqc_state; + // struct definition copied from rand_nist.c + struct { + unsigned char Key[32]; + unsigned char V[16]; + int reseed_counter; + } nist_state; +} OQS_KAT_PRNG_state; + +typedef struct { + int max_kats; + OQS_KAT_PRNG_state saved_state; + // The caller should use the OQS_KAT_PRNG_* functions instead of these callbacks. + void (*seed)(const uint8_t *, const uint8_t *); + void (*get_state)(void *); + void (*set_state)(const void *); + void (*free)(void *); +} OQS_KAT_PRNG; + +OQS_KAT_PRNG *OQS_KAT_PRNG_new(const char *method_name); + +void OQS_KAT_PRNG_seed(OQS_KAT_PRNG *prng, const uint8_t *seed, const uint8_t *personalization_string); + +void OQS_KAT_PRNG_save_state(OQS_KAT_PRNG *prng); + +void OQS_KAT_PRNG_restore_state(OQS_KAT_PRNG *prng); + +void OQS_KAT_PRNG_free(OQS_KAT_PRNG *prng); + +void OQS_print_hex_string(const char *label, const uint8_t *str, size_t len); + +void OQS_fprintBstr(FILE *fp, const char *S, const uint8_t *A, size_t L); + +#endif