Skip to content

Commit

Permalink
All KATs passing with new PRNG abstraction
Browse files Browse the repository at this point in the history
  • Loading branch information
SWilson4 committed Jan 19, 2024
1 parent c98b099 commit a0c9c39
Show file tree
Hide file tree
Showing 7 changed files with 270 additions and 206 deletions.
25 changes: 15 additions & 10 deletions src/common/rand/rand_nist.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 <assert.h>
Expand All @@ -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
Expand Down Expand Up @@ -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) {
Expand Down
10 changes: 4 additions & 6 deletions src/common/rand/rand_nist.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
6 changes: 3 additions & 3 deletions tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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})
Expand Down
170 changes: 19 additions & 151 deletions tests/kat_kem.c
Original file line number Diff line number Diff line change
Expand Up @@ -16,141 +16,9 @@
#include <oqs/rand_nist.h>
#include <oqs/sha3.h>

#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) {

Expand All @@ -166,24 +34,24 @@ 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) {
printf("[kem_kat] %s was not enabled at compile-time.\n", method_name);
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;

Expand All @@ -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) {
Expand All @@ -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;
Expand All @@ -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;
}

Expand Down
Loading

0 comments on commit a0c9c39

Please sign in to comment.