mirror of
https://github.com/openbsd/src.git
synced 2024-12-22 07:27:59 -08:00
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.
This commit is contained in:
parent
58f37af48f
commit
8889493e35
@ -1,4 +1,4 @@
|
||||
# $OpenBSD: Makefile,v 1.4 2024/12/19 23:45:09 tb Exp $
|
||||
# $OpenBSD: Makefile,v 1.5 2024/12/20 00:07:12 tb Exp $
|
||||
|
||||
PROGS += mlkem_unittest
|
||||
PROGS += mlkem768_nist_keygen_tests
|
||||
@ -26,10 +26,12 @@ run-$p: $p
|
||||
LDADD = ${CRYPTO_INT}
|
||||
DPADD = ${LIBCRYPTO}
|
||||
|
||||
CFLAGS += -DLIBRESSL_INTERNAL -Wall
|
||||
CFLAGS += -DLIBRESSL_INTERNAL -Wall -Werror
|
||||
CFLAGS += -I${.CURDIR}/../../../../lib/libcrypto/bytestring
|
||||
CFLAGS += -I${.CURDIR}/../../../../lib/libcrypto/mlkem
|
||||
CFLAGS += -I${.CURDIR}/../../../../lib/libcrypto/sha
|
||||
CFLAGS += -DLIBRESSL_INTERNAL
|
||||
|
||||
WARNINS = Yes
|
||||
|
||||
.include <bsd.regress.mk>
|
||||
|
@ -1,7 +1,8 @@
|
||||
/* $OpenBSD: mlkem1024_decap_tests.c,v 1.2 2024/12/14 19:16:24 tb Exp $ */
|
||||
/* $OpenBSD: mlkem1024_decap_tests.c,v 1.3 2024/12/20 00:07:12 tb Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2024, Google Inc.
|
||||
* Copyright (c) 2024, Bob Beck <beck@obtuse.com>
|
||||
* Copyright (c) 2024 Google Inc.
|
||||
* Copyright (c) 2024 Bob Beck <beck@obtuse.com>
|
||||
* Copyright (c) 2024 Theo Buehler <tb@openbsd.org>
|
||||
*
|
||||
* 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 <assert.h>
|
||||
#include <err.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <openssl/bytestring.h>
|
||||
#include <openssl/mlkem.h>
|
||||
#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 MLKEM1024_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 = MLKEM1024_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 (!MLKEM1024_parse_private_key(&priv, &private_key_cbs)) {
|
||||
if ((failed = !should_fail))
|
||||
warnx("#%zu: parse_private_key", line);
|
||||
goto err;
|
||||
}
|
||||
decap_ok = MLKEM1024_decap(shared_secret, CBS_data(c), CBS_len(c),
|
||||
&priv);
|
||||
if (!decap_ok) {
|
||||
TEST(!should_fail, "decap");
|
||||
return;
|
||||
if (!MLKEM1024_decap(shared_secret_buf, ciphertext, ciphertext_len,
|
||||
&priv)) {
|
||||
if ((failed = !should_fail))
|
||||
warnx("#%zu: decap", line);
|
||||
goto err;
|
||||
}
|
||||
TEST_DATAEQ(shared_secret, CBS_data(k),
|
||||
MLKEM_SHARED_SECRET_BYTES, "shared_secret");
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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);
|
||||
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);
|
||||
|
||||
test_number++;
|
||||
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;
|
||||
}
|
||||
|
@ -1,7 +1,8 @@
|
||||
/* $OpenBSD: mlkem1024_encap_tests.c,v 1.2 2024/12/14 19:16:24 tb Exp $ */
|
||||
/* $OpenBSD: mlkem1024_encap_tests.c,v 1.3 2024/12/20 00:07:12 tb Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2024, Google Inc.
|
||||
* Copyright (c) 2024, Bob Beck <beck@obtuse.com>
|
||||
* Copyright (c) 2024 Google Inc.
|
||||
* Copyright (c) 2024 Bob Beck <beck@obtuse.com>
|
||||
* Copyright (c) 2024 Theo Buehler <tb@openbsd.org>
|
||||
*
|
||||
* 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,120 +17,194 @@
|
||||
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <err.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <openssl/bytestring.h>
|
||||
#include <openssl/mlkem.h>
|
||||
#include "bytestring.h"
|
||||
#include "mlkem.h"
|
||||
|
||||
#include "mlkem_internal.h"
|
||||
#include "mlkem_tests_util.h"
|
||||
|
||||
static void
|
||||
MlkemEncapFileTest(CBS *entropy, CBS *public_key, CBS *expected_ciphertext,
|
||||
CBS *expected_shared_secret, int should_fail)
|
||||
static int
|
||||
MlkemEncapFileTest(CBB *entropy_cbb, CBB *pubkey_cbb, CBB *ciphertext_cbb,
|
||||
CBB *shared_secret_cbb, int should_fail, size_t line)
|
||||
{
|
||||
uint8_t shared_secret[MLKEM_SHARED_SECRET_BYTES];
|
||||
uint8_t ciphertext[MLKEM1024_CIPHERTEXT_BYTES];
|
||||
struct MLKEM1024_public_key pub;
|
||||
int parse_ok;
|
||||
uint8_t *entropy = NULL, *public_key = NULL, *ciphertext = NULL;
|
||||
uint8_t *shared_secret = NULL;
|
||||
size_t entropy_len = 0, public_key_len = 0, ciphertext_len = 0;
|
||||
size_t shared_secret_len = 0;
|
||||
uint8_t shared_secret_buf[MLKEM_SHARED_SECRET_BYTES];
|
||||
uint8_t ciphertext_buf[MLKEM1024_CIPHERTEXT_BYTES];
|
||||
CBS public_key_cbs;
|
||||
int failed = 1;
|
||||
|
||||
parse_ok = MLKEM1024_parse_public_key(&pub, public_key);
|
||||
if (!parse_ok) {
|
||||
TEST(!should_fail, "parse_public_key");
|
||||
return;
|
||||
if (!CBB_finish(entropy_cbb, &entropy, &entropy_len))
|
||||
goto err;
|
||||
if (!CBB_finish(pubkey_cbb, &public_key, &public_key_len))
|
||||
goto err;
|
||||
if (!CBB_finish(ciphertext_cbb, &ciphertext, &ciphertext_len))
|
||||
goto err;
|
||||
if (!CBB_finish(shared_secret_cbb, &shared_secret, &shared_secret_len))
|
||||
goto err;
|
||||
|
||||
CBS_init(&public_key_cbs, public_key, public_key_len);
|
||||
|
||||
if (!MLKEM1024_parse_public_key(&pub, &public_key_cbs)) {
|
||||
if ((failed = !should_fail))
|
||||
warnx("#%zu: parse_public_key", line);
|
||||
goto err;
|
||||
}
|
||||
MLKEM1024_encap(ciphertext, shared_secret, &pub);
|
||||
TEST_DATAEQ(shared_secret, CBS_data(expected_shared_secret),
|
||||
MLKEM_SHARED_SECRET_BYTES, "shared_secret");
|
||||
TEST_DATAEQ(ciphertext, CBS_data(expected_ciphertext),
|
||||
MLKEM1024_CIPHERTEXT_BYTES, "shared_secret");
|
||||
MLKEM1024_encap_external_entropy(ciphertext_buf, shared_secret_buf,
|
||||
&pub, entropy);
|
||||
|
||||
failed = compare_data(shared_secret, shared_secret_buf,
|
||||
MLKEM_SHARED_SECRET_BYTES, line, "shared_secret");
|
||||
failed |= compare_data(ciphertext, ciphertext_buf,
|
||||
MLKEM1024_CIPHERTEXT_BYTES, line, "ciphertext");
|
||||
|
||||
if (should_fail != failed) {
|
||||
warnx("FAIL: #%zu: should_fail %d, failed %d",
|
||||
line, should_fail, failed);
|
||||
failed = 1;
|
||||
}
|
||||
|
||||
err:
|
||||
CBB_cleanup(entropy_cbb);
|
||||
CBB_cleanup(pubkey_cbb);
|
||||
CBB_cleanup(ciphertext_cbb);
|
||||
CBB_cleanup(shared_secret_cbb);
|
||||
freezero(entropy, entropy_len);
|
||||
freezero(public_key, public_key_len);
|
||||
freezero(ciphertext, ciphertext_len);
|
||||
freezero(shared_secret, shared_secret_len);
|
||||
|
||||
return failed;
|
||||
}
|
||||
|
||||
#define S_START 0
|
||||
#define S_COMMENT 1
|
||||
#define S_ENTROPY 2
|
||||
#define S_PUBLIC_KEY 3
|
||||
#define S_RESULT 4
|
||||
#define S_CIPHERTEXT 5
|
||||
#define S_SHARED_SECRET 6
|
||||
#define S_START 0
|
||||
#define S_COMMENT 1
|
||||
#define S_ENTROPY 2
|
||||
#define S_PUBLIC_KEY 3
|
||||
#define S_RESULT 4
|
||||
#define S_CIPHERTEXT 5
|
||||
#define S_SHARED_SECRET 6
|
||||
|
||||
#define S2S(x) case x: return #x
|
||||
|
||||
static const char *
|
||||
state2str(int state)
|
||||
{
|
||||
switch (state) {
|
||||
S2S(S_START);
|
||||
S2S(S_COMMENT);
|
||||
S2S(S_ENTROPY);
|
||||
S2S(S_PUBLIC_KEY);
|
||||
S2S(S_RESULT);
|
||||
S2S(S_CIPHERTEXT);
|
||||
S2S(S_SHARED_SECRET);
|
||||
default:
|
||||
errx(1, "unknown state %d", state);
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
CBS entropy, public_key, ciphertext, shared_secret;
|
||||
const uint8_t *p = NULL;
|
||||
CBB entropy = { 0 }, public_key = { 0 }, ciphertext = { 0 }, shared_secret = { 0 };
|
||||
int should_fail = 0;
|
||||
char *buf;
|
||||
const char *test;
|
||||
size_t line;
|
||||
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];
|
||||
line = 0;
|
||||
|
||||
if ((fp = fopen(test, "r")) == NULL)
|
||||
err(1, "cant't open test file");
|
||||
|
||||
fprintf(stderr, "Testing encap 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_ENTROPY;
|
||||
break;
|
||||
case S_ENTROPY:
|
||||
if (strncmp(buf, "entropy: ", strlen("entropy: ")) != 0)
|
||||
break;
|
||||
grab_data(&entropy, buf, strlen("entropy: "));
|
||||
p = CBS_data(&entropy);
|
||||
if (!get_string_cbs(&cbs, "entropy: ", line, msg))
|
||||
errx(1, "#%zu %s: get_string_cbs", line, msg);
|
||||
hex_decode_cbs(&cbs, &entropy, line, msg);
|
||||
state = S_PUBLIC_KEY;
|
||||
break;
|
||||
case S_PUBLIC_KEY:
|
||||
if (strncmp(buf, "public_key: ",
|
||||
strlen("public_key: ")) != 0)
|
||||
break;
|
||||
grab_data(&public_key, buf, strlen("public_key: "));
|
||||
p = CBS_data(&public_key);
|
||||
if (!get_string_cbs(&cbs, "public_key = ", line, msg))
|
||||
errx(1, "#%zu %s: get_string_cbs", line, msg);
|
||||
hex_decode_cbs(&cbs, &public_key, 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_CIPHERTEXT;
|
||||
break;
|
||||
case S_CIPHERTEXT:
|
||||
if (strncmp(buf, "ciphertext: ",
|
||||
strlen("ciphertext: ")) != 0)
|
||||
break;
|
||||
grab_data(&ciphertext, buf, strlen("ciphertext: "));
|
||||
state = S_RESULT;
|
||||
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_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: "));
|
||||
MlkemEncapFileTest(&entropy, &public_key, &ciphertext,
|
||||
&shared_secret, should_fail);
|
||||
free((void *)CBS_data(&ciphertext));
|
||||
free((void *)CBS_data(&shared_secret));
|
||||
free((void *)p);
|
||||
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 |= MlkemEncapFileTest(&entropy, &public_key,
|
||||
&ciphertext, &shared_secret, should_fail, line);
|
||||
|
||||
test_number++;
|
||||
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;
|
||||
}
|
||||
|
@ -1,7 +1,8 @@
|
||||
/* $OpenBSD: mlkem1024_iteration_test.c,v 1.2 2024/12/14 19:16:24 tb Exp $ */
|
||||
/* $OpenBSD: mlkem1024_iteration_test.c,v 1.3 2024/12/20 00:07:12 tb Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2024, Google Inc.
|
||||
* Copyright (c) 2024, Bob Beck <beck@obtuse.com>
|
||||
* Copyright (c) 2024 Google Inc.
|
||||
* Copyright (c) 2024 Bob Beck <beck@obtuse.com>
|
||||
* Copyright (c) 2024 Theo Buehler <tb@openbsd.org>
|
||||
*
|
||||
* 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,32 +17,17 @@
|
||||
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <err.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <openssl/bytestring.h>
|
||||
#include <openssl/mlkem.h>
|
||||
#include "mlkem.h"
|
||||
|
||||
#include "mlkem_internal.h"
|
||||
#include "mlkem_tests_util.h"
|
||||
#include "sha3_internal.h"
|
||||
|
||||
static int
|
||||
encode_private_key(const struct MLKEM1024_private_key *priv, uint8_t **out_buf,
|
||||
size_t *out_len)
|
||||
{
|
||||
CBB cbb;
|
||||
if (!CBB_init(&cbb, MLKEM1024_PUBLIC_KEY_BYTES))
|
||||
return 0;
|
||||
if (!MLKEM1024_marshal_private_key(&cbb, priv))
|
||||
return 0;
|
||||
if (!CBB_finish(&cbb, out_buf, out_len))
|
||||
return 0;
|
||||
CBB_cleanup(&cbb);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* The structure of this test is taken from
|
||||
* https://github.com/C2SP/CCTV/blob/main/ML-KEM/README.md?ref=words.filippo.io#accumulated-pq-crystals-vectors
|
||||
@ -52,8 +38,8 @@ encode_private_key(const struct MLKEM1024_private_key *priv, uint8_t **out_buf,
|
||||
* (The RNG stream starts with 7f9c2ba4e88f827d616045507605853e.)
|
||||
*/
|
||||
|
||||
static void
|
||||
MlkemIterativeTest()
|
||||
static int
|
||||
MlkemIterativeTest(void)
|
||||
{
|
||||
/* https://github.com/C2SP/CCTV/tree/main/ML-KEM */
|
||||
/*
|
||||
@ -101,8 +87,9 @@ MlkemIterativeTest()
|
||||
*/
|
||||
shake_out(&drng, seed, sizeof(seed));
|
||||
if (i == 0) {
|
||||
TEST_DATAEQ(seed, kExpectedSeedStart,
|
||||
sizeof(kExpectedSeedStart), "seed start");
|
||||
if (compare_data(seed, kExpectedSeedStart,
|
||||
sizeof(kExpectedSeedStart), 0, "seed start") != 0)
|
||||
errx(1, "compare_data");
|
||||
}
|
||||
|
||||
/* generate ek as encoded_public_key */
|
||||
@ -115,8 +102,9 @@ MlkemIterativeTest()
|
||||
sizeof(encoded_public_key));
|
||||
|
||||
/* marshal priv to dk as encoded_private_key */
|
||||
TEST(!encode_private_key(&priv, &encoded_private_key,
|
||||
&encoded_private_key_len), "encode_private_key");
|
||||
if (!mlkem1024_encode_private_key(&priv, &encoded_private_key,
|
||||
&encoded_private_key_len))
|
||||
errx(1, "mlkem1024_encode_private_key");
|
||||
|
||||
/* hash in dk */
|
||||
shake_update(&results, encoded_private_key,
|
||||
@ -141,21 +129,21 @@ MlkemIterativeTest()
|
||||
sizeof(invalid_ciphertext));
|
||||
|
||||
/* generte k as shared secret from invalid ciphertext */
|
||||
TEST(!MLKEM1024_decap(shared_secret, invalid_ciphertext,
|
||||
sizeof(invalid_ciphertext), &priv), "decap failed!");
|
||||
if (!MLKEM1024_decap(shared_secret, invalid_ciphertext,
|
||||
sizeof(invalid_ciphertext), &priv))
|
||||
errx(1, "decap failed");
|
||||
|
||||
/* hash in k */
|
||||
shake_update(&results, shared_secret, sizeof(shared_secret));
|
||||
}
|
||||
shake_xof(&results);
|
||||
shake_out(&results, out, 32);
|
||||
shake_out(&results, out, sizeof(out));
|
||||
|
||||
TEST_DATAEQ(out, kExpectedAdam, 32, "final result hash");
|
||||
return compare_data(kExpectedAdam, out, sizeof(out), i, "final result hash");
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
MlkemIterativeTest();
|
||||
exit(failure);
|
||||
return MlkemIterativeTest();
|
||||
}
|
||||
|
@ -1,7 +1,8 @@
|
||||
/* $OpenBSD: mlkem1024_keygen_tests.c,v 1.4 2024/12/17 07:20:10 tb Exp $ */
|
||||
/* $OpenBSD: mlkem1024_keygen_tests.c,v 1.5 2024/12/20 00:07:12 tb Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2024, Google Inc.
|
||||
* Copyright (c) 2024, Bob Beck <beck@obtuse.com>
|
||||
* Copyright (c) 2024 Google Inc.
|
||||
* Copyright (c) 2024 Bob Beck <beck@obtuse.com>
|
||||
* Copyright (c) 2024 Theo Buehler <tb@openbsd.org>
|
||||
*
|
||||
* 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,115 +17,174 @@
|
||||
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <err.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <openssl/bytestring.h>
|
||||
#include <openssl/mlkem.h>
|
||||
#include "bytestring.h"
|
||||
#include "mlkem.h"
|
||||
|
||||
#include "mlkem_internal.h"
|
||||
#include "mlkem_tests_util.h"
|
||||
|
||||
static int
|
||||
encode_private_key(const struct MLKEM1024_private_key *priv, uint8_t **out_buf,
|
||||
size_t *out_len)
|
||||
{
|
||||
CBB cbb;
|
||||
if (!CBB_init(&cbb, MLKEM1024_PUBLIC_KEY_BYTES))
|
||||
return 0;
|
||||
if (!MLKEM1024_marshal_private_key(&cbb, priv))
|
||||
return 0;
|
||||
if (!CBB_finish(&cbb, out_buf, out_len))
|
||||
return 0;
|
||||
CBB_cleanup(&cbb);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void
|
||||
MlkemKeygenFileTest(CBS *seed, CBS *public_key, CBS *private_key)
|
||||
MlkemKeygenFileTest(CBB *seed_cbb, CBB *public_key_cbb, CBB *private_key_cbb,
|
||||
size_t line)
|
||||
{
|
||||
struct MLKEM1024_private_key priv;
|
||||
uint8_t *seed = NULL, *public_key = NULL, *private_key = NULL;
|
||||
size_t seed_len = 0, public_key_len = 0, private_key_len = 0;
|
||||
uint8_t *encoded_private_key = NULL;
|
||||
uint8_t encoded_public_key[MLKEM1024_PUBLIC_KEY_BYTES];
|
||||
size_t len;
|
||||
int failed = 1;
|
||||
|
||||
if (!CBB_finish(seed_cbb, &seed, &seed_len))
|
||||
goto err;
|
||||
if (!compare_length(MLKEM_SEED_BYTES, seed_len, line, "seed length"))
|
||||
goto err;
|
||||
if (!CBB_finish(public_key_cbb, &public_key, &public_key_len))
|
||||
goto err;
|
||||
if (!compare_length(MLKEM1024_PUBLIC_KEY_BYTES, public_key_len, line,
|
||||
"public key length"))
|
||||
goto err;
|
||||
if (!CBB_finish(private_key_cbb, &private_key, &private_key_len))
|
||||
goto err;
|
||||
if (!compare_length(MLKEM1024_PUBLIC_KEY_BYTES, public_key_len, line,
|
||||
"public key length"))
|
||||
goto err;
|
||||
|
||||
TEST(CBS_len(seed) != MLKEM_SEED_BYTES, "seed len bogus");
|
||||
TEST(CBS_len(private_key) != MLKEM1024_PRIVATE_KEY_BYTES,
|
||||
"expected private key len bogus");
|
||||
TEST(CBS_len(public_key) != MLKEM1024_PUBLIC_KEY_BYTES,
|
||||
"expected public key len bogus");
|
||||
MLKEM1024_generate_key_external_entropy(encoded_public_key, &priv,
|
||||
CBS_data(seed));
|
||||
TEST(!encode_private_key(&priv, &encoded_private_key,
|
||||
&len), "encode_private_key");
|
||||
TEST(len != MLKEM1024_PRIVATE_KEY_BYTES, "private key len bogus");
|
||||
TEST_DATAEQ(encoded_public_key, CBS_data(public_key),
|
||||
MLKEM1024_PUBLIC_KEY_BYTES, "public key");
|
||||
TEST_DATAEQ(encoded_private_key, CBS_data(private_key),
|
||||
MLKEM1024_PRIVATE_KEY_BYTES, "private key");
|
||||
seed);
|
||||
if (!mlkem1024_encode_private_key(&priv, &encoded_private_key, &len)) {
|
||||
warnx("#%zu: encoded_private_key", line);
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (!compare_length(MLKEM1024_PRIVATE_KEY_BYTES, len, line,
|
||||
"private key length"))
|
||||
goto err;
|
||||
|
||||
failed = compare_data(private_key, encoded_private_key,
|
||||
MLKEM1024_PRIVATE_KEY_BYTES, line, "private key");
|
||||
failed |= compare_data(public_key, encoded_public_key,
|
||||
MLKEM1024_PUBLIC_KEY_BYTES, line, "public key");
|
||||
|
||||
err:
|
||||
CBB_cleanup(seed_cbb);
|
||||
CBB_cleanup(public_key_cbb);
|
||||
CBB_cleanup(private_key_cbb);
|
||||
freezero(seed, seed_len);
|
||||
freezero(public_key, public_key_len);
|
||||
freezero(private_key, private_key_len);
|
||||
free(encoded_private_key);
|
||||
|
||||
return failed;
|
||||
}
|
||||
|
||||
#define S_START 0
|
||||
#define S_SEED 1
|
||||
#define S_PUBLIC_KEY 2
|
||||
#define S_PRIVATE_KEY 3
|
||||
#define S_START 0
|
||||
#define S_COMMENT 1
|
||||
#define S_SEED 2
|
||||
#define S_PUBLIC_KEY 3
|
||||
#define S_PRIVATE_KEY 4
|
||||
|
||||
#define S2S(x) case x: return #x
|
||||
|
||||
static const char *
|
||||
state2str(int state)
|
||||
{
|
||||
switch (state) {
|
||||
S2S(S_START);
|
||||
S2S(S_COMMENT);
|
||||
S2S(S_SEED);
|
||||
S2S(S_PUBLIC_KEY);
|
||||
S2S(S_PRIVATE_KEY);
|
||||
default:
|
||||
errx(1, "unknown state %d", state);
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
CBS seed, public_key, private_key;
|
||||
char *buf;
|
||||
CBB seed = { 0 }, public_key = { 0 }, private_key = { 0 };
|
||||
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");
|
||||
|
||||
state = S_COMMENT;
|
||||
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');
|
||||
|
||||
fprintf(stderr, "Testing keygen 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_SEED;
|
||||
test_number = 1;
|
||||
while (fgets(buf, 16*1024, fp) != NULL) {
|
||||
switch (state) {
|
||||
case S_START:
|
||||
if (strcmp(buf, "\n") != 0)
|
||||
break;
|
||||
state = S_COMMENT;
|
||||
break;
|
||||
case S_COMMENT:
|
||||
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_SEED;
|
||||
break;
|
||||
case S_SEED:
|
||||
if (strncmp(buf, "seed: ", strlen("seed: ")) != 0) {
|
||||
break;
|
||||
}
|
||||
grab_data(&seed, buf, strlen("seed: "));
|
||||
if (!get_string_cbs(&cbs, "seed: ", line, msg))
|
||||
errx(1, "#%zu %s: get_string_cbs", line, msg);
|
||||
hex_decode_cbs(&cbs, &seed, line, msg);
|
||||
state = S_PUBLIC_KEY;
|
||||
break;
|
||||
case S_PUBLIC_KEY:
|
||||
if (strncmp(buf, "public_key: ",
|
||||
strlen("public_key: ")) != 0)
|
||||
break;
|
||||
grab_data(&public_key, buf, strlen("public_key: "));
|
||||
if (!get_string_cbs(&cbs, "public_key: ", line, msg))
|
||||
errx(1, "#%zu %s: get_string_cbs", line, msg);
|
||||
hex_decode_cbs(&cbs, &public_key, 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: "));
|
||||
state = S_START;
|
||||
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);
|
||||
|
||||
MlkemKeygenFileTest(&seed, &public_key, &private_key);
|
||||
free((void *)CBS_data(&seed));
|
||||
free((void *)CBS_data(&public_key));
|
||||
free((void *)CBS_data(&private_key));
|
||||
failed |= MlkemKeygenFileTest(&seed, &public_key,
|
||||
&private_key, line);
|
||||
|
||||
test_number++;
|
||||
state = S_START;
|
||||
break;
|
||||
}
|
||||
if (CBS_len(&cbs) > 0)
|
||||
errx(1, "#%zu %s: CBS_len", line, msg);
|
||||
}
|
||||
|
||||
free(buf);
|
||||
|
||||
if (ferror(fp))
|
||||
err(1, NULL);
|
||||
fclose(fp);
|
||||
exit(failure);
|
||||
|
||||
return failed;
|
||||
}
|
||||
|
@ -1,7 +1,8 @@
|
||||
/* $OpenBSD: mlkem1024_nist_decap_tests.c,v 1.2 2024/12/14 19:16:24 tb Exp $ */
|
||||
/* $OpenBSD: mlkem1024_nist_decap_tests.c,v 1.3 2024/12/20 00:07:12 tb Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2024, Google Inc.
|
||||
* Copyright (c) 2024, Bob Beck <beck@obtuse.com>
|
||||
* Copyright (c) 2024 Google Inc.
|
||||
* Copyright (c) 2024 Bob Beck <beck@obtuse.com>
|
||||
* Copyright (c) 2024 Theo Buehler <tb@openbsd.org>
|
||||
*
|
||||
* 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,96 +17,177 @@
|
||||
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <err.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <openssl/bytestring.h>
|
||||
#include <openssl/mlkem.h>
|
||||
#include "bytestring.h"
|
||||
#include "mlkem.h"
|
||||
|
||||
#include "mlkem_internal.h"
|
||||
#include "mlkem_tests_util.h"
|
||||
|
||||
static void
|
||||
MlkemNistDecapFileTest(CBS *c, CBS *k, CBS *dk)
|
||||
static int
|
||||
MlkemNistDecapFileTest(CBB *c_cbb, CBB *k_cbb, CBS *dk, size_t line)
|
||||
{
|
||||
uint8_t *c = NULL, *k = NULL;
|
||||
size_t c_len = 0, k_len = 0;
|
||||
uint8_t shared_secret[MLKEM_SHARED_SECRET_BYTES];
|
||||
struct MLKEM1024_private_key priv;
|
||||
int failed = 1;
|
||||
|
||||
TEST(CBS_len(dk) != MLKEM1024_PRIVATE_KEY_BYTES,
|
||||
"private key len bogus");
|
||||
TEST(CBS_len(k) != MLKEM_SHARED_SECRET_BYTES,
|
||||
"shared secret len bogus");
|
||||
if (!CBB_finish(c_cbb, &c, &c_len))
|
||||
goto err;
|
||||
if (!CBB_finish(k_cbb, &k, &k_len))
|
||||
goto err;
|
||||
|
||||
TEST(!MLKEM1024_parse_private_key(&priv, dk), "parse_private_key");
|
||||
TEST(!MLKEM1024_decap(shared_secret, CBS_data(c), CBS_len(c), &priv),
|
||||
"decap");
|
||||
TEST_DATAEQ(shared_secret, CBS_data(k),
|
||||
MLKEM_SHARED_SECRET_BYTES, "shared_secret");
|
||||
if (!compare_length(MLKEM1024_PRIVATE_KEY_BYTES, CBS_len(dk), line,
|
||||
"private key len bogus"))
|
||||
goto err;
|
||||
if (!compare_length(MLKEM_SHARED_SECRET_BYTES, k_len, line,
|
||||
"shared secret len bogus"))
|
||||
goto err;
|
||||
|
||||
if (!MLKEM1024_parse_private_key(&priv, dk)) {
|
||||
warnx("#%zu MLKEM1024_parse_private_key", line);
|
||||
goto err;
|
||||
}
|
||||
if (!MLKEM1024_decap(shared_secret, c, c_len, &priv)) {
|
||||
warnx("#%zu MLKEM1024_decap", line);
|
||||
goto err;
|
||||
}
|
||||
|
||||
failed = compare_data(shared_secret, k, k_len, line, "shared_secret");
|
||||
|
||||
err:
|
||||
CBB_cleanup(c_cbb);
|
||||
CBB_cleanup(k_cbb);
|
||||
freezero(c, c_len);
|
||||
freezero(k, k_len);
|
||||
|
||||
return failed;
|
||||
}
|
||||
|
||||
#define S_START 0
|
||||
#define S_CIPHERTEXT 1
|
||||
#define S_SHARED_SECRET 2
|
||||
#define S_PRIVATE_KEY 3
|
||||
#define S_START 0
|
||||
#define S_C 1
|
||||
#define S_K 2
|
||||
#define S_EMPTY 3
|
||||
|
||||
#define S2S(x) case x: return #x
|
||||
|
||||
static const char *
|
||||
state2str(int state)
|
||||
{
|
||||
switch (state) {
|
||||
S2S(S_START);
|
||||
S2S(S_C);
|
||||
S2S(S_K);
|
||||
S2S(S_EMPTY);
|
||||
default:
|
||||
errx(1, "unknown state %d", state);
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
CBS ciphertext, shared_secret, private_key;
|
||||
const uint8_t *p;
|
||||
char *buf;
|
||||
CBB dk_cbb = { 0 }, c = { 0 }, k = { 0 };
|
||||
CBS instr;
|
||||
uint8_t *dk = NULL;
|
||||
size_t dk_len = 0;
|
||||
uint8_t bracket, newline;
|
||||
const char *test;
|
||||
size_t line;
|
||||
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");
|
||||
|
||||
if ((len = getline(&buf, &buflen, fp)) == -1)
|
||||
err(1, "failed to read instruction line");
|
||||
|
||||
/*
|
||||
* The private key is enclosed in brackets in an "instruction line".
|
||||
*/
|
||||
line = 1;
|
||||
CBS_init(&instr, buf, len);
|
||||
if (!CBS_get_u8(&instr, &bracket))
|
||||
err(1, "failed to parse instruction line '['");
|
||||
assert(bracket == '[');
|
||||
if (!CBS_get_last_u8(&instr, &newline))
|
||||
errx(1, "failed to parse instruction line '\\n'");
|
||||
assert(newline == '\n');
|
||||
if (!CBS_get_last_u8(&instr, &bracket))
|
||||
errx(1, "failed to parse instruction line ']'");
|
||||
assert(bracket == ']');
|
||||
if (!get_string_cbs(&instr, "dk: ", line, "private key"))
|
||||
errx(1, "failed to read instruction line 'dk: '");
|
||||
hex_decode_cbs(&instr, &dk_cbb, line, "private key");
|
||||
assert(CBS_len(&instr) == 0);
|
||||
|
||||
if (!CBB_finish(&dk_cbb, &dk, &dk_len))
|
||||
errx(1, "CBB finish instruction line");
|
||||
|
||||
state = S_START;
|
||||
|
||||
while ((len = getline(&buf, &buflen, fp)) != -1) {
|
||||
const char *msg = state2str(state);
|
||||
CBS cbs, dk_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');
|
||||
|
||||
fprintf(stderr, "Testing NIST 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_CIPHERTEXT;
|
||||
test_number = 1;
|
||||
while (fgets(buf, 16*1024, fp) != NULL) {
|
||||
switch (state) {
|
||||
case S_START:
|
||||
if (strcmp(buf, "\n") != 0)
|
||||
break;
|
||||
state = S_CIPHERTEXT;
|
||||
state = S_C;
|
||||
break;
|
||||
case S_CIPHERTEXT:
|
||||
if (strncmp(buf, "ciphertext: ",
|
||||
strlen("ciphertext: ")) != 0) {
|
||||
break;
|
||||
}
|
||||
grab_data(&ciphertext, buf, strlen("ciphertext: "));
|
||||
state = S_SHARED_SECRET;
|
||||
case S_C:
|
||||
if (!get_string_cbs(&cbs, "c: ", line, msg))
|
||||
errx(1, "#%zu %s: get_string_cbs", line, msg);
|
||||
hex_decode_cbs(&cbs, &c, line, msg);
|
||||
state = S_K;
|
||||
break;
|
||||
case S_SHARED_SECRET:
|
||||
if (strncmp(buf, "shared_secret: ",
|
||||
strlen("shared_secret: ")) != 0)
|
||||
break;
|
||||
grab_data(&shared_secret, buf,
|
||||
strlen("shared_secret: "));
|
||||
state = S_PRIVATE_KEY;
|
||||
case S_K:
|
||||
if (!get_string_cbs(&cbs, "k: ", line, msg))
|
||||
errx(1, "#%zu %s: get_string_cbs", line, msg);
|
||||
hex_decode_cbs(&cbs, &k, line, msg);
|
||||
state = S_EMPTY;
|
||||
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);
|
||||
case S_EMPTY:
|
||||
CBS_init(&dk_cbs, dk, dk_len);
|
||||
|
||||
MlkemNistDecapFileTest(&ciphertext, &shared_secret,
|
||||
&private_key);
|
||||
free((void *)CBS_data(&ciphertext));
|
||||
free((void *)CBS_data(&shared_secret));
|
||||
free((void *)p);
|
||||
failed |= MlkemNistDecapFileTest(&c, &k, &dk_cbs, line);
|
||||
|
||||
state = S_START;
|
||||
test_number++;
|
||||
state = S_C;
|
||||
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);
|
||||
|
||||
freezero(dk, dk_len);
|
||||
|
||||
return failed;
|
||||
}
|
||||
|
@ -1,7 +1,8 @@
|
||||
/* $OpenBSD: mlkem1024_nist_keygen_tests.c,v 1.3 2024/12/17 07:20:10 tb Exp $ */
|
||||
/* $OpenBSD: mlkem1024_nist_keygen_tests.c,v 1.4 2024/12/20 00:07:12 tb Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2024, Google Inc.
|
||||
* Copyright (c) 2024, Bob Beck <beck@obtuse.com>
|
||||
* Copyright (c) 2024 Google Inc.
|
||||
* Copyright (c) 2024 Bob Beck <beck@obtuse.com>
|
||||
* Copyright (c) 2024 Theo Buehler <tb@openbsd.org>
|
||||
*
|
||||
* 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,123 +17,181 @@
|
||||
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <err.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <openssl/bytestring.h>
|
||||
#include <openssl/mlkem.h>
|
||||
#include "bytestring.h"
|
||||
#include "mlkem.h"
|
||||
|
||||
#include "mlkem_internal.h"
|
||||
#include "mlkem_tests_util.h"
|
||||
|
||||
static int
|
||||
encode_private_key(const struct MLKEM1024_private_key *priv, uint8_t **out_buf,
|
||||
size_t *out_len)
|
||||
{
|
||||
CBB cbb;
|
||||
if (!CBB_init(&cbb, MLKEM1024_PUBLIC_KEY_BYTES))
|
||||
return 0;
|
||||
if (!MLKEM1024_marshal_private_key(&cbb, priv))
|
||||
return 0;
|
||||
if (!CBB_finish(&cbb, out_buf, out_len))
|
||||
return 0;
|
||||
CBB_cleanup(&cbb);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void
|
||||
MlkemNistKeygenFileTest(CBS *z, CBS *d, CBS *ek, CBS *dk)
|
||||
MlkemNistKeygenFileTest(CBB *z_cbb, CBB *d_cbb, CBB *ek_cbb, CBB *dk_cbb,
|
||||
size_t line)
|
||||
{
|
||||
CBB seed_cbb;
|
||||
uint8_t *z = NULL, *d = NULL, *ek = NULL, *dk = NULL;
|
||||
size_t z_len = 0, d_len = 0, ek_len = 0, dk_len = 0;
|
||||
uint8_t seed[MLKEM_SEED_BYTES];
|
||||
struct MLKEM1024_private_key priv;
|
||||
uint8_t *encoded_private_key = NULL;
|
||||
uint8_t encoded_public_key[MLKEM1024_PUBLIC_KEY_BYTES];
|
||||
size_t len;
|
||||
int failed = 1;
|
||||
|
||||
if (!CBB_init_fixed(&seed_cbb, seed, sizeof(seed)))
|
||||
goto err;
|
||||
|
||||
if (!CBB_finish(z_cbb, &z, &z_len))
|
||||
goto err;
|
||||
if (!CBB_finish(d_cbb, &d, &d_len))
|
||||
goto err;
|
||||
if (!CBB_finish(ek_cbb, &ek, &ek_len))
|
||||
goto err;
|
||||
if (!CBB_finish(dk_cbb, &dk, &dk_len))
|
||||
goto err;
|
||||
|
||||
if (!CBB_add_bytes(&seed_cbb, d, d_len))
|
||||
goto err;
|
||||
if (!CBB_add_bytes(&seed_cbb, z, z_len))
|
||||
goto err;
|
||||
if (!CBB_finish(&seed_cbb, NULL, &len))
|
||||
goto err;
|
||||
|
||||
if (!compare_length(MLKEM_SEED_BYTES, len, line, "z or d length bogus"))
|
||||
goto err;
|
||||
|
||||
TEST(CBS_len(d) != (MLKEM_SEED_BYTES / 2), "d len bogus");
|
||||
TEST(CBS_len(z) != (MLKEM_SEED_BYTES / 2), "z len bogus");
|
||||
TEST(CBS_len(dk) != MLKEM1024_PRIVATE_KEY_BYTES,
|
||||
"expected private key len bogus");
|
||||
TEST(CBS_len(ek) != MLKEM1024_PUBLIC_KEY_BYTES,
|
||||
"expected public key len bogus");
|
||||
memcpy(&seed[0], CBS_data(d), CBS_len(d));
|
||||
memcpy(&seed[MLKEM_SEED_BYTES / 2], CBS_data(z), CBS_len(z));
|
||||
MLKEM1024_generate_key_external_entropy(encoded_public_key, &priv, seed);
|
||||
TEST(!encode_private_key(&priv, &encoded_private_key,
|
||||
&len), "encode_private_key");
|
||||
TEST(len != MLKEM1024_PRIVATE_KEY_BYTES, "private key len bogus");
|
||||
TEST_DATAEQ(encoded_public_key, CBS_data(ek),
|
||||
MLKEM1024_PUBLIC_KEY_BYTES, "public key");
|
||||
TEST_DATAEQ(encoded_private_key, CBS_data(dk),
|
||||
MLKEM1024_PRIVATE_KEY_BYTES, "private key");
|
||||
|
||||
if (!mlkem1024_encode_private_key(&priv, &encoded_private_key, &len)) {
|
||||
warnx("#%zu mlkem1024_encode_private_key", line);
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (!compare_length(MLKEM1024_PRIVATE_KEY_BYTES, len, line,
|
||||
"private key length"))
|
||||
goto err;
|
||||
|
||||
failed = compare_data(ek, encoded_public_key, MLKEM1024_PUBLIC_KEY_BYTES,
|
||||
line, "public key");
|
||||
failed |= compare_data(dk, encoded_private_key, MLKEM1024_PRIVATE_KEY_BYTES,
|
||||
line, "private key");
|
||||
|
||||
err:
|
||||
CBB_cleanup(&seed_cbb);
|
||||
CBB_cleanup(z_cbb);
|
||||
CBB_cleanup(d_cbb);
|
||||
CBB_cleanup(ek_cbb);
|
||||
CBB_cleanup(dk_cbb);
|
||||
freezero(z, z_len);
|
||||
freezero(d, d_len);
|
||||
freezero(ek, ek_len);
|
||||
freezero(dk, dk_len);
|
||||
free(encoded_private_key);
|
||||
|
||||
return failed;
|
||||
}
|
||||
|
||||
#define S_START 0
|
||||
#define S_Z 1
|
||||
#define S_D 2
|
||||
#define S_EK 3
|
||||
#define S_DK 4
|
||||
#define S_START 0
|
||||
#define S_Z 1
|
||||
#define S_D 2
|
||||
#define S_EK 3
|
||||
#define S_DK 4
|
||||
|
||||
#define S2S(x) case x: return #x
|
||||
|
||||
static const char *
|
||||
state2str(int state)
|
||||
{
|
||||
switch (state) {
|
||||
S2S(S_START);
|
||||
S2S(S_Z);
|
||||
S2S(S_D);
|
||||
S2S(S_EK);
|
||||
S2S(S_DK);
|
||||
default:
|
||||
errx(1, "unknown state %d", state);
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
CBS z, d, ek, dk;
|
||||
char *buf;
|
||||
CBB z = { 0 }, d = { 0 }, ek = { 0 }, dk = { 0 };
|
||||
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 NIST keygen 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_Z;
|
||||
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_Z;
|
||||
break;
|
||||
case S_Z:
|
||||
if (strncmp(buf, "z: ", strlen("z: ")) != 0) {
|
||||
break;
|
||||
}
|
||||
grab_data(&z, buf, strlen("z: "));
|
||||
if (!get_string_cbs(&cbs, "z: ", line, msg))
|
||||
errx(1, "#%zu %s: get_string_cbs", line, msg);
|
||||
hex_decode_cbs(&cbs, &z, line, msg);
|
||||
state = S_D;
|
||||
break;
|
||||
case S_D:
|
||||
if (strncmp(buf, "d: ", strlen("d: ")) != 0)
|
||||
break;
|
||||
grab_data(&d, buf, strlen("d: "));
|
||||
if (!get_string_cbs(&cbs, "d: ", line, msg))
|
||||
errx(1, "#%zu %s: get_string_cbs", line, msg);
|
||||
hex_decode_cbs(&cbs, &d, line, msg);
|
||||
state = S_EK;
|
||||
break;
|
||||
case S_EK:
|
||||
if (strncmp(buf, "ek: ", strlen("ek: ")) != 0)
|
||||
break;
|
||||
grab_data(&ek, buf, strlen("ek: "));
|
||||
if (!get_string_cbs(&cbs, "ek: ", line, msg))
|
||||
errx(1, "#%zu %s: get_string_cbs", line, msg);
|
||||
hex_decode_cbs(&cbs, &ek, line, msg);
|
||||
state = S_DK;
|
||||
break;
|
||||
case S_DK:
|
||||
if (strncmp(buf, "dk: ", strlen("dk: ")) != 0)
|
||||
break;
|
||||
grab_data(&dk, buf, strlen("dk: "));
|
||||
if (!get_string_cbs(&cbs, "dk: ", line, msg))
|
||||
errx(1, "#%zu %s: get_string_cbs", line, msg);
|
||||
hex_decode_cbs(&cbs, &dk, line, msg);
|
||||
|
||||
MlkemNistKeygenFileTest(&z, &d, &ek, &dk);
|
||||
free((void *)CBS_data(&z));
|
||||
free((void *)CBS_data(&d));
|
||||
free((void *)CBS_data(&ek));
|
||||
free((void *)CBS_data(&dk));
|
||||
failed |= MlkemNistKeygenFileTest(&z, &d, &ek, &dk, line);
|
||||
|
||||
test_number++;
|
||||
state = S_START;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
free(buf);
|
||||
|
||||
if (ferror(fp))
|
||||
err(1, NULL);
|
||||
fclose(fp);
|
||||
exit(failure);
|
||||
|
||||
return failed;
|
||||
}
|
||||
|
@ -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 <beck@obtuse.com>
|
||||
* Copyright (c) 2024 Google Inc.
|
||||
* Copyright (c) 2024 Bob Beck <beck@obtuse.com>
|
||||
* Copyright (c) 2024 Theo Buehler <tb@openbsd.org>
|
||||
*
|
||||
* 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 <assert.h>
|
||||
#include <err.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <openssl/bytestring.h>
|
||||
#include <openssl/mlkem.h>
|
||||
#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;
|
||||
}
|
||||
decap_ok = MLKEM768_decap(shared_secret, CBS_data(c), CBS_len(c),
|
||||
&priv);
|
||||
if (!decap_ok) {
|
||||
TEST(!should_fail, "decap");
|
||||
return;
|
||||
if (!MLKEM768_decap(shared_secret_buf, ciphertext, ciphertext_len,
|
||||
&priv)) {
|
||||
if ((failed = !should_fail))
|
||||
warnx("#%zu: decap", line);
|
||||
goto err;
|
||||
}
|
||||
TEST_DATAEQ(shared_secret, CBS_data(k),
|
||||
MLKEM_SHARED_SECRET_BYTES, "shared_secret");
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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);
|
||||
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);
|
||||
|
||||
test_number++;
|
||||
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;
|
||||
}
|
||||
|
@ -1,7 +1,8 @@
|
||||
/* $OpenBSD: mlkem768_encap_tests.c,v 1.2 2024/12/14 19:16:24 tb Exp $ */
|
||||
/* $OpenBSD: mlkem768_encap_tests.c,v 1.3 2024/12/20 00:07:12 tb Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2024, Google Inc.
|
||||
* Copyright (c) 2024, Bob Beck <beck@obtuse.com>
|
||||
* Copyright (c) 2024 Google Inc.
|
||||
* Copyright (c) 2024 Bob Beck <beck@obtuse.com>
|
||||
* Copyright (c) 2024 Theo Buehler <tb@openbsd.org>
|
||||
*
|
||||
* 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,120 +17,194 @@
|
||||
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <err.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <openssl/bytestring.h>
|
||||
#include <openssl/mlkem.h>
|
||||
#include "bytestring.h"
|
||||
#include "mlkem.h"
|
||||
|
||||
#include "mlkem_internal.h"
|
||||
#include "mlkem_tests_util.h"
|
||||
|
||||
static void
|
||||
MlkemEncapFileTest(CBS *entropy, CBS *public_key, CBS *expected_ciphertext,
|
||||
CBS *expected_shared_secret, int should_fail)
|
||||
static int
|
||||
MlkemEncapFileTest(CBB *entropy_cbb, CBB *pubkey_cbb, CBB *ciphertext_cbb,
|
||||
CBB *shared_secret_cbb, int should_fail, size_t line)
|
||||
{
|
||||
uint8_t shared_secret[MLKEM_SHARED_SECRET_BYTES];
|
||||
uint8_t ciphertext[MLKEM768_CIPHERTEXT_BYTES];
|
||||
struct MLKEM768_public_key pub;
|
||||
int parse_ok;
|
||||
uint8_t *entropy = NULL, *public_key = NULL, *ciphertext = NULL;
|
||||
uint8_t *shared_secret = NULL;
|
||||
size_t entropy_len = 0, public_key_len = 0, ciphertext_len = 0;
|
||||
size_t shared_secret_len = 0;
|
||||
uint8_t shared_secret_buf[MLKEM_SHARED_SECRET_BYTES];
|
||||
uint8_t ciphertext_buf[MLKEM768_CIPHERTEXT_BYTES];
|
||||
CBS public_key_cbs;
|
||||
int failed = 1;
|
||||
|
||||
parse_ok = MLKEM768_parse_public_key(&pub, public_key);
|
||||
if (!parse_ok) {
|
||||
TEST(!should_fail, "parse_public_key");
|
||||
return;
|
||||
if (!CBB_finish(entropy_cbb, &entropy, &entropy_len))
|
||||
goto err;
|
||||
if (!CBB_finish(pubkey_cbb, &public_key, &public_key_len))
|
||||
goto err;
|
||||
if (!CBB_finish(ciphertext_cbb, &ciphertext, &ciphertext_len))
|
||||
goto err;
|
||||
if (!CBB_finish(shared_secret_cbb, &shared_secret, &shared_secret_len))
|
||||
goto err;
|
||||
|
||||
CBS_init(&public_key_cbs, public_key, public_key_len);
|
||||
|
||||
if (!MLKEM768_parse_public_key(&pub, &public_key_cbs)) {
|
||||
if ((failed = !should_fail))
|
||||
warnx("#%zu: parse_public_key", line);
|
||||
goto err;
|
||||
}
|
||||
MLKEM768_encap(ciphertext, shared_secret, &pub);
|
||||
TEST_DATAEQ(shared_secret, CBS_data(expected_shared_secret),
|
||||
MLKEM_SHARED_SECRET_BYTES, "shared_secret");
|
||||
TEST_DATAEQ(ciphertext, CBS_data(expected_ciphertext),
|
||||
MLKEM768_CIPHERTEXT_BYTES, "shared_secret");
|
||||
MLKEM768_encap_external_entropy(ciphertext_buf, shared_secret_buf,
|
||||
&pub, entropy);
|
||||
|
||||
failed = compare_data(shared_secret, shared_secret_buf,
|
||||
MLKEM_SHARED_SECRET_BYTES, line, "shared_secret");
|
||||
failed |= compare_data(ciphertext, ciphertext_buf,
|
||||
MLKEM768_CIPHERTEXT_BYTES, line, "ciphertext");
|
||||
|
||||
if (should_fail != failed) {
|
||||
warnx("FAIL: #%zu: should_fail %d, failed %d",
|
||||
line, should_fail, failed);
|
||||
failed = 1;
|
||||
}
|
||||
|
||||
err:
|
||||
CBB_cleanup(entropy_cbb);
|
||||
CBB_cleanup(pubkey_cbb);
|
||||
CBB_cleanup(ciphertext_cbb);
|
||||
CBB_cleanup(shared_secret_cbb);
|
||||
freezero(entropy, entropy_len);
|
||||
freezero(public_key, public_key_len);
|
||||
freezero(ciphertext, ciphertext_len);
|
||||
freezero(shared_secret, shared_secret_len);
|
||||
|
||||
return failed;
|
||||
}
|
||||
|
||||
#define S_START 0
|
||||
#define S_COMMENT 1
|
||||
#define S_ENTROPY 2
|
||||
#define S_PUBLIC_KEY 3
|
||||
#define S_RESULT 4
|
||||
#define S_CIPHERTEXT 5
|
||||
#define S_SHARED_SECRET 6
|
||||
#define S_START 0
|
||||
#define S_COMMENT 1
|
||||
#define S_ENTROPY 2
|
||||
#define S_PUBLIC_KEY 3
|
||||
#define S_RESULT 4
|
||||
#define S_CIPHERTEXT 5
|
||||
#define S_SHARED_SECRET 6
|
||||
|
||||
#define S2S(x) case x: return #x
|
||||
|
||||
static const char *
|
||||
state2str(int state)
|
||||
{
|
||||
switch (state) {
|
||||
S2S(S_START);
|
||||
S2S(S_COMMENT);
|
||||
S2S(S_ENTROPY);
|
||||
S2S(S_PUBLIC_KEY);
|
||||
S2S(S_RESULT);
|
||||
S2S(S_CIPHERTEXT);
|
||||
S2S(S_SHARED_SECRET);
|
||||
default:
|
||||
errx(1, "unknown state %d", state);
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
CBS entropy, public_key, ciphertext, shared_secret;
|
||||
const uint8_t *p = NULL;
|
||||
CBB entropy = { 0 }, public_key = { 0 }, ciphertext = { 0 }, shared_secret = { 0 };
|
||||
int should_fail = 0;
|
||||
char *buf;
|
||||
const char *test;
|
||||
size_t line;
|
||||
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];
|
||||
line = 0;
|
||||
|
||||
if ((fp = fopen(test, "r")) == NULL)
|
||||
err(1, "cant't open test file");
|
||||
|
||||
fprintf(stderr, "Testing encap 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_ENTROPY;
|
||||
break;
|
||||
case S_ENTROPY:
|
||||
if (strncmp(buf, "entropy: ", strlen("entropy: ")) != 0)
|
||||
break;
|
||||
grab_data(&entropy, buf, strlen("entropy: "));
|
||||
p = CBS_data(&entropy);
|
||||
if (!get_string_cbs(&cbs, "entropy: ", line, msg))
|
||||
errx(1, "#%zu %s: get_string_cbs", line, msg);
|
||||
hex_decode_cbs(&cbs, &entropy, line, msg);
|
||||
state = S_PUBLIC_KEY;
|
||||
break;
|
||||
case S_PUBLIC_KEY:
|
||||
if (strncmp(buf, "public_key: ",
|
||||
strlen("public_key: ")) != 0)
|
||||
break;
|
||||
grab_data(&public_key, buf, strlen("public_key: "));
|
||||
p = CBS_data(&public_key);
|
||||
if (!get_string_cbs(&cbs, "public_key = ", line, msg))
|
||||
errx(1, "#%zu %s: get_string_cbs", line, msg);
|
||||
hex_decode_cbs(&cbs, &public_key, 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_CIPHERTEXT;
|
||||
break;
|
||||
case S_CIPHERTEXT:
|
||||
if (strncmp(buf, "ciphertext: ",
|
||||
strlen("ciphertext: ")) != 0)
|
||||
break;
|
||||
grab_data(&ciphertext, buf, strlen("ciphertext: "));
|
||||
state = S_RESULT;
|
||||
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_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: "));
|
||||
MlkemEncapFileTest(&entropy, &public_key, &ciphertext,
|
||||
&shared_secret, should_fail);
|
||||
free((void *)CBS_data(&ciphertext));
|
||||
free((void *)CBS_data(&shared_secret));
|
||||
free((void *)p);
|
||||
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 |= MlkemEncapFileTest(&entropy, &public_key,
|
||||
&ciphertext, &shared_secret, should_fail, line);
|
||||
|
||||
test_number++;
|
||||
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;
|
||||
}
|
||||
|
@ -1,7 +1,8 @@
|
||||
/* $OpenBSD: mlkem768_iteration_test.c,v 1.2 2024/12/14 19:16:24 tb Exp $ */
|
||||
/* $OpenBSD: mlkem768_iteration_test.c,v 1.3 2024/12/20 00:07:12 tb Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2024, Google Inc.
|
||||
* Copyright (c) 2024, Bob Beck <beck@obtuse.com>
|
||||
* Copyright (c) 2024 Google Inc.
|
||||
* Copyright (c) 2024 Bob Beck <beck@obtuse.com>
|
||||
* Copyright (c) 2024 Theo Buehler <tb@openbsd.org>
|
||||
*
|
||||
* 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,32 +17,17 @@
|
||||
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <err.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <openssl/bytestring.h>
|
||||
#include <openssl/mlkem.h>
|
||||
#include "mlkem.h"
|
||||
|
||||
#include "mlkem_internal.h"
|
||||
#include "mlkem_tests_util.h"
|
||||
#include "sha3_internal.h"
|
||||
|
||||
static int
|
||||
encode_private_key(const struct MLKEM768_private_key *priv, uint8_t **out_buf,
|
||||
size_t *out_len)
|
||||
{
|
||||
CBB cbb;
|
||||
if (!CBB_init(&cbb, MLKEM768_PUBLIC_KEY_BYTES))
|
||||
return 0;
|
||||
if (!MLKEM768_marshal_private_key(&cbb, priv))
|
||||
return 0;
|
||||
if (!CBB_finish(&cbb, out_buf, out_len))
|
||||
return 0;
|
||||
CBB_cleanup(&cbb);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* The structure of this test is taken from
|
||||
* https://github.com/C2SP/CCTV/blob/main/ML-KEM/README.md?ref=words.filippo.io#accumulated-pq-crystals-vectors
|
||||
@ -52,8 +38,8 @@ encode_private_key(const struct MLKEM768_private_key *priv, uint8_t **out_buf,
|
||||
* (The RNG stream starts with 7f9c2ba4e88f827d616045507605853e.)
|
||||
*/
|
||||
|
||||
static void
|
||||
MlkemIterativeTest()
|
||||
static int
|
||||
MlkemIterativeTest(void)
|
||||
{
|
||||
/* https://github.com/C2SP/CCTV/tree/main/ML-KEM */
|
||||
/*
|
||||
@ -64,6 +50,7 @@ MlkemIterativeTest()
|
||||
0x7f, 0x9c, 0x2b, 0xa4, 0xe8, 0x8f, 0x82, 0x7d, 0x61, 0x60, 0x45,
|
||||
0x50, 0x76, 0x05, 0x85, 0x3e
|
||||
};
|
||||
|
||||
/*
|
||||
* Filippo says:
|
||||
* ML-KEM-768: f7db260e1137a742e05fe0db9525012812b004d29040a5b606aad3d134b548d3
|
||||
@ -100,8 +87,9 @@ MlkemIterativeTest()
|
||||
*/
|
||||
shake_out(&drng, seed, sizeof(seed));
|
||||
if (i == 0) {
|
||||
TEST_DATAEQ(seed, kExpectedSeedStart,
|
||||
sizeof(kExpectedSeedStart), "seed start");
|
||||
if (compare_data(seed, kExpectedSeedStart,
|
||||
sizeof(kExpectedSeedStart), 0, "seed start") != 0)
|
||||
errx(1, "compare_data");
|
||||
}
|
||||
|
||||
/* generate ek as encoded_public_key */
|
||||
@ -114,8 +102,9 @@ MlkemIterativeTest()
|
||||
sizeof(encoded_public_key));
|
||||
|
||||
/* marshal priv to dk as encoded_private_key */
|
||||
TEST(!encode_private_key(&priv, &encoded_private_key,
|
||||
&encoded_private_key_len), "encode_private_key");
|
||||
if (!mlkem768_encode_private_key(&priv, &encoded_private_key,
|
||||
&encoded_private_key_len))
|
||||
errx(1, "mlkem768_encode_private_key");
|
||||
|
||||
/* hash in dk */
|
||||
shake_update(&results, encoded_private_key,
|
||||
@ -140,21 +129,21 @@ MlkemIterativeTest()
|
||||
sizeof(invalid_ciphertext));
|
||||
|
||||
/* generte k as shared secret from invalid ciphertext */
|
||||
TEST(!MLKEM768_decap(shared_secret, invalid_ciphertext,
|
||||
sizeof(invalid_ciphertext), &priv), "decap failed!");
|
||||
if (!MLKEM768_decap(shared_secret, invalid_ciphertext,
|
||||
sizeof(invalid_ciphertext), &priv))
|
||||
errx(1, "decap failed");
|
||||
|
||||
/* hash in k */
|
||||
shake_update(&results, shared_secret, sizeof(shared_secret));
|
||||
}
|
||||
shake_xof(&results);
|
||||
shake_out(&results, out, 32);
|
||||
shake_out(&results, out, sizeof(out));
|
||||
|
||||
TEST_DATAEQ(out, kExpectedAdam, 32, "final result hash");
|
||||
return compare_data(kExpectedAdam, out, sizeof(out), i, "final result hash");
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
MlkemIterativeTest();
|
||||
exit(failure);
|
||||
return MlkemIterativeTest();
|
||||
}
|
||||
|
@ -1,7 +1,8 @@
|
||||
/* $OpenBSD: mlkem768_keygen_tests.c,v 1.4 2024/12/17 07:20:10 tb Exp $ */
|
||||
/* $OpenBSD: mlkem768_keygen_tests.c,v 1.5 2024/12/20 00:07:12 tb Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2024, Google Inc.
|
||||
* Copyright (c) 2024, Bob Beck <beck@obtuse.com>
|
||||
* Copyright (c) 2024 Google Inc.
|
||||
* Copyright (c) 2024 Bob Beck <beck@obtuse.com>
|
||||
* Copyright (c) 2024 Theo Buehler <tb@openbsd.org>
|
||||
*
|
||||
* 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,115 +17,174 @@
|
||||
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <err.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <openssl/bytestring.h>
|
||||
#include <openssl/mlkem.h>
|
||||
#include "bytestring.h"
|
||||
#include "mlkem.h"
|
||||
|
||||
#include "mlkem_internal.h"
|
||||
#include "mlkem_tests_util.h"
|
||||
|
||||
static int
|
||||
encode_private_key(const struct MLKEM768_private_key *priv, uint8_t **out_buf,
|
||||
size_t *out_len)
|
||||
{
|
||||
CBB cbb;
|
||||
if (!CBB_init(&cbb, MLKEM768_PUBLIC_KEY_BYTES))
|
||||
return 0;
|
||||
if (!MLKEM768_marshal_private_key(&cbb, priv))
|
||||
return 0;
|
||||
if (!CBB_finish(&cbb, out_buf, out_len))
|
||||
return 0;
|
||||
CBB_cleanup(&cbb);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void
|
||||
MlkemKeygenFileTest(CBS *seed, CBS *public_key, CBS *private_key)
|
||||
MlkemKeygenFileTest(CBB *seed_cbb, CBB *public_key_cbb, CBB *private_key_cbb,
|
||||
size_t line)
|
||||
{
|
||||
struct MLKEM768_private_key priv;
|
||||
uint8_t *seed = NULL, *public_key = NULL, *private_key = NULL;
|
||||
size_t seed_len = 0, public_key_len = 0, private_key_len = 0;
|
||||
uint8_t *encoded_private_key = NULL;
|
||||
uint8_t encoded_public_key[MLKEM768_PUBLIC_KEY_BYTES];
|
||||
size_t len;
|
||||
int failed = 1;
|
||||
|
||||
if (!CBB_finish(seed_cbb, &seed, &seed_len))
|
||||
goto err;
|
||||
if (!compare_length(MLKEM_SEED_BYTES, seed_len, line, "seed length"))
|
||||
goto err;
|
||||
if (!CBB_finish(public_key_cbb, &public_key, &public_key_len))
|
||||
goto err;
|
||||
if (!compare_length(MLKEM768_PUBLIC_KEY_BYTES, public_key_len, line,
|
||||
"public key length"))
|
||||
goto err;
|
||||
if (!CBB_finish(private_key_cbb, &private_key, &private_key_len))
|
||||
goto err;
|
||||
if (!compare_length(MLKEM768_PUBLIC_KEY_BYTES, public_key_len, line,
|
||||
"public key length"))
|
||||
goto err;
|
||||
|
||||
TEST(CBS_len(seed) != MLKEM_SEED_BYTES, "seed len bogus");
|
||||
TEST(CBS_len(private_key) != MLKEM768_PRIVATE_KEY_BYTES,
|
||||
"expected private key len bogus");
|
||||
TEST(CBS_len(public_key) != MLKEM768_PUBLIC_KEY_BYTES,
|
||||
"expected public key len bogus");
|
||||
MLKEM768_generate_key_external_entropy(encoded_public_key, &priv,
|
||||
CBS_data(seed));
|
||||
TEST(!encode_private_key(&priv, &encoded_private_key,
|
||||
&len), "encode_private_key");
|
||||
TEST(len != MLKEM768_PRIVATE_KEY_BYTES, "private key len bogus");
|
||||
TEST_DATAEQ(encoded_public_key, CBS_data(public_key),
|
||||
MLKEM768_PUBLIC_KEY_BYTES, "public key");
|
||||
TEST_DATAEQ(encoded_private_key, CBS_data(private_key),
|
||||
MLKEM768_PRIVATE_KEY_BYTES, "private key");
|
||||
seed);
|
||||
if (!mlkem768_encode_private_key(&priv, &encoded_private_key, &len)) {
|
||||
warnx("#%zu: encoded_private_key", line);
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (!compare_length(MLKEM768_PRIVATE_KEY_BYTES, len, line,
|
||||
"private key length"))
|
||||
goto err;
|
||||
|
||||
failed = compare_data(private_key, encoded_private_key,
|
||||
MLKEM768_PRIVATE_KEY_BYTES, line, "private key");
|
||||
failed |= compare_data(public_key, encoded_public_key,
|
||||
MLKEM768_PUBLIC_KEY_BYTES, line, "public key");
|
||||
|
||||
err:
|
||||
CBB_cleanup(seed_cbb);
|
||||
CBB_cleanup(public_key_cbb);
|
||||
CBB_cleanup(private_key_cbb);
|
||||
freezero(seed, seed_len);
|
||||
freezero(public_key, public_key_len);
|
||||
freezero(private_key, private_key_len);
|
||||
free(encoded_private_key);
|
||||
|
||||
return failed;
|
||||
}
|
||||
|
||||
#define S_START 0
|
||||
#define S_SEED 1
|
||||
#define S_PUBLIC_KEY 2
|
||||
#define S_PRIVATE_KEY 3
|
||||
#define S_START 0
|
||||
#define S_COMMENT 1
|
||||
#define S_SEED 2
|
||||
#define S_PUBLIC_KEY 3
|
||||
#define S_PRIVATE_KEY 4
|
||||
|
||||
#define S2S(x) case x: return #x
|
||||
|
||||
static const char *
|
||||
state2str(int state)
|
||||
{
|
||||
switch (state) {
|
||||
S2S(S_START);
|
||||
S2S(S_COMMENT);
|
||||
S2S(S_SEED);
|
||||
S2S(S_PUBLIC_KEY);
|
||||
S2S(S_PRIVATE_KEY);
|
||||
default:
|
||||
errx(1, "unknown state %d", state);
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
CBS seed, public_key, private_key;
|
||||
char *buf;
|
||||
CBB seed = { 0 }, public_key = { 0 }, private_key = { 0 };
|
||||
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");
|
||||
|
||||
state = S_COMMENT;
|
||||
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');
|
||||
|
||||
fprintf(stderr, "Testing keygen 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_SEED;
|
||||
test_number = 1;
|
||||
while (fgets(buf, 16*1024, fp) != NULL) {
|
||||
switch (state) {
|
||||
case S_START:
|
||||
if (strcmp(buf, "\n") != 0)
|
||||
break;
|
||||
state = S_COMMENT;
|
||||
break;
|
||||
case S_COMMENT:
|
||||
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_SEED;
|
||||
break;
|
||||
case S_SEED:
|
||||
if (strncmp(buf, "seed: ", strlen("seed: ")) != 0) {
|
||||
break;
|
||||
}
|
||||
grab_data(&seed, buf, strlen("seed: "));
|
||||
if (!get_string_cbs(&cbs, "seed: ", line, msg))
|
||||
errx(1, "#%zu %s: get_string_cbs", line, msg);
|
||||
hex_decode_cbs(&cbs, &seed, line, msg);
|
||||
state = S_PUBLIC_KEY;
|
||||
break;
|
||||
case S_PUBLIC_KEY:
|
||||
if (strncmp(buf, "public_key: ",
|
||||
strlen("public_key: ")) != 0)
|
||||
break;
|
||||
grab_data(&public_key, buf, strlen("public_key: "));
|
||||
if (!get_string_cbs(&cbs, "public_key: ", line, msg))
|
||||
errx(1, "#%zu %s: get_string_cbs", line, msg);
|
||||
hex_decode_cbs(&cbs, &public_key, 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: "));
|
||||
state = S_START;
|
||||
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);
|
||||
|
||||
MlkemKeygenFileTest(&seed, &public_key, &private_key);
|
||||
free((void *)CBS_data(&seed));
|
||||
free((void *)CBS_data(&public_key));
|
||||
free((void *)CBS_data(&private_key));
|
||||
failed |= MlkemKeygenFileTest(&seed, &public_key,
|
||||
&private_key, line);
|
||||
|
||||
test_number++;
|
||||
state = S_START;
|
||||
break;
|
||||
}
|
||||
if (CBS_len(&cbs) > 0)
|
||||
errx(1, "#%zu %s: CBS_len", line, msg);
|
||||
}
|
||||
|
||||
free(buf);
|
||||
|
||||
if (ferror(fp))
|
||||
err(1, NULL);
|
||||
fclose(fp);
|
||||
exit(failure);
|
||||
|
||||
return failed;
|
||||
}
|
||||
|
@ -1,7 +1,8 @@
|
||||
/* $OpenBSD: mlkem768_nist_decap_tests.c,v 1.2 2024/12/14 19:16:24 tb Exp $ */
|
||||
/* $OpenBSD: mlkem768_nist_decap_tests.c,v 1.3 2024/12/20 00:07:12 tb Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2024, Google Inc.
|
||||
* Copyright (c) 2024, Bob Beck <beck@obtuse.com>
|
||||
* Copyright (c) 2024 Google Inc.
|
||||
* Copyright (c) 2024 Bob Beck <beck@obtuse.com>
|
||||
* Copyright (c) 2024 Theo Buehler <tb@openbsd.org>
|
||||
*
|
||||
* 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,96 +17,177 @@
|
||||
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <err.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <openssl/bytestring.h>
|
||||
#include <openssl/mlkem.h>
|
||||
#include "bytestring.h"
|
||||
#include "mlkem.h"
|
||||
|
||||
#include "mlkem_internal.h"
|
||||
#include "mlkem_tests_util.h"
|
||||
|
||||
static void
|
||||
MlkemNistDecapFileTest(CBS *c, CBS *k, CBS *dk)
|
||||
static int
|
||||
MlkemNistDecapFileTest(CBB *c_cbb, CBB *k_cbb, CBS *dk, size_t line)
|
||||
{
|
||||
uint8_t *c = NULL, *k = NULL;
|
||||
size_t c_len = 0, k_len = 0;
|
||||
uint8_t shared_secret[MLKEM_SHARED_SECRET_BYTES];
|
||||
struct MLKEM768_private_key priv;
|
||||
int failed = 1;
|
||||
|
||||
TEST(CBS_len(dk) != MLKEM768_PRIVATE_KEY_BYTES,
|
||||
"private key len bogus");
|
||||
TEST(CBS_len(k) != MLKEM_SHARED_SECRET_BYTES,
|
||||
"shared secret len bogus");
|
||||
if (!CBB_finish(c_cbb, &c, &c_len))
|
||||
goto err;
|
||||
if (!CBB_finish(k_cbb, &k, &k_len))
|
||||
goto err;
|
||||
|
||||
TEST(!MLKEM768_parse_private_key(&priv, dk), "parse_private_key");
|
||||
TEST(!MLKEM768_decap(shared_secret, CBS_data(c), CBS_len(c), &priv),
|
||||
"decap");
|
||||
TEST_DATAEQ(shared_secret, CBS_data(k),
|
||||
MLKEM_SHARED_SECRET_BYTES, "shared_secret");
|
||||
if (!compare_length(MLKEM768_PRIVATE_KEY_BYTES, CBS_len(dk), line,
|
||||
"private key len bogus"))
|
||||
goto err;
|
||||
if (!compare_length(MLKEM_SHARED_SECRET_BYTES, k_len, line,
|
||||
"shared secret len bogus"))
|
||||
goto err;
|
||||
|
||||
if (!MLKEM768_parse_private_key(&priv, dk)) {
|
||||
warnx("#%zu MLKEM768_parse_private_key", line);
|
||||
goto err;
|
||||
}
|
||||
if (!MLKEM768_decap(shared_secret, c, c_len, &priv)) {
|
||||
warnx("#%zu MLKEM768_decap", line);
|
||||
goto err;
|
||||
}
|
||||
|
||||
failed = compare_data(shared_secret, k, k_len, line, "shared_secret");
|
||||
|
||||
err:
|
||||
CBB_cleanup(c_cbb);
|
||||
CBB_cleanup(k_cbb);
|
||||
freezero(c, c_len);
|
||||
freezero(k, k_len);
|
||||
|
||||
return failed;
|
||||
}
|
||||
|
||||
#define S_START 0
|
||||
#define S_CIPHERTEXT 1
|
||||
#define S_SHARED_SECRET 2
|
||||
#define S_PRIVATE_KEY 3
|
||||
#define S_START 0
|
||||
#define S_C 1
|
||||
#define S_K 2
|
||||
#define S_EMPTY 3
|
||||
|
||||
#define S2S(x) case x: return #x
|
||||
|
||||
static const char *
|
||||
state2str(int state)
|
||||
{
|
||||
switch (state) {
|
||||
S2S(S_START);
|
||||
S2S(S_C);
|
||||
S2S(S_K);
|
||||
S2S(S_EMPTY);
|
||||
default:
|
||||
errx(1, "unknown state %d", state);
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
CBS ciphertext, shared_secret, private_key;
|
||||
const uint8_t *p;
|
||||
char *buf;
|
||||
CBB dk_cbb = { 0 }, c = { 0 }, k = { 0 };
|
||||
CBS instr;
|
||||
uint8_t *dk = NULL;
|
||||
size_t dk_len = 0;
|
||||
uint8_t bracket, newline;
|
||||
const char *test;
|
||||
size_t line;
|
||||
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");
|
||||
|
||||
if ((len = getline(&buf, &buflen, fp)) == -1)
|
||||
err(1, "failed to read instruction line");
|
||||
|
||||
/*
|
||||
* The private key is enclosed in brackets in an "instruction line".
|
||||
*/
|
||||
line = 1;
|
||||
CBS_init(&instr, buf, len);
|
||||
if (!CBS_get_u8(&instr, &bracket))
|
||||
err(1, "failed to parse instruction line '['");
|
||||
assert(bracket == '[');
|
||||
if (!CBS_get_last_u8(&instr, &newline))
|
||||
errx(1, "failed to parse instruction line '\\n'");
|
||||
assert(newline == '\n');
|
||||
if (!CBS_get_last_u8(&instr, &bracket))
|
||||
errx(1, "failed to parse instruction line ']'");
|
||||
assert(bracket == ']');
|
||||
if (!get_string_cbs(&instr, "dk: ", line, "private key"))
|
||||
errx(1, "failed to read instruction line 'dk: '");
|
||||
hex_decode_cbs(&instr, &dk_cbb, line, "private key");
|
||||
assert(CBS_len(&instr) == 0);
|
||||
|
||||
if (!CBB_finish(&dk_cbb, &dk, &dk_len))
|
||||
errx(1, "CBB finish instruction line");
|
||||
|
||||
state = S_START;
|
||||
|
||||
while ((len = getline(&buf, &buflen, fp)) != -1) {
|
||||
const char *msg = state2str(state);
|
||||
CBS cbs, dk_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');
|
||||
|
||||
fprintf(stderr, "Testing NIST 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_CIPHERTEXT;
|
||||
test_number = 1;
|
||||
while (fgets(buf, 16*1024, fp) != NULL) {
|
||||
switch (state) {
|
||||
case S_START:
|
||||
if (strcmp(buf, "\n") != 0)
|
||||
break;
|
||||
state = S_CIPHERTEXT;
|
||||
state = S_C;
|
||||
break;
|
||||
case S_CIPHERTEXT:
|
||||
if (strncmp(buf, "ciphertext: ",
|
||||
strlen("ciphertext: ")) != 0) {
|
||||
break;
|
||||
}
|
||||
grab_data(&ciphertext, buf, strlen("ciphertext: "));
|
||||
state = S_SHARED_SECRET;
|
||||
case S_C:
|
||||
if (!get_string_cbs(&cbs, "c: ", line, msg))
|
||||
errx(1, "#%zu %s: get_string_cbs", line, msg);
|
||||
hex_decode_cbs(&cbs, &c, line, msg);
|
||||
state = S_K;
|
||||
break;
|
||||
case S_SHARED_SECRET:
|
||||
if (strncmp(buf, "shared_secret: ",
|
||||
strlen("shared_secret: ")) != 0)
|
||||
break;
|
||||
grab_data(&shared_secret, buf,
|
||||
strlen("shared_secret: "));
|
||||
state = S_PRIVATE_KEY;
|
||||
case S_K:
|
||||
if (!get_string_cbs(&cbs, "k: ", line, msg))
|
||||
errx(1, "#%zu %s: get_string_cbs", line, msg);
|
||||
hex_decode_cbs(&cbs, &k, line, msg);
|
||||
state = S_EMPTY;
|
||||
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);
|
||||
case S_EMPTY:
|
||||
CBS_init(&dk_cbs, dk, dk_len);
|
||||
|
||||
MlkemNistDecapFileTest(&ciphertext, &shared_secret,
|
||||
&private_key);
|
||||
free((void *)CBS_data(&ciphertext));
|
||||
free((void *)CBS_data(&shared_secret));
|
||||
free((void *)p);
|
||||
failed |= MlkemNistDecapFileTest(&c, &k, &dk_cbs, line);
|
||||
|
||||
state = S_START;
|
||||
test_number++;
|
||||
state = S_C;
|
||||
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);
|
||||
|
||||
freezero(dk, dk_len);
|
||||
|
||||
return failed;
|
||||
}
|
||||
|
@ -1,7 +1,8 @@
|
||||
/* $OpenBSD: mlkem768_nist_keygen_tests.c,v 1.3 2024/12/17 07:20:10 tb Exp $ */
|
||||
/* $OpenBSD: mlkem768_nist_keygen_tests.c,v 1.4 2024/12/20 00:07:12 tb Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2024, Google Inc.
|
||||
* Copyright (c) 2024, Bob Beck <beck@obtuse.com>
|
||||
* Copyright (c) 2024 Google Inc.
|
||||
* Copyright (c) 2024 Bob Beck <beck@obtuse.com>
|
||||
* Copyright (c) 2024 Theo Buehler <tb@openbsd.org>
|
||||
*
|
||||
* 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,123 +17,181 @@
|
||||
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <err.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <openssl/bytestring.h>
|
||||
#include <openssl/mlkem.h>
|
||||
#include "bytestring.h"
|
||||
#include "mlkem.h"
|
||||
|
||||
#include "mlkem_internal.h"
|
||||
#include "mlkem_tests_util.h"
|
||||
|
||||
static int
|
||||
encode_private_key(const struct MLKEM768_private_key *priv, uint8_t **out_buf,
|
||||
size_t *out_len)
|
||||
{
|
||||
CBB cbb;
|
||||
if (!CBB_init(&cbb, MLKEM768_PUBLIC_KEY_BYTES))
|
||||
return 0;
|
||||
if (!MLKEM768_marshal_private_key(&cbb, priv))
|
||||
return 0;
|
||||
if (!CBB_finish(&cbb, out_buf, out_len))
|
||||
return 0;
|
||||
CBB_cleanup(&cbb);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void
|
||||
MlkemNistKeygenFileTest(CBS *z, CBS *d, CBS *ek, CBS *dk)
|
||||
MlkemNistKeygenFileTest(CBB *z_cbb, CBB *d_cbb, CBB *ek_cbb, CBB *dk_cbb,
|
||||
size_t line)
|
||||
{
|
||||
CBB seed_cbb;
|
||||
uint8_t *z = NULL, *d = NULL, *ek = NULL, *dk = NULL;
|
||||
size_t z_len = 0, d_len = 0, ek_len = 0, dk_len = 0;
|
||||
uint8_t seed[MLKEM_SEED_BYTES];
|
||||
struct MLKEM768_private_key priv;
|
||||
uint8_t *encoded_private_key = NULL;
|
||||
uint8_t encoded_public_key[MLKEM768_PUBLIC_KEY_BYTES];
|
||||
size_t len;
|
||||
int failed = 1;
|
||||
|
||||
if (!CBB_init_fixed(&seed_cbb, seed, sizeof(seed)))
|
||||
goto err;
|
||||
|
||||
if (!CBB_finish(z_cbb, &z, &z_len))
|
||||
goto err;
|
||||
if (!CBB_finish(d_cbb, &d, &d_len))
|
||||
goto err;
|
||||
if (!CBB_finish(ek_cbb, &ek, &ek_len))
|
||||
goto err;
|
||||
if (!CBB_finish(dk_cbb, &dk, &dk_len))
|
||||
goto err;
|
||||
|
||||
if (!CBB_add_bytes(&seed_cbb, d, d_len))
|
||||
goto err;
|
||||
if (!CBB_add_bytes(&seed_cbb, z, z_len))
|
||||
goto err;
|
||||
if (!CBB_finish(&seed_cbb, NULL, &len))
|
||||
goto err;
|
||||
|
||||
if (!compare_length(MLKEM_SEED_BYTES, len, line, "z or d length bogus"))
|
||||
goto err;
|
||||
|
||||
TEST(CBS_len(d) != (MLKEM_SEED_BYTES / 2), "d len bogus");
|
||||
TEST(CBS_len(z) != (MLKEM_SEED_BYTES / 2), "z len bogus");
|
||||
TEST(CBS_len(dk) != MLKEM768_PRIVATE_KEY_BYTES,
|
||||
"expected private key len bogus");
|
||||
TEST(CBS_len(ek) != MLKEM768_PUBLIC_KEY_BYTES,
|
||||
"expected public key len bogus");
|
||||
memcpy(&seed[0], CBS_data(d), CBS_len(d));
|
||||
memcpy(&seed[MLKEM_SEED_BYTES / 2], CBS_data(z), CBS_len(z));
|
||||
MLKEM768_generate_key_external_entropy(encoded_public_key, &priv, seed);
|
||||
TEST(!encode_private_key(&priv, &encoded_private_key,
|
||||
&len), "encode_private_key");
|
||||
TEST(len != MLKEM768_PRIVATE_KEY_BYTES, "private key len bogus");
|
||||
TEST_DATAEQ(encoded_public_key, CBS_data(ek),
|
||||
MLKEM768_PUBLIC_KEY_BYTES, "public key");
|
||||
TEST_DATAEQ(encoded_private_key, CBS_data(dk),
|
||||
MLKEM768_PRIVATE_KEY_BYTES, "private key");
|
||||
|
||||
if (!mlkem768_encode_private_key(&priv, &encoded_private_key, &len)) {
|
||||
warnx("#%zu mlkem768_encode_private_key", line);
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (!compare_length(MLKEM768_PRIVATE_KEY_BYTES, len, line,
|
||||
"private key length"))
|
||||
goto err;
|
||||
|
||||
failed = compare_data(ek, encoded_public_key, MLKEM768_PUBLIC_KEY_BYTES,
|
||||
line, "public key");
|
||||
failed |= compare_data(dk, encoded_private_key, MLKEM768_PRIVATE_KEY_BYTES,
|
||||
line, "private key");
|
||||
|
||||
err:
|
||||
CBB_cleanup(&seed_cbb);
|
||||
CBB_cleanup(z_cbb);
|
||||
CBB_cleanup(d_cbb);
|
||||
CBB_cleanup(ek_cbb);
|
||||
CBB_cleanup(dk_cbb);
|
||||
freezero(z, z_len);
|
||||
freezero(d, d_len);
|
||||
freezero(ek, ek_len);
|
||||
freezero(dk, dk_len);
|
||||
free(encoded_private_key);
|
||||
|
||||
return failed;
|
||||
}
|
||||
|
||||
#define S_START 0
|
||||
#define S_Z 1
|
||||
#define S_D 2
|
||||
#define S_EK 3
|
||||
#define S_DK 4
|
||||
#define S_START 0
|
||||
#define S_Z 1
|
||||
#define S_D 2
|
||||
#define S_EK 3
|
||||
#define S_DK 4
|
||||
|
||||
#define S2S(x) case x: return #x
|
||||
|
||||
static const char *
|
||||
state2str(int state)
|
||||
{
|
||||
switch (state) {
|
||||
S2S(S_START);
|
||||
S2S(S_Z);
|
||||
S2S(S_D);
|
||||
S2S(S_EK);
|
||||
S2S(S_DK);
|
||||
default:
|
||||
errx(1, "unknown state %d", state);
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
CBS z, d, ek, dk;
|
||||
char *buf;
|
||||
CBB z = { 0 }, d = { 0 }, ek = { 0 }, dk = { 0 };
|
||||
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 NIST keygen 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_Z;
|
||||
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_Z;
|
||||
break;
|
||||
case S_Z:
|
||||
if (strncmp(buf, "z: ", strlen("z: ")) != 0) {
|
||||
break;
|
||||
}
|
||||
grab_data(&z, buf, strlen("z: "));
|
||||
if (!get_string_cbs(&cbs, "z: ", line, msg))
|
||||
errx(1, "#%zu %s: get_string_cbs", line, msg);
|
||||
hex_decode_cbs(&cbs, &z, line, msg);
|
||||
state = S_D;
|
||||
break;
|
||||
case S_D:
|
||||
if (strncmp(buf, "d: ", strlen("d: ")) != 0)
|
||||
break;
|
||||
grab_data(&d, buf, strlen("d: "));
|
||||
if (!get_string_cbs(&cbs, "d: ", line, msg))
|
||||
errx(1, "#%zu %s: get_string_cbs", line, msg);
|
||||
hex_decode_cbs(&cbs, &d, line, msg);
|
||||
state = S_EK;
|
||||
break;
|
||||
case S_EK:
|
||||
if (strncmp(buf, "ek: ", strlen("ek: ")) != 0)
|
||||
break;
|
||||
grab_data(&ek, buf, strlen("ek: "));
|
||||
if (!get_string_cbs(&cbs, "ek: ", line, msg))
|
||||
errx(1, "#%zu %s: get_string_cbs", line, msg);
|
||||
hex_decode_cbs(&cbs, &ek, line, msg);
|
||||
state = S_DK;
|
||||
break;
|
||||
case S_DK:
|
||||
if (strncmp(buf, "dk: ", strlen("dk: ")) != 0)
|
||||
break;
|
||||
grab_data(&dk, buf, strlen("dk: "));
|
||||
if (!get_string_cbs(&cbs, "dk: ", line, msg))
|
||||
errx(1, "#%zu %s: get_string_cbs", line, msg);
|
||||
hex_decode_cbs(&cbs, &dk, line, msg);
|
||||
|
||||
MlkemNistKeygenFileTest(&z, &d, &ek, &dk);
|
||||
free((void *)CBS_data(&z));
|
||||
free((void *)CBS_data(&d));
|
||||
free((void *)CBS_data(&ek));
|
||||
free((void *)CBS_data(&dk));
|
||||
failed |= MlkemNistKeygenFileTest(&z, &d, &ek, &dk, line);
|
||||
|
||||
test_number++;
|
||||
state = S_START;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
free(buf);
|
||||
|
||||
if (ferror(fp))
|
||||
err(1, NULL);
|
||||
fclose(fp);
|
||||
exit(failure);
|
||||
|
||||
return failed;
|
||||
}
|
||||
|
@ -1,7 +1,8 @@
|
||||
/* $OpenBSD: mlkem_tests_util.c,v 1.2 2024/12/14 19:16:24 tb Exp $ */
|
||||
/* $OpenBSD: mlkem_tests_util.c,v 1.3 2024/12/20 00:07:12 tb Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2024, Google Inc.
|
||||
* Copyright (c) 2024, Bob Beck <beck@obtuse.com>
|
||||
* Copyright (c) 2024 Google Inc.
|
||||
* Copyright (c) 2024 Bob Beck <beck@obtuse.com>
|
||||
* Copyright (c) 2024 Theo Buehler <tb@openbsd.org>
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
@ -19,15 +20,19 @@
|
||||
#include <err.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "bytestring.h"
|
||||
#include "mlkem.h"
|
||||
|
||||
#include "mlkem_internal.h"
|
||||
|
||||
#include "mlkem_tests_util.h"
|
||||
|
||||
int failure;
|
||||
int test_number;
|
||||
|
||||
void
|
||||
static void
|
||||
hexdump(const uint8_t *buf, size_t len, const uint8_t *compare)
|
||||
{
|
||||
const char *mark = "";
|
||||
@ -43,32 +48,171 @@ hexdump(const uint8_t *buf, size_t len, const uint8_t *compare)
|
||||
}
|
||||
|
||||
int
|
||||
hex_decode(char *buf, size_t len, uint8_t **out_buf, size_t *out_len)
|
||||
compare_data(const uint8_t *want, const uint8_t *got, size_t len, size_t line,
|
||||
const char *msg)
|
||||
{
|
||||
size_t i;
|
||||
if (*out_buf != NULL)
|
||||
abort(); /* Du hast einin rotweinflarsche... */
|
||||
if (memcmp(want, got, len) == 0)
|
||||
return 0;
|
||||
|
||||
MALLOC(*out_buf, len);
|
||||
*out_len = 0;
|
||||
warnx("FAIL: #%zu - %s differs", line, msg);
|
||||
fprintf(stderr, "want:\n");
|
||||
hexdump(want, len, got);
|
||||
fprintf(stderr, "got:\n");
|
||||
hexdump(got, len, want);
|
||||
fprintf(stderr, "\n");
|
||||
|
||||
for (i = 0; i < len; i += 2) {
|
||||
if (sscanf(buf + i, "%2hhx", *out_buf + *out_len) != 1)
|
||||
err(1, "FAIL- hex decode failed for %d\n",
|
||||
(int)*out_len);
|
||||
(*out_len)++;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
void
|
||||
grab_data(CBS *cbs, char *buf, size_t offset)
|
||||
int
|
||||
compare_length(size_t want, size_t got, size_t line, const char *msg)
|
||||
{
|
||||
char *start = buf + offset;
|
||||
size_t len = strlen(start);
|
||||
uint8_t *new = NULL;
|
||||
size_t new_len = 0;
|
||||
/* This is hex encoded - decode it. */
|
||||
TEST(!hex_decode(start, len - 1, &new, &new_len), "hex decode failed");
|
||||
CBS_init(cbs, new, new_len);
|
||||
if (want == got)
|
||||
return 1;
|
||||
|
||||
warnx("#%zu: %s: want %zu, got %zu", line, msg, want, got);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
hex_get_nibble_cbs(CBS *cbs, uint8_t *out_nibble)
|
||||
{
|
||||
uint8_t c;
|
||||
|
||||
if (!CBS_get_u8(cbs, &c))
|
||||
return 0;
|
||||
|
||||
if (c >= '0' && c <= '9') {
|
||||
*out_nibble = c - '0';
|
||||
return 1;
|
||||
}
|
||||
if (c >= 'a' && c <= 'f') {
|
||||
*out_nibble = c - 'a' + 10;
|
||||
return 1;
|
||||
}
|
||||
if (c >= 'A' && c <= 'F') {
|
||||
*out_nibble = c - 'A' + 10;
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
hex_decode_cbs(CBS *cbs, CBB *cbb, size_t line, const char *msg)
|
||||
{
|
||||
if (!CBB_init(cbb, 0))
|
||||
errx(1, "#%zu %s: %s CBB_init", line, msg, __func__);
|
||||
|
||||
while (CBS_len(cbs) > 0) {
|
||||
uint8_t hi, lo;
|
||||
|
||||
if (!hex_get_nibble_cbs(cbs, &hi))
|
||||
errx(1, "#%zu %s: %s nibble", line, msg, __func__);
|
||||
if (!hex_get_nibble_cbs(cbs, &lo))
|
||||
errx(1, "#%zu %s: %s nibble", line, msg, __func__);
|
||||
|
||||
if (!CBB_add_u8(cbb, hi << 4 | lo))
|
||||
errx(1, "#%zu %s: %s CBB_add_u8", line, msg, __func__);
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
get_string_cbs(CBS *cbs_in, const char *str, size_t line, const char *msg)
|
||||
{
|
||||
CBS cbs;
|
||||
size_t len = strlen(str);
|
||||
|
||||
if (!CBS_get_bytes(cbs_in, &cbs, len))
|
||||
errx(1, "#%zu %s: %s CBB_get_bytes", line, msg, __func__);
|
||||
|
||||
return CBS_mem_equal(&cbs, str, len);
|
||||
}
|
||||
|
||||
int
|
||||
mlkem768_encode_private_key(const struct MLKEM768_private_key *priv,
|
||||
uint8_t **out_buf, size_t *out_len)
|
||||
{
|
||||
CBB cbb;
|
||||
int ret = 0;
|
||||
|
||||
if (!CBB_init(&cbb, MLKEM768_PUBLIC_KEY_BYTES))
|
||||
goto err;
|
||||
if (!MLKEM768_marshal_private_key(&cbb, priv))
|
||||
goto err;
|
||||
if (!CBB_finish(&cbb, out_buf, out_len))
|
||||
goto err;
|
||||
|
||||
ret = 1;
|
||||
|
||||
err:
|
||||
CBB_cleanup(&cbb);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int
|
||||
mlkem768_encode_public_key(const struct MLKEM768_public_key *pub,
|
||||
uint8_t **out_buf, size_t *out_len)
|
||||
{
|
||||
CBB cbb;
|
||||
int ret = 0;
|
||||
|
||||
if (!CBB_init(&cbb, MLKEM768_PUBLIC_KEY_BYTES))
|
||||
goto err;
|
||||
if (!MLKEM768_marshal_public_key(&cbb, pub))
|
||||
goto err;
|
||||
if (!CBB_finish(&cbb, out_buf, out_len))
|
||||
goto err;
|
||||
|
||||
ret = 1;
|
||||
|
||||
err:
|
||||
CBB_cleanup(&cbb);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int
|
||||
mlkem1024_encode_private_key(const struct MLKEM1024_private_key *priv,
|
||||
uint8_t **out_buf, size_t *out_len)
|
||||
{
|
||||
CBB cbb;
|
||||
int ret = 0;
|
||||
|
||||
if (!CBB_init(&cbb, MLKEM1024_PUBLIC_KEY_BYTES))
|
||||
goto err;
|
||||
if (!MLKEM1024_marshal_private_key(&cbb, priv))
|
||||
goto err;
|
||||
if (!CBB_finish(&cbb, out_buf, out_len))
|
||||
goto err;
|
||||
|
||||
ret = 1;
|
||||
|
||||
err:
|
||||
CBB_cleanup(&cbb);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int
|
||||
mlkem1024_encode_public_key(const struct MLKEM1024_public_key *pub,
|
||||
uint8_t **out_buf, size_t *out_len)
|
||||
{
|
||||
CBB cbb;
|
||||
int ret = 0;
|
||||
|
||||
if (!CBB_init(&cbb, MLKEM1024_PUBLIC_KEY_BYTES))
|
||||
goto err;
|
||||
if (!MLKEM1024_marshal_public_key(&cbb, pub))
|
||||
goto err;
|
||||
if (!CBB_finish(&cbb, out_buf, out_len))
|
||||
goto err;
|
||||
|
||||
ret = 1;
|
||||
|
||||
err:
|
||||
CBB_cleanup(&cbb);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
/* $OpenBSD: mlkem_tests_util.h,v 1.2 2024/12/14 19:16:24 tb Exp $ */
|
||||
/* $OpenBSD: mlkem_tests_util.h,v 1.3 2024/12/20 00:07:12 tb Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2024, Bob Beck <beck@obtuse.com>
|
||||
* Copyright (c) 2024 Bob Beck <beck@obtuse.com>
|
||||
* Copyright (c) 2024 Theo Buehler <tb@openbsd.org>
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
@ -18,47 +19,31 @@
|
||||
#ifndef MLKEM_TEST_UTIL_H
|
||||
#define MLKEM_TEST_UTIL_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <openssl/bytestring.h>
|
||||
#include "bytestring.h"
|
||||
|
||||
#define TEST(cond, msg) do { \
|
||||
if ((cond)) { \
|
||||
failure = 1; \
|
||||
fprintf(stderr, "FAIL: %s:%d - Test %d: %s\n", \
|
||||
__FILE__, __LINE__, test_number, msg); \
|
||||
} \
|
||||
} while(0)
|
||||
struct MLKEM1024_private_key;
|
||||
struct MLKEM1024_public_key;
|
||||
struct MLKEM768_private_key;
|
||||
struct MLKEM768_public_key;
|
||||
|
||||
#define MALLOC(A, B) do { \
|
||||
if (((A) = malloc(B)) == NULL) { \
|
||||
failure = 1; \
|
||||
fprintf(stderr, "FAIL: %s:%d - Test %d: malloc\n", \
|
||||
__FILE__, __LINE__, test_number); \
|
||||
exit(1); \
|
||||
} \
|
||||
} while(0)
|
||||
/* XXX - return values of the two compare functions are inconsistent */
|
||||
int compare_data(const uint8_t *want, const uint8_t *got, size_t len,
|
||||
size_t line, const char *msg);
|
||||
int compare_length(size_t want, size_t got, size_t line, const char *msg);
|
||||
|
||||
#define TEST_DATAEQ(values, expected, len, msg) do { \
|
||||
if (memcmp((values), (expected), (len)) != 0) { \
|
||||
failure = 1; \
|
||||
fprintf(stderr, "FAIL: %s:%d - Test %d: %s differs\n", \
|
||||
__FILE__, __LINE__, test_number, msg); \
|
||||
fprintf(stderr, "values:\n"); \
|
||||
hexdump(values, len, expected); \
|
||||
fprintf(stderr, "expected:\n"); \
|
||||
hexdump(expected, len, values); \
|
||||
fprintf(stderr, "\n"); \
|
||||
} \
|
||||
} while(0)
|
||||
void hex_decode_cbs(CBS *cbs, CBB *cbb, size_t line, const char *msg);
|
||||
int get_string_cbs(CBS *cbs, const char *str, size_t line, const char *msg);
|
||||
|
||||
extern int failure, test_number;
|
||||
int mlkem768_encode_private_key(const struct MLKEM768_private_key *priv,
|
||||
uint8_t **out_buf, size_t *out_len);
|
||||
int mlkem768_encode_public_key(const struct MLKEM768_public_key *pub,
|
||||
uint8_t **out_buf, size_t *out_len);
|
||||
int mlkem1024_encode_private_key(const struct MLKEM1024_private_key *priv,
|
||||
uint8_t **out_buf, size_t *out_len);
|
||||
int mlkem1024_encode_public_key(const struct MLKEM1024_public_key *pub,
|
||||
uint8_t **out_buf, size_t *out_len);
|
||||
|
||||
void hexdump(const uint8_t *buf, size_t len, const uint8_t *compare);
|
||||
int hex_decode(char *buf, size_t len, uint8_t **out_buf, size_t *out_len);
|
||||
void grab_data(CBS *cbs, char *buf, size_t offset);
|
||||
|
||||
#endif
|
||||
#endif /* MLKEM_TEST_UTIL_H */
|
||||
|
@ -1,7 +1,7 @@
|
||||
/* $OpenBSD: mlkem_unittest.c,v 1.3 2024/12/14 19:16:24 tb Exp $ */
|
||||
/* $OpenBSD: mlkem_unittest.c,v 1.4 2024/12/20 00:07:12 tb Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2024, Google Inc.
|
||||
* Copyright (c) 2024, Bob Beck <beck@obtuse.com>
|
||||
* Copyright (c) 2024 Google Inc.
|
||||
* Copyright (c) 2024 Bob Beck <beck@obtuse.com>
|
||||
*
|
||||
* 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,52 +16,22 @@
|
||||
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <err.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <openssl/bytestring.h>
|
||||
#include <openssl/mlkem.h>
|
||||
#include "bytestring.h"
|
||||
#include "mlkem.h"
|
||||
|
||||
#include "mlkem_internal.h"
|
||||
#include "mlkem_tests_util.h"
|
||||
|
||||
static int
|
||||
encode_public_key(const struct MLKEM768_public_key *pub, uint8_t **out_buf,
|
||||
size_t *out_len)
|
||||
MlKem768UnitTest(void)
|
||||
{
|
||||
CBB cbb;
|
||||
if (!CBB_init(&cbb, MLKEM768_PUBLIC_KEY_BYTES))
|
||||
return 0;
|
||||
if (!MLKEM768_marshal_public_key(&cbb, pub))
|
||||
return 0;
|
||||
if (!CBB_finish(&cbb, out_buf, out_len))
|
||||
return 0;
|
||||
CBB_cleanup(&cbb);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
encode_private_key(const struct MLKEM768_private_key *priv, uint8_t **out_buf,
|
||||
size_t *out_len)
|
||||
{
|
||||
CBB cbb;
|
||||
if (!CBB_init(&cbb, MLKEM768_PUBLIC_KEY_BYTES))
|
||||
return 0;
|
||||
if (!MLKEM768_marshal_private_key(&cbb, priv))
|
||||
return 0;
|
||||
if (!CBB_finish(&cbb, out_buf, out_len))
|
||||
return 0;
|
||||
CBB_cleanup(&cbb);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void
|
||||
MlKem768UnitTest()
|
||||
{
|
||||
struct MLKEM768_private_key *priv, *priv2;
|
||||
struct MLKEM768_public_key *pub, *pub2;
|
||||
struct MLKEM768_private_key priv = { 0 }, priv2 = { 0 };
|
||||
struct MLKEM768_public_key pub = { 0 }, pub2 = { 0 };
|
||||
uint8_t encoded_public_key[MLKEM768_PUBLIC_KEY_BYTES];
|
||||
uint8_t ciphertext[MLKEM768_CIPHERTEXT_BYTES];
|
||||
uint8_t shared_secret1[MLKEM_SHARED_SECRET_BYTES];
|
||||
@ -70,123 +40,138 @@ MlKem768UnitTest()
|
||||
uint8_t *encoded_private_key = NULL, *tmp_buf = NULL;
|
||||
size_t encoded_private_key_len, tmp_buf_len;
|
||||
CBS cbs;
|
||||
int failed = 0;
|
||||
|
||||
fprintf(stderr, "ML-KEM 768...\n");
|
||||
|
||||
MALLOC(priv, sizeof(struct MLKEM768_private_key));
|
||||
MLKEM768_generate_key(encoded_public_key, NULL, priv);
|
||||
MLKEM768_generate_key(encoded_public_key, NULL, &priv);
|
||||
|
||||
memcpy(first_two_bytes, encoded_public_key, sizeof(first_two_bytes));
|
||||
memset(encoded_public_key, 0xff, sizeof(first_two_bytes));
|
||||
CBS_init(&cbs, encoded_public_key,
|
||||
sizeof(encoded_public_key));
|
||||
MALLOC(pub, sizeof(struct MLKEM768_public_key));
|
||||
/* Parsing should fail because the first coefficient is >= kPrime; */
|
||||
TEST(MLKEM768_parse_public_key(pub, &cbs),
|
||||
"Kyber_parse_public_key should have failed");
|
||||
|
||||
CBS_init(&cbs, encoded_public_key, sizeof(encoded_public_key));
|
||||
|
||||
/* Parsing should fail because the first coefficient is >= kPrime. */
|
||||
if (MLKEM768_parse_public_key(&pub, &cbs)) {
|
||||
warnx("MLKEM768_parse_public_key should have failed");
|
||||
failed |= 1;
|
||||
}
|
||||
|
||||
memcpy(encoded_public_key, first_two_bytes, sizeof(first_two_bytes));
|
||||
CBS_init(&cbs, encoded_public_key, sizeof(encoded_public_key));
|
||||
TEST(!MLKEM768_parse_public_key(pub, &cbs),
|
||||
"MLKEM768_parse_public_key");
|
||||
TEST(CBS_len(&cbs) != 0u, "CBS_len must be 0");
|
||||
if (!MLKEM768_parse_public_key(&pub, &cbs)) {
|
||||
warnx("MLKEM768_parse_public_key");
|
||||
failed |= 1;
|
||||
}
|
||||
|
||||
TEST(!encode_public_key(pub, &tmp_buf, &tmp_buf_len),
|
||||
"encode_public_key");
|
||||
TEST(sizeof(encoded_public_key) != tmp_buf_len,
|
||||
"encoded public key lengths differ");
|
||||
TEST_DATAEQ(tmp_buf, encoded_public_key, tmp_buf_len,
|
||||
"encoded public keys");
|
||||
if (CBS_len(&cbs) != 0u) {
|
||||
warnx("CBS_len must be 0");
|
||||
failed |= 1;
|
||||
}
|
||||
|
||||
if (!mlkem768_encode_public_key(&pub, &tmp_buf, &tmp_buf_len)) {
|
||||
warnx("encode_public_key");
|
||||
failed |= 1;
|
||||
}
|
||||
if (sizeof(encoded_public_key) != tmp_buf_len) {
|
||||
warnx("mlkem768 encoded public key lengths differ");
|
||||
failed |= 1;
|
||||
}
|
||||
|
||||
if (compare_data(encoded_public_key, tmp_buf, tmp_buf_len, 768,
|
||||
"encoded public keys") != 0) {
|
||||
warnx("compare_data");
|
||||
failed |= 1;
|
||||
}
|
||||
free(tmp_buf);
|
||||
tmp_buf = NULL;
|
||||
|
||||
MALLOC(pub2, sizeof(struct MLKEM768_public_key));
|
||||
MLKEM768_public_from_private(pub2, priv);
|
||||
TEST(!encode_public_key(pub2, &tmp_buf, &tmp_buf_len),
|
||||
"encode_public_key");
|
||||
TEST(sizeof(encoded_public_key) != tmp_buf_len,
|
||||
"encoded public key lengths differ");
|
||||
TEST_DATAEQ(tmp_buf, encoded_public_key, tmp_buf_len,
|
||||
"encoded pubic keys");
|
||||
MLKEM768_public_from_private(&pub2, &priv);
|
||||
if (!mlkem768_encode_public_key(&pub2, &tmp_buf, &tmp_buf_len)) {
|
||||
warnx("mlkem768_encode_public_key");
|
||||
failed |= 1;
|
||||
}
|
||||
if (sizeof(encoded_public_key) != tmp_buf_len) {
|
||||
warnx("mlkem768 encoded public key lengths differ");
|
||||
failed |= 1;
|
||||
}
|
||||
|
||||
if (compare_data(encoded_public_key, tmp_buf, tmp_buf_len, 768,
|
||||
"encoded public keys") != 0) {
|
||||
warnx("compare_data");
|
||||
failed |= 1;
|
||||
}
|
||||
free(tmp_buf);
|
||||
tmp_buf = NULL;
|
||||
|
||||
TEST(!encode_private_key(priv, &encoded_private_key,
|
||||
&encoded_private_key_len), "encode_private_key");
|
||||
if (!mlkem768_encode_private_key(&priv, &encoded_private_key,
|
||||
&encoded_private_key_len)) {
|
||||
warnx("mlkem768_encode_private_key");
|
||||
failed |= 1;
|
||||
}
|
||||
|
||||
memcpy(first_two_bytes, encoded_private_key, sizeof(first_two_bytes));
|
||||
memset(encoded_private_key, 0xff, sizeof(first_two_bytes));
|
||||
CBS_init(&cbs, encoded_private_key, encoded_private_key_len);
|
||||
MALLOC(priv2, sizeof(struct MLKEM768_private_key));
|
||||
|
||||
/* Parsing should fail because the first coefficient is >= kPrime. */
|
||||
TEST(MLKEM768_parse_private_key(priv2, &cbs), "Should not have parsed");
|
||||
if (MLKEM768_parse_private_key(&priv2, &cbs)) {
|
||||
warnx("MLKEM768_parse_private_key should have failed");
|
||||
failed |= 1;
|
||||
}
|
||||
|
||||
memcpy(encoded_private_key, first_two_bytes, sizeof(first_two_bytes));
|
||||
CBS_init(&cbs, encoded_private_key, encoded_private_key_len);
|
||||
TEST(!MLKEM768_parse_private_key(priv2, &cbs),
|
||||
"MLKEM768_parse_private_key");
|
||||
TEST(!encode_private_key(priv2, &tmp_buf, &tmp_buf_len),
|
||||
"encode_private_key");
|
||||
TEST(encoded_private_key_len != tmp_buf_len,
|
||||
"encoded private key lengths differ");
|
||||
TEST_DATAEQ(tmp_buf, encoded_private_key, encoded_private_key_len,
|
||||
"encoded private keys");
|
||||
|
||||
if (!MLKEM768_parse_private_key(&priv2, &cbs)) {
|
||||
warnx("MLKEM768_parse_private_key");
|
||||
failed |= 1;
|
||||
}
|
||||
|
||||
if (!mlkem768_encode_private_key(&priv2, &tmp_buf, &tmp_buf_len)) {
|
||||
warnx("mlkem768_encode_private_key");
|
||||
failed |= 1;
|
||||
}
|
||||
|
||||
if (encoded_private_key_len != tmp_buf_len) {
|
||||
warnx("mlkem768 encode private key lengths differ");
|
||||
failed |= 1;
|
||||
}
|
||||
|
||||
if (compare_data(encoded_private_key, tmp_buf, tmp_buf_len, 768,
|
||||
"encoded private key") != 0) {
|
||||
warnx("compare_data");
|
||||
failed |= 1;
|
||||
}
|
||||
|
||||
free(tmp_buf);
|
||||
tmp_buf = NULL;
|
||||
|
||||
MLKEM768_encap(ciphertext, shared_secret1, pub);
|
||||
MLKEM768_encap(ciphertext, shared_secret1, &pub);
|
||||
MLKEM768_decap(shared_secret2, ciphertext, MLKEM768_CIPHERTEXT_BYTES,
|
||||
priv);
|
||||
TEST_DATAEQ(shared_secret1, shared_secret2, MLKEM_SHARED_SECRET_BYTES,
|
||||
"shared secrets with priv");
|
||||
&priv);
|
||||
if (compare_data(shared_secret1, shared_secret2, MLKEM_SHARED_SECRET_BYTES,
|
||||
768, "shared secrets with priv") != 0) {
|
||||
warnx("compare_data");
|
||||
failed |= 1;
|
||||
}
|
||||
|
||||
MLKEM768_decap(shared_secret2, ciphertext, MLKEM768_CIPHERTEXT_BYTES,
|
||||
priv2);
|
||||
TEST_DATAEQ(shared_secret1, shared_secret2, MLKEM_SHARED_SECRET_BYTES,
|
||||
"shared secrets with priv2");
|
||||
&priv2);
|
||||
if (compare_data(shared_secret1, shared_secret2, MLKEM_SHARED_SECRET_BYTES,
|
||||
768, "shared secrets with priv2") != 0) {
|
||||
warnx("compare_data");
|
||||
failed |= 1;
|
||||
}
|
||||
|
||||
free(encoded_private_key);
|
||||
free(pub);
|
||||
free(pub2);
|
||||
free(priv);
|
||||
free(priv2);
|
||||
|
||||
return failed;
|
||||
}
|
||||
|
||||
static int
|
||||
encode_1024public_key(const struct MLKEM1024_public_key *pub, uint8_t **out_buf,
|
||||
size_t *out_len)
|
||||
MlKem1024UnitTest(void)
|
||||
{
|
||||
CBB cbb;
|
||||
if (!CBB_init(&cbb, MLKEM1024_PUBLIC_KEY_BYTES))
|
||||
return 0;
|
||||
if (!MLKEM1024_marshal_public_key(&cbb, pub))
|
||||
return 0;
|
||||
if (!CBB_finish(&cbb, out_buf, out_len))
|
||||
return 0;
|
||||
CBB_cleanup(&cbb);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
encode_1024private_key(const struct MLKEM1024_private_key *priv, uint8_t **out_buf,
|
||||
size_t *out_len)
|
||||
{
|
||||
CBB cbb;
|
||||
if (!CBB_init(&cbb, MLKEM1024_PUBLIC_KEY_BYTES))
|
||||
return 0;
|
||||
if (!MLKEM1024_marshal_private_key(&cbb, priv))
|
||||
return 0;
|
||||
if (!CBB_finish(&cbb, out_buf, out_len))
|
||||
return 0;
|
||||
CBB_cleanup(&cbb);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void
|
||||
MlKem1024UnitTest()
|
||||
{
|
||||
struct MLKEM1024_private_key *priv, *priv2;
|
||||
struct MLKEM1024_public_key *pub, *pub2;
|
||||
struct MLKEM1024_private_key priv = { 0 }, priv2 = { 0 };
|
||||
struct MLKEM1024_public_key pub = { 0 }, pub2 = { 0 };
|
||||
uint8_t encoded_public_key[MLKEM1024_PUBLIC_KEY_BYTES];
|
||||
uint8_t ciphertext[MLKEM1024_CIPHERTEXT_BYTES];
|
||||
uint8_t shared_secret1[MLKEM_SHARED_SECRET_BYTES];
|
||||
@ -195,92 +180,140 @@ MlKem1024UnitTest()
|
||||
uint8_t *encoded_private_key = NULL, *tmp_buf = NULL;
|
||||
size_t encoded_private_key_len, tmp_buf_len;
|
||||
CBS cbs;
|
||||
int failed = 0;
|
||||
|
||||
fprintf(stderr, "ML-KEM 1024...\n");
|
||||
|
||||
MALLOC(priv, sizeof(struct MLKEM1024_private_key));
|
||||
MLKEM1024_generate_key(encoded_public_key, NULL, priv);
|
||||
MLKEM1024_generate_key(encoded_public_key, NULL, &priv);
|
||||
|
||||
memcpy(first_two_bytes, encoded_public_key, sizeof(first_two_bytes));
|
||||
memset(encoded_public_key, 0xff, sizeof(first_two_bytes));
|
||||
CBS_init(&cbs, encoded_public_key,
|
||||
sizeof(encoded_public_key));
|
||||
MALLOC(pub, sizeof(struct MLKEM1024_public_key));
|
||||
/* Parsing should fail because the first coefficient is >= kPrime; */
|
||||
TEST(MLKEM1024_parse_public_key(pub, &cbs),
|
||||
"Kyber_parse_public_key should have failed");
|
||||
|
||||
CBS_init(&cbs, encoded_public_key, sizeof(encoded_public_key));
|
||||
|
||||
/* Parsing should fail because the first coefficient is >= kPrime. */
|
||||
if (MLKEM1024_parse_public_key(&pub, &cbs)) {
|
||||
warnx("MLKEM1024_parse_public_key should have failed");
|
||||
failed |= 1;
|
||||
}
|
||||
|
||||
memcpy(encoded_public_key, first_two_bytes, sizeof(first_two_bytes));
|
||||
CBS_init(&cbs, encoded_public_key, sizeof(encoded_public_key));
|
||||
TEST(!MLKEM1024_parse_public_key(pub, &cbs),
|
||||
"MLKEM1024_parse_public_key");
|
||||
TEST(CBS_len(&cbs) != 0u, "CBS_len must be 0");
|
||||
if (!MLKEM1024_parse_public_key(&pub, &cbs)) {
|
||||
warnx("MLKEM1024_parse_public_key");
|
||||
failed |= 1;
|
||||
}
|
||||
|
||||
TEST(!encode_1024public_key(pub, &tmp_buf, &tmp_buf_len),
|
||||
"encode_1024public_key");
|
||||
TEST(sizeof(encoded_public_key) != tmp_buf_len,
|
||||
"encoded public key lengths differ");
|
||||
TEST_DATAEQ(tmp_buf, encoded_public_key, tmp_buf_len,
|
||||
"encoded public keys");
|
||||
if (CBS_len(&cbs) != 0u) {
|
||||
warnx("CBS_len must be 0");
|
||||
failed |= 1;
|
||||
}
|
||||
|
||||
if (!mlkem1024_encode_public_key(&pub, &tmp_buf, &tmp_buf_len)) {
|
||||
warnx("encode_public_key");
|
||||
failed |= 1;
|
||||
}
|
||||
if (sizeof(encoded_public_key) != tmp_buf_len) {
|
||||
warnx("mlkem1024 encoded public key lengths differ");
|
||||
failed |= 1;
|
||||
}
|
||||
|
||||
if (compare_data(encoded_public_key, tmp_buf, tmp_buf_len, 1024,
|
||||
"encoded public keys") != 0) {
|
||||
warnx("compare_data");
|
||||
failed |= 1;
|
||||
}
|
||||
free(tmp_buf);
|
||||
tmp_buf = NULL;
|
||||
|
||||
MALLOC(pub2, sizeof(struct MLKEM1024_public_key));
|
||||
MLKEM1024_public_from_private(pub2, priv);
|
||||
TEST(!encode_1024public_key(pub2, &tmp_buf, &tmp_buf_len),
|
||||
"encode_public_key");
|
||||
TEST(sizeof(encoded_public_key) != tmp_buf_len,
|
||||
"encoded public key lengths differ");
|
||||
TEST_DATAEQ(tmp_buf, encoded_public_key, tmp_buf_len,
|
||||
"encoded pubic keys");
|
||||
MLKEM1024_public_from_private(&pub2, &priv);
|
||||
if (!mlkem1024_encode_public_key(&pub2, &tmp_buf, &tmp_buf_len)) {
|
||||
warnx("mlkem1024_encode_public_key");
|
||||
failed |= 1;
|
||||
}
|
||||
if (sizeof(encoded_public_key) != tmp_buf_len) {
|
||||
warnx("mlkem1024 encoded public key lengths differ");
|
||||
failed |= 1;
|
||||
}
|
||||
|
||||
if (compare_data(encoded_public_key, tmp_buf, tmp_buf_len, 1024,
|
||||
"encoded public keys") != 0) {
|
||||
warnx("compare_data");
|
||||
failed |= 1;
|
||||
}
|
||||
free(tmp_buf);
|
||||
tmp_buf = NULL;
|
||||
|
||||
TEST(!encode_1024private_key(priv, &encoded_private_key,
|
||||
&encoded_private_key_len), "encode_1024private_key");
|
||||
if (!mlkem1024_encode_private_key(&priv, &encoded_private_key,
|
||||
&encoded_private_key_len)) {
|
||||
warnx("mlkem1024_encode_private_key");
|
||||
failed |= 1;
|
||||
}
|
||||
|
||||
memcpy(first_two_bytes, encoded_private_key, sizeof(first_two_bytes));
|
||||
memset(encoded_private_key, 0xff, sizeof(first_two_bytes));
|
||||
CBS_init(&cbs, encoded_private_key, encoded_private_key_len);
|
||||
MALLOC(priv2, sizeof(struct MLKEM1024_private_key));
|
||||
|
||||
/* Parsing should fail because the first coefficient is >= kPrime. */
|
||||
TEST(MLKEM1024_parse_private_key(priv2, &cbs), "Should not have parsed");
|
||||
if (MLKEM1024_parse_private_key(&priv2, &cbs)) {
|
||||
warnx("MLKEM1024_parse_private_key should have failed");
|
||||
failed |= 1;
|
||||
}
|
||||
|
||||
memcpy(encoded_private_key, first_two_bytes, sizeof(first_two_bytes));
|
||||
CBS_init(&cbs, encoded_private_key, encoded_private_key_len);
|
||||
TEST(!MLKEM1024_parse_private_key(priv2, &cbs),
|
||||
"MLKEM1024_parse_private_key");
|
||||
TEST(!encode_1024private_key(priv2, &tmp_buf, &tmp_buf_len),
|
||||
"encode_private_key");
|
||||
TEST(encoded_private_key_len != tmp_buf_len,
|
||||
"encoded private key lengths differ");
|
||||
TEST_DATAEQ(tmp_buf, encoded_private_key, encoded_private_key_len,
|
||||
"encoded private keys");
|
||||
|
||||
if (!MLKEM1024_parse_private_key(&priv2, &cbs)) {
|
||||
warnx("MLKEM1024_parse_private_key");
|
||||
failed |= 1;
|
||||
}
|
||||
|
||||
if (!mlkem1024_encode_private_key(&priv2, &tmp_buf, &tmp_buf_len)) {
|
||||
warnx("mlkem1024_encode_private_key");
|
||||
failed |= 1;
|
||||
}
|
||||
|
||||
if (encoded_private_key_len != tmp_buf_len) {
|
||||
warnx("mlkem1024 encode private key lengths differ");
|
||||
failed |= 1;
|
||||
}
|
||||
|
||||
if (compare_data(encoded_private_key, tmp_buf, tmp_buf_len, 1024,
|
||||
"encoded private key") != 0) {
|
||||
warnx("compare_data");
|
||||
failed |= 1;
|
||||
}
|
||||
|
||||
free(tmp_buf);
|
||||
tmp_buf = NULL;
|
||||
|
||||
MLKEM1024_encap(ciphertext, shared_secret1, pub);
|
||||
MLKEM1024_encap(ciphertext, shared_secret1, &pub);
|
||||
MLKEM1024_decap(shared_secret2, ciphertext, MLKEM1024_CIPHERTEXT_BYTES,
|
||||
priv);
|
||||
TEST_DATAEQ(shared_secret1, shared_secret2, MLKEM_SHARED_SECRET_BYTES,
|
||||
"shared secrets with priv");
|
||||
&priv);
|
||||
if (compare_data(shared_secret1, shared_secret2, MLKEM_SHARED_SECRET_BYTES,
|
||||
1024, "shared secrets with priv") != 0) {
|
||||
warnx("compare_data");
|
||||
failed |= 1;
|
||||
}
|
||||
|
||||
MLKEM1024_decap(shared_secret2, ciphertext, MLKEM1024_CIPHERTEXT_BYTES,
|
||||
priv2);
|
||||
TEST_DATAEQ(shared_secret1, shared_secret2, MLKEM_SHARED_SECRET_BYTES,
|
||||
"shared secrets with priv2");
|
||||
&priv2);
|
||||
if (compare_data(shared_secret1, shared_secret2, MLKEM_SHARED_SECRET_BYTES,
|
||||
1024, "shared secrets with priv2") != 0) {
|
||||
warnx("compare_data");
|
||||
failed |= 1;
|
||||
}
|
||||
|
||||
free(encoded_private_key);
|
||||
free(pub);
|
||||
free(pub2);
|
||||
free(priv);
|
||||
free(priv2);
|
||||
|
||||
return failed;
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
MlKem768UnitTest();
|
||||
MlKem1024UnitTest();
|
||||
int failed = 0;
|
||||
|
||||
exit(failure);
|
||||
failed |= MlKem768UnitTest();
|
||||
failed |= MlKem1024UnitTest();
|
||||
|
||||
return failed;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user