From b1838090ad769162b2ea08f33254c67d084bb22f Mon Sep 17 00:00:00 2001 From: tb <> Date: Fri, 20 Dec 2024 00:07:12 +0000 Subject: Rework and fix the mlkem tests Make proper use of CBB and CBS. If a CBS ever owns data, you're holding it wrong. Ditch gross macros, sscanf, and globals. The use of fgets is annoying here, so replace it with getline, which be provided by portable if needed. Most importantly, make the tests actually signal failure rather than only printing an error. Fix the state machines in a few of them. Some tests didn't parse the .txt file at all. Others mostly did but didn't actually test what they were supposed to be testing. Such failures were hidden by the way the tests were written. This basically needed a complete revamp. It still isn't pretty and much of it could be deduplicated, but I only have so much time alotted on this blue planet. --- .../lib/libcrypto/mlkem/mlkem768_decap_tests.c | 201 ++++++++++++++------- 1 file changed, 134 insertions(+), 67 deletions(-) (limited to 'src/regress/lib/libcrypto/mlkem/mlkem768_decap_tests.c') diff --git a/src/regress/lib/libcrypto/mlkem/mlkem768_decap_tests.c b/src/regress/lib/libcrypto/mlkem/mlkem768_decap_tests.c index 96dc435c4d..a88e487494 100644 --- a/src/regress/lib/libcrypto/mlkem/mlkem768_decap_tests.c +++ b/src/regress/lib/libcrypto/mlkem/mlkem768_decap_tests.c @@ -1,7 +1,8 @@ -/* $OpenBSD: mlkem768_decap_tests.c,v 1.2 2024/12/14 19:16:24 tb Exp $ */ +/* $OpenBSD: mlkem768_decap_tests.c,v 1.3 2024/12/20 00:07:12 tb Exp $ */ /* - * Copyright (c) 2024, Google Inc. - * Copyright (c) 2024, Bob Beck + * Copyright (c) 2024 Google Inc. + * Copyright (c) 2024 Bob Beck + * Copyright (c) 2024 Theo Buehler * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -16,113 +17,179 @@ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include +#include #include #include #include -#include -#include -#include +#include "bytestring.h" +#include "mlkem.h" #include "mlkem_tests_util.h" -static void -MlkemDecapFileTest(CBS *c, CBS *k, CBS *dk, int should_fail) +static int +MlkemDecapFileTest(CBB *ciphertext_cbb, CBB *shared_secret_cbb, + CBB *private_key_cbb, int should_fail, size_t line) { - uint8_t shared_secret[MLKEM_SHARED_SECRET_BYTES]; struct MLKEM768_private_key priv; - int parse_ok, decap_ok; + uint8_t *ciphertext = NULL, *shared_secret = NULL, *private_key = NULL; + size_t ciphertext_len = 0, shared_secret_len = 0, private_key_len = 0; + uint8_t shared_secret_buf[MLKEM_SHARED_SECRET_BYTES]; + CBS private_key_cbs; + int failed = 1; - parse_ok = MLKEM768_parse_private_key(&priv, dk); - if (!parse_ok) { - TEST(!should_fail, "parse_private_key"); - return; + if (!CBB_finish(ciphertext_cbb, &ciphertext, &ciphertext_len)) + goto err; + if (!CBB_finish(shared_secret_cbb, &shared_secret, &shared_secret_len)) + goto err; + if (!CBB_finish(private_key_cbb, &private_key, &private_key_len)) + goto err; + + CBS_init(&private_key_cbs, private_key, private_key_len); + + if (!MLKEM768_parse_private_key(&priv, &private_key_cbs)) { + if ((failed = !should_fail)) + warnx("#%zu: parse_private_key", line); + goto err; + } + if (!MLKEM768_decap(shared_secret_buf, ciphertext, ciphertext_len, + &priv)) { + if ((failed = !should_fail)) + warnx("#%zu: decap", line); + goto err; } - decap_ok = MLKEM768_decap(shared_secret, CBS_data(c), CBS_len(c), - &priv); - if (!decap_ok) { - TEST(!should_fail, "decap"); - return; + + failed = compare_data(shared_secret, shared_secret_buf, + MLKEM_SHARED_SECRET_BYTES, line, "shared_secret"); + + if (should_fail != failed) { + warnx("FAIL: #%zu: should_fail %d, failed %d", + line, should_fail, failed); + failed = 1; } - TEST_DATAEQ(shared_secret, CBS_data(k), - MLKEM_SHARED_SECRET_BYTES, "shared_secret"); + + err: + CBB_cleanup(ciphertext_cbb); + CBB_cleanup(shared_secret_cbb); + CBB_cleanup(private_key_cbb); + freezero(ciphertext, ciphertext_len); + freezero(shared_secret, shared_secret_len); + freezero(private_key, private_key_len); + + return failed; } -#define S_START 0 -#define S_COMMENT 1 -#define S_PRIVATE_KEY 2 -#define S_CIPHERTEXT 3 -#define S_RESULT 4 -#define S_SHARED_SECRET 5 +#define S_START 0 +#define S_COMMENT 1 +#define S_PRIVATE_KEY 2 +#define S_CIPHERTEXT 3 +#define S_RESULT 4 +#define S_SHARED_SECRET 5 + +#define S2S(x) case x: return #x + +static const char * +state2str(int state) +{ + switch (state) { + S2S(S_START); + S2S(S_COMMENT); + S2S(S_PRIVATE_KEY); + S2S(S_CIPHERTEXT); + S2S(S_RESULT); + S2S(S_SHARED_SECRET); + default: + errx(1, "unknown state %d", state); + } +} int main(int argc, char **argv) { - CBS ciphertext, shared_secret, private_key; - const uint8_t *p = NULL; + CBB ciphertext = { 0 }, shared_secret = { 0 }, private_key = { 0 }; int should_fail = 0; - char *buf; + const char *test; + size_t line = 0; + char *buf = NULL; + size_t buflen = 0; + ssize_t len; FILE *fp; int state; + int failed = 0; + + if (argc < 2) + errx(1, "%s: missing test file", argv[0]); + + test = argv[1]; + + if ((fp = fopen(test, "r")) == NULL) + err(1, "cant't open test file"); - fprintf(stderr, "Testing decap test vectors in %s\n", argv[1]); - TEST((fp = fopen(argv[1], "r")) == NULL, "can't open test file"); - MALLOC(buf, 16*1024); state = S_COMMENT; - test_number = 1; - while (fgets(buf, 16*1024, fp) != NULL) { + line = 0; + + while ((len = getline(&buf, &buflen, fp)) != -1) { + const char *msg = state2str(state); + CBS cbs; + uint8_t u8; + + line++; + CBS_init(&cbs, buf, len); + + if (!CBS_get_last_u8(&cbs, &u8)) + errx(1, "#%zu %s: CBB_get_last_u8", line, msg); + assert(u8 == '\n'); + switch (state) { case S_START: - if (strcmp(buf, "\n") != 0) - break; state = S_COMMENT; break; case S_COMMENT: - if (strncmp(buf, "#", 1) != 0) - break; + if (!CBS_get_u8(&cbs, &u8)) + errx(1, "#%zu %s: CBB_get_u8", line, msg); + assert(u8 == '#'); + if (!CBS_skip(&cbs, CBS_len(&cbs))) + errx(1, "#%zu %s: CBB_skip", line, msg); state = S_PRIVATE_KEY; break; case S_PRIVATE_KEY: - if (strncmp(buf, "private_key: ", - strlen("private_key: ")) != 0) - break; - grab_data(&private_key, buf, strlen("private_key: ")); - p = CBS_data(&private_key); + if (!get_string_cbs(&cbs, "private_key: ", line, msg)) + errx(1, "#%zu %s: get_string_cbs", line, msg); + hex_decode_cbs(&cbs, &private_key, line, msg); state = S_CIPHERTEXT; break; case S_CIPHERTEXT: - if (strncmp(buf, "ciphertext: ", - strlen("ciphertext: ")) != 0) - break; - grab_data(&ciphertext, buf, strlen("ciphertext: ")); + if (!get_string_cbs(&cbs, "ciphertext: ", line, msg)) + errx(1, "#%zu %s: get_string_cbs", line, msg); + hex_decode_cbs(&cbs, &ciphertext, line, msg); state = S_RESULT; break; case S_RESULT: - if (strncmp(buf, "result: pass", - strlen("result: pass")) != 0) - should_fail = 1; - else - should_fail = 0; + if (!get_string_cbs(&cbs, "result: ", line, msg)) + errx(1, "#%zu %s: get_string_cbs", line, msg); + should_fail = get_string_cbs(&cbs, "fail", line, msg); state = S_SHARED_SECRET; break; case S_SHARED_SECRET: - if (strncmp(buf, "shared_secret: ", - strlen("shared_secret: ")) != 0) - break; - grab_data(&shared_secret, buf, - strlen("shared_secret: ")); - MlkemDecapFileTest(&ciphertext, &shared_secret, - &private_key, should_fail); - free((void *)CBS_data(&ciphertext)); - free((void *)CBS_data(&shared_secret)); - free((void *)p); - - test_number++; + if (!get_string_cbs(&cbs, "shared_secret: ", line, msg)) + errx(1, "#%zu %s: get_string_cbs", line, msg); + hex_decode_cbs(&cbs, &shared_secret, line, msg); + + failed |= MlkemDecapFileTest(&ciphertext, &shared_secret, + &private_key, should_fail, line); + state = S_START; break; } + if (CBS_len(&cbs) > 0) + errx(1, "#%zu %s: CBS_len", line, msg); } - free(buf); - exit(failure); + + if (ferror(fp)) + err(1, NULL); + fclose(fp); + + return failed; } -- cgit v1.2.3-55-g6feb