summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authortb <>2024-12-20 00:07:12 +0000
committertb <>2024-12-20 00:07:12 +0000
commitb1838090ad769162b2ea08f33254c67d084bb22f (patch)
treef04653a882e3c8a90b00b8e6f900e4a225736db9
parent86a35b733e7f43fa01b1c83b3c582855e18ef432 (diff)
downloadopenbsd-b1838090ad769162b2ea08f33254c67d084bb22f.tar.gz
openbsd-b1838090ad769162b2ea08f33254c67d084bb22f.tar.bz2
openbsd-b1838090ad769162b2ea08f33254c67d084bb22f.zip
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.
-rw-r--r--src/regress/lib/libcrypto/mlkem/Makefile6
-rw-r--r--src/regress/lib/libcrypto/mlkem/mlkem1024_decap_tests.c201
-rw-r--r--src/regress/lib/libcrypto/mlkem/mlkem1024_encap_tests.c221
-rw-r--r--src/regress/lib/libcrypto/mlkem/mlkem1024_iteration_test.c52
-rw-r--r--src/regress/lib/libcrypto/mlkem/mlkem1024_keygen_tests.c198
-rw-r--r--src/regress/lib/libcrypto/mlkem/mlkem1024_nist_decap_tests.c210
-rw-r--r--src/regress/lib/libcrypto/mlkem/mlkem1024_nist_keygen_tests.c203
-rw-r--r--src/regress/lib/libcrypto/mlkem/mlkem768_decap_tests.c201
-rw-r--r--src/regress/lib/libcrypto/mlkem/mlkem768_encap_tests.c221
-rw-r--r--src/regress/lib/libcrypto/mlkem/mlkem768_iteration_test.c53
-rw-r--r--src/regress/lib/libcrypto/mlkem/mlkem768_keygen_tests.c198
-rw-r--r--src/regress/lib/libcrypto/mlkem/mlkem768_nist_decap_tests.c210
-rw-r--r--src/regress/lib/libcrypto/mlkem/mlkem768_nist_keygen_tests.c203
-rw-r--r--src/regress/lib/libcrypto/mlkem/mlkem_tests_util.c194
-rw-r--r--src/regress/lib/libcrypto/mlkem/mlkem_tests_util.h63
-rw-r--r--src/regress/lib/libcrypto/mlkem/mlkem_unittest.c387
16 files changed, 1824 insertions, 997 deletions
diff --git a/src/regress/lib/libcrypto/mlkem/Makefile b/src/regress/lib/libcrypto/mlkem/Makefile
index b8e5c4583a..1ee2dcc78d 100644
--- a/src/regress/lib/libcrypto/mlkem/Makefile
+++ b/src/regress/lib/libcrypto/mlkem/Makefile
@@ -1,4 +1,4 @@
1# $OpenBSD: Makefile,v 1.4 2024/12/19 23:45:09 tb Exp $ 1# $OpenBSD: Makefile,v 1.5 2024/12/20 00:07:12 tb Exp $
2 2
3PROGS += mlkem_unittest 3PROGS += mlkem_unittest
4PROGS += mlkem768_nist_keygen_tests 4PROGS += mlkem768_nist_keygen_tests
@@ -26,10 +26,12 @@ run-$p: $p
26LDADD = ${CRYPTO_INT} 26LDADD = ${CRYPTO_INT}
27DPADD = ${LIBCRYPTO} 27DPADD = ${LIBCRYPTO}
28 28
29CFLAGS += -DLIBRESSL_INTERNAL -Wall 29CFLAGS += -DLIBRESSL_INTERNAL -Wall -Werror
30CFLAGS += -I${.CURDIR}/../../../../lib/libcrypto/bytestring 30CFLAGS += -I${.CURDIR}/../../../../lib/libcrypto/bytestring
31CFLAGS += -I${.CURDIR}/../../../../lib/libcrypto/mlkem 31CFLAGS += -I${.CURDIR}/../../../../lib/libcrypto/mlkem
32CFLAGS += -I${.CURDIR}/../../../../lib/libcrypto/sha 32CFLAGS += -I${.CURDIR}/../../../../lib/libcrypto/sha
33CFLAGS += -DLIBRESSL_INTERNAL 33CFLAGS += -DLIBRESSL_INTERNAL
34 34
35WARNINS = Yes
36
35.include <bsd.regress.mk> 37.include <bsd.regress.mk>
diff --git a/src/regress/lib/libcrypto/mlkem/mlkem1024_decap_tests.c b/src/regress/lib/libcrypto/mlkem/mlkem1024_decap_tests.c
index b38cd52d28..c75b2c7ca8 100644
--- a/src/regress/lib/libcrypto/mlkem/mlkem1024_decap_tests.c
+++ b/src/regress/lib/libcrypto/mlkem/mlkem1024_decap_tests.c
@@ -1,7 +1,8 @@
1/* $OpenBSD: mlkem1024_decap_tests.c,v 1.2 2024/12/14 19:16:24 tb Exp $ */ 1/* $OpenBSD: mlkem1024_decap_tests.c,v 1.3 2024/12/20 00:07:12 tb Exp $ */
2/* 2/*
3 * Copyright (c) 2024, Google Inc. 3 * Copyright (c) 2024 Google Inc.
4 * Copyright (c) 2024, Bob Beck <beck@obtuse.com> 4 * Copyright (c) 2024 Bob Beck <beck@obtuse.com>
5 * Copyright (c) 2024 Theo Buehler <tb@openbsd.org>
5 * 6 *
6 * Permission to use, copy, modify, and/or distribute this software for any 7 * Permission to use, copy, modify, and/or distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above 8 * purpose with or without fee is hereby granted, provided that the above
@@ -16,113 +17,179 @@
16 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */ 18 */
18 19
20#include <assert.h>
21#include <err.h>
19#include <stdint.h> 22#include <stdint.h>
20#include <stdio.h> 23#include <stdio.h>
21#include <stdlib.h> 24#include <stdlib.h>
22#include <string.h>
23 25
24#include <openssl/bytestring.h> 26#include "bytestring.h"
25#include <openssl/mlkem.h> 27#include "mlkem.h"
26 28
27#include "mlkem_tests_util.h" 29#include "mlkem_tests_util.h"
28 30
29static void 31static int
30MlkemDecapFileTest(CBS *c, CBS *k, CBS *dk, int should_fail) 32MlkemDecapFileTest(CBB *ciphertext_cbb, CBB *shared_secret_cbb,
33 CBB *private_key_cbb, int should_fail, size_t line)
31{ 34{
32 uint8_t shared_secret[MLKEM_SHARED_SECRET_BYTES];
33 struct MLKEM1024_private_key priv; 35 struct MLKEM1024_private_key priv;
34 int parse_ok, decap_ok; 36 uint8_t *ciphertext = NULL, *shared_secret = NULL, *private_key = NULL;
37 size_t ciphertext_len = 0, shared_secret_len = 0, private_key_len = 0;
38 uint8_t shared_secret_buf[MLKEM_SHARED_SECRET_BYTES];
39 CBS private_key_cbs;
40 int failed = 1;
35 41
36 parse_ok = MLKEM1024_parse_private_key(&priv, dk); 42 if (!CBB_finish(ciphertext_cbb, &ciphertext, &ciphertext_len))
37 if (!parse_ok) { 43 goto err;
38 TEST(!should_fail, "parse_private_key"); 44 if (!CBB_finish(shared_secret_cbb, &shared_secret, &shared_secret_len))
39 return; 45 goto err;
46 if (!CBB_finish(private_key_cbb, &private_key, &private_key_len))
47 goto err;
48
49 CBS_init(&private_key_cbs, private_key, private_key_len);
50
51 if (!MLKEM1024_parse_private_key(&priv, &private_key_cbs)) {
52 if ((failed = !should_fail))
53 warnx("#%zu: parse_private_key", line);
54 goto err;
55 }
56 if (!MLKEM1024_decap(shared_secret_buf, ciphertext, ciphertext_len,
57 &priv)) {
58 if ((failed = !should_fail))
59 warnx("#%zu: decap", line);
60 goto err;
40 } 61 }
41 decap_ok = MLKEM1024_decap(shared_secret, CBS_data(c), CBS_len(c), 62
42 &priv); 63 failed = compare_data(shared_secret, shared_secret_buf,
43 if (!decap_ok) { 64 MLKEM_SHARED_SECRET_BYTES, line, "shared_secret");
44 TEST(!should_fail, "decap"); 65
45 return; 66 if (should_fail != failed) {
67 warnx("FAIL: #%zu: should_fail %d, failed %d",
68 line, should_fail, failed);
69 failed = 1;
46 } 70 }
47 TEST_DATAEQ(shared_secret, CBS_data(k), 71
48 MLKEM_SHARED_SECRET_BYTES, "shared_secret"); 72 err:
73 CBB_cleanup(ciphertext_cbb);
74 CBB_cleanup(shared_secret_cbb);
75 CBB_cleanup(private_key_cbb);
76 freezero(ciphertext, ciphertext_len);
77 freezero(shared_secret, shared_secret_len);
78 freezero(private_key, private_key_len);
79
80 return failed;
49} 81}
50 82
51#define S_START 0 83#define S_START 0
52#define S_COMMENT 1 84#define S_COMMENT 1
53#define S_PRIVATE_KEY 2 85#define S_PRIVATE_KEY 2
54#define S_CIPHERTEXT 3 86#define S_CIPHERTEXT 3
55#define S_RESULT 4 87#define S_RESULT 4
56#define S_SHARED_SECRET 5 88#define S_SHARED_SECRET 5
89
90#define S2S(x) case x: return #x
91
92static const char *
93state2str(int state)
94{
95 switch (state) {
96 S2S(S_START);
97 S2S(S_COMMENT);
98 S2S(S_PRIVATE_KEY);
99 S2S(S_CIPHERTEXT);
100 S2S(S_RESULT);
101 S2S(S_SHARED_SECRET);
102 default:
103 errx(1, "unknown state %d", state);
104 }
105}
57 106
58int 107int
59main(int argc, char **argv) 108main(int argc, char **argv)
60{ 109{
61 CBS ciphertext, shared_secret, private_key; 110 CBB ciphertext = { 0 }, shared_secret = { 0 }, private_key = { 0 };
62 const uint8_t *p = NULL;
63 int should_fail = 0; 111 int should_fail = 0;
64 char *buf; 112 const char *test;
113 size_t line = 0;
114 char *buf = NULL;
115 size_t buflen = 0;
116 ssize_t len;
65 FILE *fp; 117 FILE *fp;
66 int state; 118 int state;
119 int failed = 0;
120
121 if (argc < 2)
122 errx(1, "%s: missing test file", argv[0]);
123
124 test = argv[1];
125
126 if ((fp = fopen(test, "r")) == NULL)
127 err(1, "cant't open test file");
67 128
68 fprintf(stderr, "Testing decap test vectors in %s\n", argv[1]);
69 TEST((fp = fopen(argv[1], "r")) == NULL, "can't open test file");
70 MALLOC(buf, 16*1024);
71 state = S_COMMENT; 129 state = S_COMMENT;
72 test_number = 1; 130 line = 0;
73 while (fgets(buf, 16*1024, fp) != NULL) { 131
132 while ((len = getline(&buf, &buflen, fp)) != -1) {
133 const char *msg = state2str(state);
134 CBS cbs;
135 uint8_t u8;
136
137 line++;
138 CBS_init(&cbs, buf, len);
139
140 if (!CBS_get_last_u8(&cbs, &u8))
141 errx(1, "#%zu %s: CBB_get_last_u8", line, msg);
142 assert(u8 == '\n');
143
74 switch (state) { 144 switch (state) {
75 case S_START: 145 case S_START:
76 if (strcmp(buf, "\n") != 0)
77 break;
78 state = S_COMMENT; 146 state = S_COMMENT;
79 break; 147 break;
80 case S_COMMENT: 148 case S_COMMENT:
81 if (strncmp(buf, "#", 1) != 0) 149 if (!CBS_get_u8(&cbs, &u8))
82 break; 150 errx(1, "#%zu %s: CBB_get_u8", line, msg);
151 assert(u8 == '#');
152 if (!CBS_skip(&cbs, CBS_len(&cbs)))
153 errx(1, "#%zu %s: CBB_skip", line, msg);
83 state = S_PRIVATE_KEY; 154 state = S_PRIVATE_KEY;
84 break; 155 break;
85 case S_PRIVATE_KEY: 156 case S_PRIVATE_KEY:
86 if (strncmp(buf, "private_key: ", 157 if (!get_string_cbs(&cbs, "private_key: ", line, msg))
87 strlen("private_key: ")) != 0) 158 errx(1, "#%zu %s: get_string_cbs", line, msg);
88 break; 159 hex_decode_cbs(&cbs, &private_key, line, msg);
89 grab_data(&private_key, buf, strlen("private_key: "));
90 p = CBS_data(&private_key);
91 state = S_CIPHERTEXT; 160 state = S_CIPHERTEXT;
92 break; 161 break;
93 case S_CIPHERTEXT: 162 case S_CIPHERTEXT:
94 if (strncmp(buf, "ciphertext: ", 163 if (!get_string_cbs(&cbs, "ciphertext: ", line, msg))
95 strlen("ciphertext: ")) != 0) 164 errx(1, "#%zu %s: get_string_cbs", line, msg);
96 break; 165 hex_decode_cbs(&cbs, &ciphertext, line, msg);
97 grab_data(&ciphertext, buf, strlen("ciphertext: "));
98 state = S_RESULT; 166 state = S_RESULT;
99 break; 167 break;
100 case S_RESULT: 168 case S_RESULT:
101 if (strncmp(buf, "result: pass", 169 if (!get_string_cbs(&cbs, "result: ", line, msg))
102 strlen("result: pass")) != 0) 170 errx(1, "#%zu %s: get_string_cbs", line, msg);
103 should_fail = 1; 171 should_fail = get_string_cbs(&cbs, "fail", line, msg);
104 else
105 should_fail = 0;
106 state = S_SHARED_SECRET; 172 state = S_SHARED_SECRET;
107 break; 173 break;
108 case S_SHARED_SECRET: 174 case S_SHARED_SECRET:
109 if (strncmp(buf, "shared_secret: ", 175 if (!get_string_cbs(&cbs, "shared_secret: ", line, msg))
110 strlen("shared_secret: ")) != 0) 176 errx(1, "#%zu %s: get_string_cbs", line, msg);
111 break; 177 hex_decode_cbs(&cbs, &shared_secret, line, msg);
112 grab_data(&shared_secret, buf, 178
113 strlen("shared_secret: ")); 179 failed |= MlkemDecapFileTest(&ciphertext, &shared_secret,
114 MlkemDecapFileTest(&ciphertext, &shared_secret, 180 &private_key, should_fail, line);
115 &private_key, should_fail); 181
116 free((void *)CBS_data(&ciphertext));
117 free((void *)CBS_data(&shared_secret));
118 free((void *)p);
119
120 test_number++;
121 state = S_START; 182 state = S_START;
122 break; 183 break;
123 } 184 }
185 if (CBS_len(&cbs) > 0)
186 errx(1, "#%zu %s: CBS_len", line, msg);
124 } 187 }
125
126 free(buf); 188 free(buf);
127 exit(failure); 189
190 if (ferror(fp))
191 err(1, NULL);
192 fclose(fp);
193
194 return failed;
128} 195}
diff --git a/src/regress/lib/libcrypto/mlkem/mlkem1024_encap_tests.c b/src/regress/lib/libcrypto/mlkem/mlkem1024_encap_tests.c
index 83924ba6d2..06b00a4b75 100644
--- a/src/regress/lib/libcrypto/mlkem/mlkem1024_encap_tests.c
+++ b/src/regress/lib/libcrypto/mlkem/mlkem1024_encap_tests.c
@@ -1,7 +1,8 @@
1/* $OpenBSD: mlkem1024_encap_tests.c,v 1.2 2024/12/14 19:16:24 tb Exp $ */ 1/* $OpenBSD: mlkem1024_encap_tests.c,v 1.3 2024/12/20 00:07:12 tb Exp $ */
2/* 2/*
3 * Copyright (c) 2024, Google Inc. 3 * Copyright (c) 2024 Google Inc.
4 * Copyright (c) 2024, Bob Beck <beck@obtuse.com> 4 * Copyright (c) 2024 Bob Beck <beck@obtuse.com>
5 * Copyright (c) 2024 Theo Buehler <tb@openbsd.org>
5 * 6 *
6 * Permission to use, copy, modify, and/or distribute this software for any 7 * Permission to use, copy, modify, and/or distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above 8 * purpose with or without fee is hereby granted, provided that the above
@@ -16,120 +17,194 @@
16 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */ 18 */
18 19
20#include <assert.h>
21#include <err.h>
19#include <stdint.h> 22#include <stdint.h>
20#include <stdio.h> 23#include <stdio.h>
21#include <stdlib.h> 24#include <stdlib.h>
22#include <string.h>
23 25
24#include <openssl/bytestring.h> 26#include "bytestring.h"
25#include <openssl/mlkem.h> 27#include "mlkem.h"
26 28
29#include "mlkem_internal.h"
27#include "mlkem_tests_util.h" 30#include "mlkem_tests_util.h"
28 31
29static void 32static int
30MlkemEncapFileTest(CBS *entropy, CBS *public_key, CBS *expected_ciphertext, 33MlkemEncapFileTest(CBB *entropy_cbb, CBB *pubkey_cbb, CBB *ciphertext_cbb,
31 CBS *expected_shared_secret, int should_fail) 34 CBB *shared_secret_cbb, int should_fail, size_t line)
32{ 35{
33 uint8_t shared_secret[MLKEM_SHARED_SECRET_BYTES];
34 uint8_t ciphertext[MLKEM1024_CIPHERTEXT_BYTES];
35 struct MLKEM1024_public_key pub; 36 struct MLKEM1024_public_key pub;
36 int parse_ok; 37 uint8_t *entropy = NULL, *public_key = NULL, *ciphertext = NULL;
38 uint8_t *shared_secret = NULL;
39 size_t entropy_len = 0, public_key_len = 0, ciphertext_len = 0;
40 size_t shared_secret_len = 0;
41 uint8_t shared_secret_buf[MLKEM_SHARED_SECRET_BYTES];
42 uint8_t ciphertext_buf[MLKEM1024_CIPHERTEXT_BYTES];
43 CBS public_key_cbs;
44 int failed = 1;
37 45
38 parse_ok = MLKEM1024_parse_public_key(&pub, public_key); 46 if (!CBB_finish(entropy_cbb, &entropy, &entropy_len))
39 if (!parse_ok) { 47 goto err;
40 TEST(!should_fail, "parse_public_key"); 48 if (!CBB_finish(pubkey_cbb, &public_key, &public_key_len))
41 return; 49 goto err;
50 if (!CBB_finish(ciphertext_cbb, &ciphertext, &ciphertext_len))
51 goto err;
52 if (!CBB_finish(shared_secret_cbb, &shared_secret, &shared_secret_len))
53 goto err;
54
55 CBS_init(&public_key_cbs, public_key, public_key_len);
56
57 if (!MLKEM1024_parse_public_key(&pub, &public_key_cbs)) {
58 if ((failed = !should_fail))
59 warnx("#%zu: parse_public_key", line);
60 goto err;
42 } 61 }
43 MLKEM1024_encap(ciphertext, shared_secret, &pub); 62 MLKEM1024_encap_external_entropy(ciphertext_buf, shared_secret_buf,
44 TEST_DATAEQ(shared_secret, CBS_data(expected_shared_secret), 63 &pub, entropy);
45 MLKEM_SHARED_SECRET_BYTES, "shared_secret"); 64
46 TEST_DATAEQ(ciphertext, CBS_data(expected_ciphertext), 65 failed = compare_data(shared_secret, shared_secret_buf,
47 MLKEM1024_CIPHERTEXT_BYTES, "shared_secret"); 66 MLKEM_SHARED_SECRET_BYTES, line, "shared_secret");
67 failed |= compare_data(ciphertext, ciphertext_buf,
68 MLKEM1024_CIPHERTEXT_BYTES, line, "ciphertext");
69
70 if (should_fail != failed) {
71 warnx("FAIL: #%zu: should_fail %d, failed %d",
72 line, should_fail, failed);
73 failed = 1;
74 }
75
76 err:
77 CBB_cleanup(entropy_cbb);
78 CBB_cleanup(pubkey_cbb);
79 CBB_cleanup(ciphertext_cbb);
80 CBB_cleanup(shared_secret_cbb);
81 freezero(entropy, entropy_len);
82 freezero(public_key, public_key_len);
83 freezero(ciphertext, ciphertext_len);
84 freezero(shared_secret, shared_secret_len);
85
86 return failed;
48} 87}
49 88
50#define S_START 0 89#define S_START 0
51#define S_COMMENT 1 90#define S_COMMENT 1
52#define S_ENTROPY 2 91#define S_ENTROPY 2
53#define S_PUBLIC_KEY 3 92#define S_PUBLIC_KEY 3
54#define S_RESULT 4 93#define S_RESULT 4
55#define S_CIPHERTEXT 5 94#define S_CIPHERTEXT 5
56#define S_SHARED_SECRET 6 95#define S_SHARED_SECRET 6
96
97#define S2S(x) case x: return #x
98
99static const char *
100state2str(int state)
101{
102 switch (state) {
103 S2S(S_START);
104 S2S(S_COMMENT);
105 S2S(S_ENTROPY);
106 S2S(S_PUBLIC_KEY);
107 S2S(S_RESULT);
108 S2S(S_CIPHERTEXT);
109 S2S(S_SHARED_SECRET);
110 default:
111 errx(1, "unknown state %d", state);
112 }
113}
57 114
58int 115int
59main(int argc, char **argv) 116main(int argc, char **argv)
60{ 117{
61 CBS entropy, public_key, ciphertext, shared_secret; 118 CBB entropy = { 0 }, public_key = { 0 }, ciphertext = { 0 }, shared_secret = { 0 };
62 const uint8_t *p = NULL;
63 int should_fail = 0; 119 int should_fail = 0;
64 char *buf; 120 const char *test;
121 size_t line;
122 char *buf = NULL;
123 size_t buflen = 0;
124 ssize_t len;
65 FILE *fp; 125 FILE *fp;
66 int state; 126 int state;
127 int failed = 0;
128
129 if (argc < 2)
130 errx(1, "%s: missing test file", argv[0]);
131
132 test = argv[1];
133 line = 0;
134
135 if ((fp = fopen(test, "r")) == NULL)
136 err(1, "cant't open test file");
67 137
68 fprintf(stderr, "Testing encap test vectors in %s\n", argv[1]);
69 TEST((fp = fopen(argv[1], "r")) == NULL, "can't open test file");
70 MALLOC(buf, 16*1024);
71 state = S_COMMENT; 138 state = S_COMMENT;
72 test_number = 1; 139 line = 0;
73 while (fgets(buf, 16*1024, fp) != NULL) { 140
141 while ((len = getline(&buf, &buflen, fp)) != -1) {
142 const char *msg = state2str(state);
143 CBS cbs;
144 uint8_t u8;
145
146 line++;
147 CBS_init(&cbs, buf, len);
148
149 if (!CBS_get_last_u8(&cbs, &u8))
150 errx(1, "#%zu %s: CBB_get_last_u8", line, msg);
151 assert(u8 == '\n');
152
74 switch (state) { 153 switch (state) {
75 case S_START: 154 case S_START:
76 if (strcmp(buf, "\n") != 0)
77 break;
78 state = S_COMMENT; 155 state = S_COMMENT;
79 break; 156 break;
80 case S_COMMENT: 157 case S_COMMENT:
81 if (strncmp(buf, "#", 1) != 0) 158 if (!CBS_get_u8(&cbs, &u8))
82 break; 159 errx(1, "#%zu %s: CBB_get_u8", line, msg);
160 assert(u8 == '#');
161 if (!CBS_skip(&cbs, CBS_len(&cbs)))
162 errx(1, "#%zu %s: CBB_skip", line, msg);
83 state = S_ENTROPY; 163 state = S_ENTROPY;
84 break; 164 break;
85 case S_ENTROPY: 165 case S_ENTROPY:
86 if (strncmp(buf, "entropy: ", strlen("entropy: ")) != 0) 166 if (!get_string_cbs(&cbs, "entropy: ", line, msg))
87 break; 167 errx(1, "#%zu %s: get_string_cbs", line, msg);
88 grab_data(&entropy, buf, strlen("entropy: ")); 168 hex_decode_cbs(&cbs, &entropy, line, msg);
89 p = CBS_data(&entropy);
90 state = S_PUBLIC_KEY; 169 state = S_PUBLIC_KEY;
91 break; 170 break;
92 case S_PUBLIC_KEY: 171 case S_PUBLIC_KEY:
93 if (strncmp(buf, "public_key: ", 172 if (!get_string_cbs(&cbs, "public_key = ", line, msg))
94 strlen("public_key: ")) != 0) 173 errx(1, "#%zu %s: get_string_cbs", line, msg);
95 break; 174 hex_decode_cbs(&cbs, &public_key, line, msg);
96 grab_data(&public_key, buf, strlen("public_key: "));
97 p = CBS_data(&public_key);
98 state = S_RESULT; 175 state = S_RESULT;
99 break; 176 break;
100 case S_RESULT: 177 case S_RESULT:
101 if (strncmp(buf, "result: pass", 178 if (!get_string_cbs(&cbs, "result: ", line, msg))
102 strlen("result: pass")) != 0) 179 errx(1, "#%zu %s: get_string_cbs", line, msg);
103 should_fail = 1; 180 should_fail = get_string_cbs(&cbs, "fail", line, msg);
104 else
105 should_fail = 0;
106 state = S_CIPHERTEXT; 181 state = S_CIPHERTEXT;
107 break; 182 break;
108 case S_CIPHERTEXT: 183 case S_CIPHERTEXT:
109 if (strncmp(buf, "ciphertext: ", 184 if (!get_string_cbs(&cbs, "ciphertext: ", line, msg))
110 strlen("ciphertext: ")) != 0) 185 errx(1, "#%zu %s: get_string_cbs", line, msg);
111 break; 186 hex_decode_cbs(&cbs, &ciphertext, line, msg);
112 grab_data(&ciphertext, buf, strlen("ciphertext: ")); 187 state = S_SHARED_SECRET;
113 state = S_RESULT;
114 break; 188 break;
115 case S_SHARED_SECRET: 189 case S_SHARED_SECRET:
116 if (strncmp(buf, "shared_secret: ", 190 if (!get_string_cbs(&cbs, "shared_secret: ", line, msg))
117 strlen("shared_secret: ")) != 0) 191 errx(1, "#%zu %s: get_string_cbs", line, msg);
118 break; 192 hex_decode_cbs(&cbs, &shared_secret, line, msg);
119 grab_data(&shared_secret, buf, 193
120 strlen("shared_secret: ")); 194 failed |= MlkemEncapFileTest(&entropy, &public_key,
121 MlkemEncapFileTest(&entropy, &public_key, &ciphertext, 195 &ciphertext, &shared_secret, should_fail, line);
122 &shared_secret, should_fail); 196
123 free((void *)CBS_data(&ciphertext));
124 free((void *)CBS_data(&shared_secret));
125 free((void *)p);
126
127 test_number++;
128 state = S_START; 197 state = S_START;
129 break; 198 break;
130 } 199 }
200 if (CBS_len(&cbs) > 0)
201 errx(1, "#%zu %s: CBS_len", line, msg);
131 } 202 }
132
133 free(buf); 203 free(buf);
134 exit(failure); 204
205 if (ferror(fp))
206 err(1, NULL);
207 fclose(fp);
208
209 return failed;
135} 210}
diff --git a/src/regress/lib/libcrypto/mlkem/mlkem1024_iteration_test.c b/src/regress/lib/libcrypto/mlkem/mlkem1024_iteration_test.c
index 2b03a724ab..e6a4d4f906 100644
--- a/src/regress/lib/libcrypto/mlkem/mlkem1024_iteration_test.c
+++ b/src/regress/lib/libcrypto/mlkem/mlkem1024_iteration_test.c
@@ -1,7 +1,8 @@
1/* $OpenBSD: mlkem1024_iteration_test.c,v 1.2 2024/12/14 19:16:24 tb Exp $ */ 1/* $OpenBSD: mlkem1024_iteration_test.c,v 1.3 2024/12/20 00:07:12 tb Exp $ */
2/* 2/*
3 * Copyright (c) 2024, Google Inc. 3 * Copyright (c) 2024 Google Inc.
4 * Copyright (c) 2024, Bob Beck <beck@obtuse.com> 4 * Copyright (c) 2024 Bob Beck <beck@obtuse.com>
5 * Copyright (c) 2024 Theo Buehler <tb@openbsd.org>
5 * 6 *
6 * Permission to use, copy, modify, and/or distribute this software for any 7 * Permission to use, copy, modify, and/or distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above 8 * purpose with or without fee is hereby granted, provided that the above
@@ -16,32 +17,17 @@
16 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */ 18 */
18 19
20#include <err.h>
19#include <stdint.h> 21#include <stdint.h>
20#include <stdio.h> 22#include <stdio.h>
21#include <stdlib.h> 23#include <stdlib.h>
22 24
23#include <openssl/bytestring.h> 25#include "mlkem.h"
24#include <openssl/mlkem.h>
25 26
26#include "mlkem_internal.h" 27#include "mlkem_internal.h"
27#include "mlkem_tests_util.h" 28#include "mlkem_tests_util.h"
28#include "sha3_internal.h" 29#include "sha3_internal.h"
29 30
30static int
31encode_private_key(const struct MLKEM1024_private_key *priv, uint8_t **out_buf,
32 size_t *out_len)
33{
34 CBB cbb;
35 if (!CBB_init(&cbb, MLKEM1024_PUBLIC_KEY_BYTES))
36 return 0;
37 if (!MLKEM1024_marshal_private_key(&cbb, priv))
38 return 0;
39 if (!CBB_finish(&cbb, out_buf, out_len))
40 return 0;
41 CBB_cleanup(&cbb);
42 return 1;
43}
44
45/* 31/*
46 * The structure of this test is taken from 32 * The structure of this test is taken from
47 * https://github.com/C2SP/CCTV/blob/main/ML-KEM/README.md?ref=words.filippo.io#accumulated-pq-crystals-vectors 33 * 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,
52 * (The RNG stream starts with 7f9c2ba4e88f827d616045507605853e.) 38 * (The RNG stream starts with 7f9c2ba4e88f827d616045507605853e.)
53 */ 39 */
54 40
55static void 41static int
56MlkemIterativeTest() 42MlkemIterativeTest(void)
57{ 43{
58 /* https://github.com/C2SP/CCTV/tree/main/ML-KEM */ 44 /* https://github.com/C2SP/CCTV/tree/main/ML-KEM */
59 /* 45 /*
@@ -101,8 +87,9 @@ MlkemIterativeTest()
101 */ 87 */
102 shake_out(&drng, seed, sizeof(seed)); 88 shake_out(&drng, seed, sizeof(seed));
103 if (i == 0) { 89 if (i == 0) {
104 TEST_DATAEQ(seed, kExpectedSeedStart, 90 if (compare_data(seed, kExpectedSeedStart,
105 sizeof(kExpectedSeedStart), "seed start"); 91 sizeof(kExpectedSeedStart), 0, "seed start") != 0)
92 errx(1, "compare_data");
106 } 93 }
107 94
108 /* generate ek as encoded_public_key */ 95 /* generate ek as encoded_public_key */
@@ -115,8 +102,9 @@ MlkemIterativeTest()
115 sizeof(encoded_public_key)); 102 sizeof(encoded_public_key));
116 103
117 /* marshal priv to dk as encoded_private_key */ 104 /* marshal priv to dk as encoded_private_key */
118 TEST(!encode_private_key(&priv, &encoded_private_key, 105 if (!mlkem1024_encode_private_key(&priv, &encoded_private_key,
119 &encoded_private_key_len), "encode_private_key"); 106 &encoded_private_key_len))
107 errx(1, "mlkem1024_encode_private_key");
120 108
121 /* hash in dk */ 109 /* hash in dk */
122 shake_update(&results, encoded_private_key, 110 shake_update(&results, encoded_private_key,
@@ -141,21 +129,21 @@ MlkemIterativeTest()
141 sizeof(invalid_ciphertext)); 129 sizeof(invalid_ciphertext));
142 130
143 /* generte k as shared secret from invalid ciphertext */ 131 /* generte k as shared secret from invalid ciphertext */
144 TEST(!MLKEM1024_decap(shared_secret, invalid_ciphertext, 132 if (!MLKEM1024_decap(shared_secret, invalid_ciphertext,
145 sizeof(invalid_ciphertext), &priv), "decap failed!"); 133 sizeof(invalid_ciphertext), &priv))
134 errx(1, "decap failed");
146 135
147 /* hash in k */ 136 /* hash in k */
148 shake_update(&results, shared_secret, sizeof(shared_secret)); 137 shake_update(&results, shared_secret, sizeof(shared_secret));
149 } 138 }
150 shake_xof(&results); 139 shake_xof(&results);
151 shake_out(&results, out, 32); 140 shake_out(&results, out, sizeof(out));
152 141
153 TEST_DATAEQ(out, kExpectedAdam, 32, "final result hash"); 142 return compare_data(kExpectedAdam, out, sizeof(out), i, "final result hash");
154} 143}
155 144
156int 145int
157main(int argc, char **argv) 146main(int argc, char **argv)
158{ 147{
159 MlkemIterativeTest(); 148 return MlkemIterativeTest();
160 exit(failure);
161} 149}
diff --git a/src/regress/lib/libcrypto/mlkem/mlkem1024_keygen_tests.c b/src/regress/lib/libcrypto/mlkem/mlkem1024_keygen_tests.c
index 1b1a18bc22..559a6da36d 100644
--- a/src/regress/lib/libcrypto/mlkem/mlkem1024_keygen_tests.c
+++ b/src/regress/lib/libcrypto/mlkem/mlkem1024_keygen_tests.c
@@ -1,7 +1,8 @@
1/* $OpenBSD: mlkem1024_keygen_tests.c,v 1.4 2024/12/17 07:20:10 tb Exp $ */ 1/* $OpenBSD: mlkem1024_keygen_tests.c,v 1.5 2024/12/20 00:07:12 tb Exp $ */
2/* 2/*
3 * Copyright (c) 2024, Google Inc. 3 * Copyright (c) 2024 Google Inc.
4 * Copyright (c) 2024, Bob Beck <beck@obtuse.com> 4 * Copyright (c) 2024 Bob Beck <beck@obtuse.com>
5 * Copyright (c) 2024 Theo Buehler <tb@openbsd.org>
5 * 6 *
6 * Permission to use, copy, modify, and/or distribute this software for any 7 * Permission to use, copy, modify, and/or distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above 8 * purpose with or without fee is hereby granted, provided that the above
@@ -16,115 +17,174 @@
16 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */ 18 */
18 19
20#include <assert.h>
21#include <err.h>
19#include <stdint.h> 22#include <stdint.h>
20#include <stdio.h> 23#include <stdio.h>
21#include <stdlib.h> 24#include <stdlib.h>
22#include <string.h>
23 25
24#include <openssl/bytestring.h> 26#include "bytestring.h"
25#include <openssl/mlkem.h> 27#include "mlkem.h"
26 28
27#include "mlkem_internal.h" 29#include "mlkem_internal.h"
28#include "mlkem_tests_util.h" 30#include "mlkem_tests_util.h"
29 31
30static int 32static int
31encode_private_key(const struct MLKEM1024_private_key *priv, uint8_t **out_buf, 33MlkemKeygenFileTest(CBB *seed_cbb, CBB *public_key_cbb, CBB *private_key_cbb,
32 size_t *out_len) 34 size_t line)
33{
34 CBB cbb;
35 if (!CBB_init(&cbb, MLKEM1024_PUBLIC_KEY_BYTES))
36 return 0;
37 if (!MLKEM1024_marshal_private_key(&cbb, priv))
38 return 0;
39 if (!CBB_finish(&cbb, out_buf, out_len))
40 return 0;
41 CBB_cleanup(&cbb);
42 return 1;
43}
44
45static void
46MlkemKeygenFileTest(CBS *seed, CBS *public_key, CBS *private_key)
47{ 35{
48 struct MLKEM1024_private_key priv; 36 struct MLKEM1024_private_key priv;
37 uint8_t *seed = NULL, *public_key = NULL, *private_key = NULL;
38 size_t seed_len = 0, public_key_len = 0, private_key_len = 0;
49 uint8_t *encoded_private_key = NULL; 39 uint8_t *encoded_private_key = NULL;
50 uint8_t encoded_public_key[MLKEM1024_PUBLIC_KEY_BYTES]; 40 uint8_t encoded_public_key[MLKEM1024_PUBLIC_KEY_BYTES];
51 size_t len; 41 size_t len;
42 int failed = 1;
43
44 if (!CBB_finish(seed_cbb, &seed, &seed_len))
45 goto err;
46 if (!compare_length(MLKEM_SEED_BYTES, seed_len, line, "seed length"))
47 goto err;
48 if (!CBB_finish(public_key_cbb, &public_key, &public_key_len))
49 goto err;
50 if (!compare_length(MLKEM1024_PUBLIC_KEY_BYTES, public_key_len, line,
51 "public key length"))
52 goto err;
53 if (!CBB_finish(private_key_cbb, &private_key, &private_key_len))
54 goto err;
55 if (!compare_length(MLKEM1024_PUBLIC_KEY_BYTES, public_key_len, line,
56 "public key length"))
57 goto err;
52 58
53 TEST(CBS_len(seed) != MLKEM_SEED_BYTES, "seed len bogus");
54 TEST(CBS_len(private_key) != MLKEM1024_PRIVATE_KEY_BYTES,
55 "expected private key len bogus");
56 TEST(CBS_len(public_key) != MLKEM1024_PUBLIC_KEY_BYTES,
57 "expected public key len bogus");
58 MLKEM1024_generate_key_external_entropy(encoded_public_key, &priv, 59 MLKEM1024_generate_key_external_entropy(encoded_public_key, &priv,
59 CBS_data(seed)); 60 seed);
60 TEST(!encode_private_key(&priv, &encoded_private_key, 61 if (!mlkem1024_encode_private_key(&priv, &encoded_private_key, &len)) {
61 &len), "encode_private_key"); 62 warnx("#%zu: encoded_private_key", line);
62 TEST(len != MLKEM1024_PRIVATE_KEY_BYTES, "private key len bogus"); 63 goto err;
63 TEST_DATAEQ(encoded_public_key, CBS_data(public_key), 64 }
64 MLKEM1024_PUBLIC_KEY_BYTES, "public key"); 65
65 TEST_DATAEQ(encoded_private_key, CBS_data(private_key), 66 if (!compare_length(MLKEM1024_PRIVATE_KEY_BYTES, len, line,
66 MLKEM1024_PRIVATE_KEY_BYTES, "private key"); 67 "private key length"))
68 goto err;
69
70 failed = compare_data(private_key, encoded_private_key,
71 MLKEM1024_PRIVATE_KEY_BYTES, line, "private key");
72 failed |= compare_data(public_key, encoded_public_key,
73 MLKEM1024_PUBLIC_KEY_BYTES, line, "public key");
74
75 err:
76 CBB_cleanup(seed_cbb);
77 CBB_cleanup(public_key_cbb);
78 CBB_cleanup(private_key_cbb);
79 freezero(seed, seed_len);
80 freezero(public_key, public_key_len);
81 freezero(private_key, private_key_len);
67 free(encoded_private_key); 82 free(encoded_private_key);
83
84 return failed;
68} 85}
69 86
70#define S_START 0 87#define S_START 0
71#define S_SEED 1 88#define S_COMMENT 1
72#define S_PUBLIC_KEY 2 89#define S_SEED 2
73#define S_PRIVATE_KEY 3 90#define S_PUBLIC_KEY 3
91#define S_PRIVATE_KEY 4
92
93#define S2S(x) case x: return #x
94
95static const char *
96state2str(int state)
97{
98 switch (state) {
99 S2S(S_START);
100 S2S(S_COMMENT);
101 S2S(S_SEED);
102 S2S(S_PUBLIC_KEY);
103 S2S(S_PRIVATE_KEY);
104 default:
105 errx(1, "unknown state %d", state);
106 }
107}
74 108
75int 109int
76main(int argc, char **argv) 110main(int argc, char **argv)
77{ 111{
78 CBS seed, public_key, private_key; 112 CBB seed = { 0 }, public_key = { 0 }, private_key = { 0 };
79 char *buf; 113 const char *test;
114 size_t line = 0;
115 char *buf = NULL;
116 size_t buflen = 0;
117 ssize_t len;
80 FILE *fp; 118 FILE *fp;
81 int state; 119 int state;
120 int failed = 0;
121
122 if (argc < 2)
123 errx(1, "%s: missing test file", argv[0]);
124
125 test = argv[1];
126
127 if ((fp = fopen(test, "r")) == NULL)
128 err(1, "cant't open test file");
129
130 state = S_COMMENT;
131 line = 0;
132
133 while ((len = getline(&buf, &buflen, fp)) != -1) {
134 const char *msg = state2str(state);
135 CBS cbs;
136 uint8_t u8;
137
138 line++;
139 CBS_init(&cbs, buf, len);
140
141 if (!CBS_get_last_u8(&cbs, &u8))
142 errx(1, "#%zu %s: CBB_get_last_u8", line, msg);
143 assert(u8 == '\n');
82 144
83 fprintf(stderr, "Testing keygen test vectors in %s\n", argv[1]);
84 TEST((fp = fopen(argv[1], "r")) == NULL, "can't open test file");
85 MALLOC(buf, 16*1024);
86 state = S_SEED;
87 test_number = 1;
88 while (fgets(buf, 16*1024, fp) != NULL) {
89 switch (state) { 145 switch (state) {
90 case S_START: 146 case S_START:
91 if (strcmp(buf, "\n") != 0) 147 state = S_COMMENT;
92 break; 148 break;
149 case S_COMMENT:
150 if (!CBS_get_u8(&cbs, &u8))
151 errx(1, "#%zu %s: CBB_get_u8", line, msg);
152 assert(u8 == '#');
153 if (!CBS_skip(&cbs, CBS_len(&cbs)))
154 errx(1, "#%zu %s: CBB_skip", line, msg);
93 state = S_SEED; 155 state = S_SEED;
94 break; 156 break;
95 case S_SEED: 157 case S_SEED:
96 if (strncmp(buf, "seed: ", strlen("seed: ")) != 0) { 158 if (!get_string_cbs(&cbs, "seed: ", line, msg))
97 break; 159 errx(1, "#%zu %s: get_string_cbs", line, msg);
98 } 160 hex_decode_cbs(&cbs, &seed, line, msg);
99 grab_data(&seed, buf, strlen("seed: "));
100 state = S_PUBLIC_KEY; 161 state = S_PUBLIC_KEY;
101 break; 162 break;
102 case S_PUBLIC_KEY: 163 case S_PUBLIC_KEY:
103 if (strncmp(buf, "public_key: ", 164 if (!get_string_cbs(&cbs, "public_key: ", line, msg))
104 strlen("public_key: ")) != 0) 165 errx(1, "#%zu %s: get_string_cbs", line, msg);
105 break; 166 hex_decode_cbs(&cbs, &public_key, line, msg);
106 grab_data(&public_key, buf, strlen("public_key: "));
107 state = S_PRIVATE_KEY; 167 state = S_PRIVATE_KEY;
108 break; 168 break;
109 case S_PRIVATE_KEY: 169 case S_PRIVATE_KEY:
110 if (strncmp(buf, "private_key: ", 170 if (!get_string_cbs(&cbs, "private_key: ", line, msg))
111 strlen("private_key: ")) != 0) 171 errx(1, "#%zu %s: get_string_cbs", line, msg);
112 break; 172 hex_decode_cbs(&cbs, &private_key, line, msg);
113 grab_data(&private_key, buf, strlen("private_key: "));
114 state = S_START;
115 173
116 MlkemKeygenFileTest(&seed, &public_key, &private_key); 174 failed |= MlkemKeygenFileTest(&seed, &public_key,
117 free((void *)CBS_data(&seed)); 175 &private_key, line);
118 free((void *)CBS_data(&public_key));
119 free((void *)CBS_data(&private_key));
120 176
121 test_number++;
122 state = S_START; 177 state = S_START;
123 break; 178 break;
124 } 179 }
180 if (CBS_len(&cbs) > 0)
181 errx(1, "#%zu %s: CBS_len", line, msg);
125 } 182 }
126
127 free(buf); 183 free(buf);
184
185 if (ferror(fp))
186 err(1, NULL);
128 fclose(fp); 187 fclose(fp);
129 exit(failure); 188
189 return failed;
130} 190}
diff --git a/src/regress/lib/libcrypto/mlkem/mlkem1024_nist_decap_tests.c b/src/regress/lib/libcrypto/mlkem/mlkem1024_nist_decap_tests.c
index a59d062234..ba05de9f05 100644
--- a/src/regress/lib/libcrypto/mlkem/mlkem1024_nist_decap_tests.c
+++ b/src/regress/lib/libcrypto/mlkem/mlkem1024_nist_decap_tests.c
@@ -1,7 +1,8 @@
1/* $OpenBSD: mlkem1024_nist_decap_tests.c,v 1.2 2024/12/14 19:16:24 tb Exp $ */ 1/* $OpenBSD: mlkem1024_nist_decap_tests.c,v 1.3 2024/12/20 00:07:12 tb Exp $ */
2/* 2/*
3 * Copyright (c) 2024, Google Inc. 3 * Copyright (c) 2024 Google Inc.
4 * Copyright (c) 2024, Bob Beck <beck@obtuse.com> 4 * Copyright (c) 2024 Bob Beck <beck@obtuse.com>
5 * Copyright (c) 2024 Theo Buehler <tb@openbsd.org>
5 * 6 *
6 * Permission to use, copy, modify, and/or distribute this software for any 7 * Permission to use, copy, modify, and/or distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above 8 * purpose with or without fee is hereby granted, provided that the above
@@ -16,96 +17,177 @@
16 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */ 18 */
18 19
20#include <assert.h>
21#include <err.h>
19#include <stdint.h> 22#include <stdint.h>
20#include <stdio.h> 23#include <stdio.h>
21#include <stdlib.h> 24#include <stdlib.h>
22#include <string.h>
23 25
24#include <openssl/bytestring.h> 26#include "bytestring.h"
25#include <openssl/mlkem.h> 27#include "mlkem.h"
26 28
27#include "mlkem_internal.h" 29#include "mlkem_internal.h"
28#include "mlkem_tests_util.h" 30#include "mlkem_tests_util.h"
29 31
30static void 32static int
31MlkemNistDecapFileTest(CBS *c, CBS *k, CBS *dk) 33MlkemNistDecapFileTest(CBB *c_cbb, CBB *k_cbb, CBS *dk, size_t line)
32{ 34{
35 uint8_t *c = NULL, *k = NULL;
36 size_t c_len = 0, k_len = 0;
33 uint8_t shared_secret[MLKEM_SHARED_SECRET_BYTES]; 37 uint8_t shared_secret[MLKEM_SHARED_SECRET_BYTES];
34 struct MLKEM1024_private_key priv; 38 struct MLKEM1024_private_key priv;
39 int failed = 1;
35 40
36 TEST(CBS_len(dk) != MLKEM1024_PRIVATE_KEY_BYTES, 41 if (!CBB_finish(c_cbb, &c, &c_len))
37 "private key len bogus"); 42 goto err;
38 TEST(CBS_len(k) != MLKEM_SHARED_SECRET_BYTES, 43 if (!CBB_finish(k_cbb, &k, &k_len))
39 "shared secret len bogus"); 44 goto err;
40 45
41 TEST(!MLKEM1024_parse_private_key(&priv, dk), "parse_private_key"); 46 if (!compare_length(MLKEM1024_PRIVATE_KEY_BYTES, CBS_len(dk), line,
42 TEST(!MLKEM1024_decap(shared_secret, CBS_data(c), CBS_len(c), &priv), 47 "private key len bogus"))
43 "decap"); 48 goto err;
44 TEST_DATAEQ(shared_secret, CBS_data(k), 49 if (!compare_length(MLKEM_SHARED_SECRET_BYTES, k_len, line,
45 MLKEM_SHARED_SECRET_BYTES, "shared_secret"); 50 "shared secret len bogus"))
51 goto err;
52
53 if (!MLKEM1024_parse_private_key(&priv, dk)) {
54 warnx("#%zu MLKEM1024_parse_private_key", line);
55 goto err;
56 }
57 if (!MLKEM1024_decap(shared_secret, c, c_len, &priv)) {
58 warnx("#%zu MLKEM1024_decap", line);
59 goto err;
60 }
61
62 failed = compare_data(shared_secret, k, k_len, line, "shared_secret");
63
64 err:
65 CBB_cleanup(c_cbb);
66 CBB_cleanup(k_cbb);
67 freezero(c, c_len);
68 freezero(k, k_len);
69
70 return failed;
46} 71}
47 72
48#define S_START 0 73#define S_START 0
49#define S_CIPHERTEXT 1 74#define S_C 1
50#define S_SHARED_SECRET 2 75#define S_K 2
51#define S_PRIVATE_KEY 3 76#define S_EMPTY 3
77
78#define S2S(x) case x: return #x
79
80static const char *
81state2str(int state)
82{
83 switch (state) {
84 S2S(S_START);
85 S2S(S_C);
86 S2S(S_K);
87 S2S(S_EMPTY);
88 default:
89 errx(1, "unknown state %d", state);
90 }
91}
52 92
53int 93int
54main(int argc, char **argv) 94main(int argc, char **argv)
55{ 95{
56 CBS ciphertext, shared_secret, private_key; 96 CBB dk_cbb = { 0 }, c = { 0 }, k = { 0 };
57 const uint8_t *p; 97 CBS instr;
58 char *buf; 98 uint8_t *dk = NULL;
99 size_t dk_len = 0;
100 uint8_t bracket, newline;
101 const char *test;
102 size_t line;
103 char *buf = NULL;
104 size_t buflen = 0;
105 ssize_t len;
59 FILE *fp; 106 FILE *fp;
60 int state; 107 int state;
108 int failed = 0;
109
110 if (argc < 2)
111 errx(1, "%s: missing test file", argv[0]);
112
113 test = argv[1];
114
115 if ((fp = fopen(test, "r")) == NULL)
116 err(1, "cant't open test file");
117
118 if ((len = getline(&buf, &buflen, fp)) == -1)
119 err(1, "failed to read instruction line");
120
121 /*
122 * The private key is enclosed in brackets in an "instruction line".
123 */
124 line = 1;
125 CBS_init(&instr, buf, len);
126 if (!CBS_get_u8(&instr, &bracket))
127 err(1, "failed to parse instruction line '['");
128 assert(bracket == '[');
129 if (!CBS_get_last_u8(&instr, &newline))
130 errx(1, "failed to parse instruction line '\\n'");
131 assert(newline == '\n');
132 if (!CBS_get_last_u8(&instr, &bracket))
133 errx(1, "failed to parse instruction line ']'");
134 assert(bracket == ']');
135 if (!get_string_cbs(&instr, "dk: ", line, "private key"))
136 errx(1, "failed to read instruction line 'dk: '");
137 hex_decode_cbs(&instr, &dk_cbb, line, "private key");
138 assert(CBS_len(&instr) == 0);
139
140 if (!CBB_finish(&dk_cbb, &dk, &dk_len))
141 errx(1, "CBB finish instruction line");
142
143 state = S_START;
144
145 while ((len = getline(&buf, &buflen, fp)) != -1) {
146 const char *msg = state2str(state);
147 CBS cbs, dk_cbs;
148 uint8_t u8;
149
150 line++;
151 CBS_init(&cbs, buf, len);
152
153 if (!CBS_get_last_u8(&cbs, &u8))
154 errx(1, "#%zu %s: CBB_get_last_u8", line, msg);
155 assert(u8 == '\n');
61 156
62 fprintf(stderr, "Testing NIST decap test vectors in %s\n", argv[1]);
63 TEST((fp = fopen(argv[1], "r")) == NULL, "can't open test file");
64 MALLOC(buf, 16*1024);
65 state = S_CIPHERTEXT;
66 test_number = 1;
67 while (fgets(buf, 16*1024, fp) != NULL) {
68 switch (state) { 157 switch (state) {
69 case S_START: 158 case S_START:
70 if (strcmp(buf, "\n") != 0) 159 state = S_C;
71 break;
72 state = S_CIPHERTEXT;
73 break; 160 break;
74 case S_CIPHERTEXT: 161 case S_C:
75 if (strncmp(buf, "ciphertext: ", 162 if (!get_string_cbs(&cbs, "c: ", line, msg))
76 strlen("ciphertext: ")) != 0) { 163 errx(1, "#%zu %s: get_string_cbs", line, msg);
77 break; 164 hex_decode_cbs(&cbs, &c, line, msg);
78 } 165 state = S_K;
79 grab_data(&ciphertext, buf, strlen("ciphertext: "));
80 state = S_SHARED_SECRET;
81 break; 166 break;
82 case S_SHARED_SECRET: 167 case S_K:
83 if (strncmp(buf, "shared_secret: ", 168 if (!get_string_cbs(&cbs, "k: ", line, msg))
84 strlen("shared_secret: ")) != 0) 169 errx(1, "#%zu %s: get_string_cbs", line, msg);
85 break; 170 hex_decode_cbs(&cbs, &k, line, msg);
86 grab_data(&shared_secret, buf, 171 state = S_EMPTY;
87 strlen("shared_secret: "));
88 state = S_PRIVATE_KEY;
89 break; 172 break;
90 case S_PRIVATE_KEY: 173 case S_EMPTY:
91 if (strncmp(buf, "private_key: ", 174 CBS_init(&dk_cbs, dk, dk_len);
92 strlen("private_key: ")) != 0) 175
93 break; 176 failed |= MlkemNistDecapFileTest(&c, &k, &dk_cbs, line);
94 grab_data(&private_key, buf, strlen("private_key: ")); 177
95 p = CBS_data(&private_key); 178 state = S_C;
96
97 MlkemNistDecapFileTest(&ciphertext, &shared_secret,
98 &private_key);
99 free((void *)CBS_data(&ciphertext));
100 free((void *)CBS_data(&shared_secret));
101 free((void *)p);
102
103 state = S_START;
104 test_number++;
105 break; 179 break;
106 } 180 }
181 if (CBS_len(&cbs) > 0)
182 errx(1, "#%zu %s: CBS_len", line, msg);
107 } 183 }
108
109 free(buf); 184 free(buf);
110 exit(failure); 185
186 if (ferror(fp))
187 err(1, NULL);
188 fclose(fp);
189
190 freezero(dk, dk_len);
191
192 return failed;
111} 193}
diff --git a/src/regress/lib/libcrypto/mlkem/mlkem1024_nist_keygen_tests.c b/src/regress/lib/libcrypto/mlkem/mlkem1024_nist_keygen_tests.c
index d293d121d4..e84f7dafc6 100644
--- a/src/regress/lib/libcrypto/mlkem/mlkem1024_nist_keygen_tests.c
+++ b/src/regress/lib/libcrypto/mlkem/mlkem1024_nist_keygen_tests.c
@@ -1,7 +1,8 @@
1/* $OpenBSD: mlkem1024_nist_keygen_tests.c,v 1.3 2024/12/17 07:20:10 tb Exp $ */ 1/* $OpenBSD: mlkem1024_nist_keygen_tests.c,v 1.4 2024/12/20 00:07:12 tb Exp $ */
2/* 2/*
3 * Copyright (c) 2024, Google Inc. 3 * Copyright (c) 2024 Google Inc.
4 * Copyright (c) 2024, Bob Beck <beck@obtuse.com> 4 * Copyright (c) 2024 Bob Beck <beck@obtuse.com>
5 * Copyright (c) 2024 Theo Buehler <tb@openbsd.org>
5 * 6 *
6 * Permission to use, copy, modify, and/or distribute this software for any 7 * Permission to use, copy, modify, and/or distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above 8 * purpose with or without fee is hereby granted, provided that the above
@@ -16,123 +17,181 @@
16 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */ 18 */
18 19
20#include <assert.h>
21#include <err.h>
19#include <stdint.h> 22#include <stdint.h>
20#include <stdio.h> 23#include <stdio.h>
21#include <stdlib.h> 24#include <stdlib.h>
22#include <string.h>
23 25
24#include <openssl/bytestring.h> 26#include "bytestring.h"
25#include <openssl/mlkem.h> 27#include "mlkem.h"
26 28
27#include "mlkem_internal.h" 29#include "mlkem_internal.h"
28#include "mlkem_tests_util.h" 30#include "mlkem_tests_util.h"
29 31
30static int 32static int
31encode_private_key(const struct MLKEM1024_private_key *priv, uint8_t **out_buf, 33MlkemNistKeygenFileTest(CBB *z_cbb, CBB *d_cbb, CBB *ek_cbb, CBB *dk_cbb,
32 size_t *out_len) 34 size_t line)
33{
34 CBB cbb;
35 if (!CBB_init(&cbb, MLKEM1024_PUBLIC_KEY_BYTES))
36 return 0;
37 if (!MLKEM1024_marshal_private_key(&cbb, priv))
38 return 0;
39 if (!CBB_finish(&cbb, out_buf, out_len))
40 return 0;
41 CBB_cleanup(&cbb);
42 return 1;
43}
44
45static void
46MlkemNistKeygenFileTest(CBS *z, CBS *d, CBS *ek, CBS *dk)
47{ 35{
36 CBB seed_cbb;
37 uint8_t *z = NULL, *d = NULL, *ek = NULL, *dk = NULL;
38 size_t z_len = 0, d_len = 0, ek_len = 0, dk_len = 0;
48 uint8_t seed[MLKEM_SEED_BYTES]; 39 uint8_t seed[MLKEM_SEED_BYTES];
49 struct MLKEM1024_private_key priv; 40 struct MLKEM1024_private_key priv;
50 uint8_t *encoded_private_key = NULL; 41 uint8_t *encoded_private_key = NULL;
51 uint8_t encoded_public_key[MLKEM1024_PUBLIC_KEY_BYTES]; 42 uint8_t encoded_public_key[MLKEM1024_PUBLIC_KEY_BYTES];
52 size_t len; 43 size_t len;
44 int failed = 1;
45
46 if (!CBB_init_fixed(&seed_cbb, seed, sizeof(seed)))
47 goto err;
48
49 if (!CBB_finish(z_cbb, &z, &z_len))
50 goto err;
51 if (!CBB_finish(d_cbb, &d, &d_len))
52 goto err;
53 if (!CBB_finish(ek_cbb, &ek, &ek_len))
54 goto err;
55 if (!CBB_finish(dk_cbb, &dk, &dk_len))
56 goto err;
57
58 if (!CBB_add_bytes(&seed_cbb, d, d_len))
59 goto err;
60 if (!CBB_add_bytes(&seed_cbb, z, z_len))
61 goto err;
62 if (!CBB_finish(&seed_cbb, NULL, &len))
63 goto err;
64
65 if (!compare_length(MLKEM_SEED_BYTES, len, line, "z or d length bogus"))
66 goto err;
53 67
54 TEST(CBS_len(d) != (MLKEM_SEED_BYTES / 2), "d len bogus");
55 TEST(CBS_len(z) != (MLKEM_SEED_BYTES / 2), "z len bogus");
56 TEST(CBS_len(dk) != MLKEM1024_PRIVATE_KEY_BYTES,
57 "expected private key len bogus");
58 TEST(CBS_len(ek) != MLKEM1024_PUBLIC_KEY_BYTES,
59 "expected public key len bogus");
60 memcpy(&seed[0], CBS_data(d), CBS_len(d));
61 memcpy(&seed[MLKEM_SEED_BYTES / 2], CBS_data(z), CBS_len(z));
62 MLKEM1024_generate_key_external_entropy(encoded_public_key, &priv, seed); 68 MLKEM1024_generate_key_external_entropy(encoded_public_key, &priv, seed);
63 TEST(!encode_private_key(&priv, &encoded_private_key, 69
64 &len), "encode_private_key"); 70 if (!mlkem1024_encode_private_key(&priv, &encoded_private_key, &len)) {
65 TEST(len != MLKEM1024_PRIVATE_KEY_BYTES, "private key len bogus"); 71 warnx("#%zu mlkem1024_encode_private_key", line);
66 TEST_DATAEQ(encoded_public_key, CBS_data(ek), 72 goto err;
67 MLKEM1024_PUBLIC_KEY_BYTES, "public key"); 73 }
68 TEST_DATAEQ(encoded_private_key, CBS_data(dk), 74
69 MLKEM1024_PRIVATE_KEY_BYTES, "private key"); 75 if (!compare_length(MLKEM1024_PRIVATE_KEY_BYTES, len, line,
76 "private key length"))
77 goto err;
78
79 failed = compare_data(ek, encoded_public_key, MLKEM1024_PUBLIC_KEY_BYTES,
80 line, "public key");
81 failed |= compare_data(dk, encoded_private_key, MLKEM1024_PRIVATE_KEY_BYTES,
82 line, "private key");
83
84 err:
85 CBB_cleanup(&seed_cbb);
86 CBB_cleanup(z_cbb);
87 CBB_cleanup(d_cbb);
88 CBB_cleanup(ek_cbb);
89 CBB_cleanup(dk_cbb);
90 freezero(z, z_len);
91 freezero(d, d_len);
92 freezero(ek, ek_len);
93 freezero(dk, dk_len);
70 free(encoded_private_key); 94 free(encoded_private_key);
95
96 return failed;
71} 97}
72 98
73#define S_START 0 99#define S_START 0
74#define S_Z 1 100#define S_Z 1
75#define S_D 2 101#define S_D 2
76#define S_EK 3 102#define S_EK 3
77#define S_DK 4 103#define S_DK 4
104
105#define S2S(x) case x: return #x
106
107static const char *
108state2str(int state)
109{
110 switch (state) {
111 S2S(S_START);
112 S2S(S_Z);
113 S2S(S_D);
114 S2S(S_EK);
115 S2S(S_DK);
116 default:
117 errx(1, "unknown state %d", state);
118 }
119}
78 120
79int 121int
80main(int argc, char **argv) 122main(int argc, char **argv)
81{ 123{
82 CBS z, d, ek, dk; 124 CBB z = { 0 }, d = { 0 }, ek = { 0 }, dk = { 0 };
83 char *buf; 125 const char *test;
126 size_t line = 0;
127 char *buf = NULL;
128 size_t buflen = 0;
129 ssize_t len;
84 FILE *fp; 130 FILE *fp;
85 int state; 131 int state;
132 int failed = 0;
133
134 if (argc < 2)
135 errx(1, "%s: missing test file", argv[0]);
136
137 test = argv[1];
138
139 if ((fp = fopen(test, "r")) == NULL)
140 err(1, "cant't open test file");
86 141
87 fprintf(stderr, "Testing NIST keygen test vectors in %s\n", argv[1]);
88 TEST((fp = fopen(argv[1], "r")) == NULL, "can't open test file");
89 MALLOC(buf, 16*1024);
90 state = S_Z; 142 state = S_Z;
91 test_number = 1; 143 line = 0;
92 while (fgets(buf, 16*1024, fp) != NULL) { 144
145 while ((len = getline(&buf, &buflen, fp)) != -1) {
146 const char *msg = state2str(state);
147 CBS cbs;
148 uint8_t u8;
149
150 line++;
151 CBS_init(&cbs, buf, len);
152
153 if (!CBS_get_last_u8(&cbs, &u8))
154 errx(1, "#%zu %s: CBB_get_last_u8", line, msg);
155 assert(u8 == '\n');
156
93 switch (state) { 157 switch (state) {
94 case S_START: 158 case S_START:
95 if (strcmp(buf, "\n") != 0)
96 break;
97 state = S_Z; 159 state = S_Z;
98 break; 160 break;
99 case S_Z: 161 case S_Z:
100 if (strncmp(buf, "z: ", strlen("z: ")) != 0) { 162 if (!get_string_cbs(&cbs, "z: ", line, msg))
101 break; 163 errx(1, "#%zu %s: get_string_cbs", line, msg);
102 } 164 hex_decode_cbs(&cbs, &z, line, msg);
103 grab_data(&z, buf, strlen("z: "));
104 state = S_D; 165 state = S_D;
105 break; 166 break;
106 case S_D: 167 case S_D:
107 if (strncmp(buf, "d: ", strlen("d: ")) != 0) 168 if (!get_string_cbs(&cbs, "d: ", line, msg))
108 break; 169 errx(1, "#%zu %s: get_string_cbs", line, msg);
109 grab_data(&d, buf, strlen("d: ")); 170 hex_decode_cbs(&cbs, &d, line, msg);
110 state = S_EK; 171 state = S_EK;
111 break; 172 break;
112 case S_EK: 173 case S_EK:
113 if (strncmp(buf, "ek: ", strlen("ek: ")) != 0) 174 if (!get_string_cbs(&cbs, "ek: ", line, msg))
114 break; 175 errx(1, "#%zu %s: get_string_cbs", line, msg);
115 grab_data(&ek, buf, strlen("ek: ")); 176 hex_decode_cbs(&cbs, &ek, line, msg);
116 state = S_DK; 177 state = S_DK;
117 break; 178 break;
118 case S_DK: 179 case S_DK:
119 if (strncmp(buf, "dk: ", strlen("dk: ")) != 0) 180 if (!get_string_cbs(&cbs, "dk: ", line, msg))
120 break; 181 errx(1, "#%zu %s: get_string_cbs", line, msg);
121 grab_data(&dk, buf, strlen("dk: ")); 182 hex_decode_cbs(&cbs, &dk, line, msg);
122 183
123 MlkemNistKeygenFileTest(&z, &d, &ek, &dk); 184 failed |= MlkemNistKeygenFileTest(&z, &d, &ek, &dk, line);
124 free((void *)CBS_data(&z));
125 free((void *)CBS_data(&d));
126 free((void *)CBS_data(&ek));
127 free((void *)CBS_data(&dk));
128 185
129 test_number++;
130 state = S_START; 186 state = S_START;
131 break; 187 break;
132 } 188 }
133 } 189 }
134
135 free(buf); 190 free(buf);
191
192 if (ferror(fp))
193 err(1, NULL);
136 fclose(fp); 194 fclose(fp);
137 exit(failure); 195
196 return failed;
138} 197}
diff --git a/src/regress/lib/libcrypto/mlkem/mlkem768_decap_tests.c b/src/regress/lib/libcrypto/mlkem/mlkem768_decap_tests.c
index 96dc435c4d..a88e487494 100644
--- a/src/regress/lib/libcrypto/mlkem/mlkem768_decap_tests.c
+++ b/src/regress/lib/libcrypto/mlkem/mlkem768_decap_tests.c
@@ -1,7 +1,8 @@
1/* $OpenBSD: mlkem768_decap_tests.c,v 1.2 2024/12/14 19:16:24 tb Exp $ */ 1/* $OpenBSD: mlkem768_decap_tests.c,v 1.3 2024/12/20 00:07:12 tb Exp $ */
2/* 2/*
3 * Copyright (c) 2024, Google Inc. 3 * Copyright (c) 2024 Google Inc.
4 * Copyright (c) 2024, Bob Beck <beck@obtuse.com> 4 * Copyright (c) 2024 Bob Beck <beck@obtuse.com>
5 * Copyright (c) 2024 Theo Buehler <tb@openbsd.org>
5 * 6 *
6 * Permission to use, copy, modify, and/or distribute this software for any 7 * Permission to use, copy, modify, and/or distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above 8 * purpose with or without fee is hereby granted, provided that the above
@@ -16,113 +17,179 @@
16 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */ 18 */
18 19
20#include <assert.h>
21#include <err.h>
19#include <stdint.h> 22#include <stdint.h>
20#include <stdio.h> 23#include <stdio.h>
21#include <stdlib.h> 24#include <stdlib.h>
22#include <string.h>
23 25
24#include <openssl/bytestring.h> 26#include "bytestring.h"
25#include <openssl/mlkem.h> 27#include "mlkem.h"
26 28
27#include "mlkem_tests_util.h" 29#include "mlkem_tests_util.h"
28 30
29static void 31static int
30MlkemDecapFileTest(CBS *c, CBS *k, CBS *dk, int should_fail) 32MlkemDecapFileTest(CBB *ciphertext_cbb, CBB *shared_secret_cbb,
33 CBB *private_key_cbb, int should_fail, size_t line)
31{ 34{
32 uint8_t shared_secret[MLKEM_SHARED_SECRET_BYTES];
33 struct MLKEM768_private_key priv; 35 struct MLKEM768_private_key priv;
34 int parse_ok, decap_ok; 36 uint8_t *ciphertext = NULL, *shared_secret = NULL, *private_key = NULL;
37 size_t ciphertext_len = 0, shared_secret_len = 0, private_key_len = 0;
38 uint8_t shared_secret_buf[MLKEM_SHARED_SECRET_BYTES];
39 CBS private_key_cbs;
40 int failed = 1;
35 41
36 parse_ok = MLKEM768_parse_private_key(&priv, dk); 42 if (!CBB_finish(ciphertext_cbb, &ciphertext, &ciphertext_len))
37 if (!parse_ok) { 43 goto err;
38 TEST(!should_fail, "parse_private_key"); 44 if (!CBB_finish(shared_secret_cbb, &shared_secret, &shared_secret_len))
39 return; 45 goto err;
46 if (!CBB_finish(private_key_cbb, &private_key, &private_key_len))
47 goto err;
48
49 CBS_init(&private_key_cbs, private_key, private_key_len);
50
51 if (!MLKEM768_parse_private_key(&priv, &private_key_cbs)) {
52 if ((failed = !should_fail))
53 warnx("#%zu: parse_private_key", line);
54 goto err;
55 }
56 if (!MLKEM768_decap(shared_secret_buf, ciphertext, ciphertext_len,
57 &priv)) {
58 if ((failed = !should_fail))
59 warnx("#%zu: decap", line);
60 goto err;
40 } 61 }
41 decap_ok = MLKEM768_decap(shared_secret, CBS_data(c), CBS_len(c), 62
42 &priv); 63 failed = compare_data(shared_secret, shared_secret_buf,
43 if (!decap_ok) { 64 MLKEM_SHARED_SECRET_BYTES, line, "shared_secret");
44 TEST(!should_fail, "decap"); 65
45 return; 66 if (should_fail != failed) {
67 warnx("FAIL: #%zu: should_fail %d, failed %d",
68 line, should_fail, failed);
69 failed = 1;
46 } 70 }
47 TEST_DATAEQ(shared_secret, CBS_data(k), 71
48 MLKEM_SHARED_SECRET_BYTES, "shared_secret"); 72 err:
73 CBB_cleanup(ciphertext_cbb);
74 CBB_cleanup(shared_secret_cbb);
75 CBB_cleanup(private_key_cbb);
76 freezero(ciphertext, ciphertext_len);
77 freezero(shared_secret, shared_secret_len);
78 freezero(private_key, private_key_len);
79
80 return failed;
49} 81}
50 82
51#define S_START 0 83#define S_START 0
52#define S_COMMENT 1 84#define S_COMMENT 1
53#define S_PRIVATE_KEY 2 85#define S_PRIVATE_KEY 2
54#define S_CIPHERTEXT 3 86#define S_CIPHERTEXT 3
55#define S_RESULT 4 87#define S_RESULT 4
56#define S_SHARED_SECRET 5 88#define S_SHARED_SECRET 5
89
90#define S2S(x) case x: return #x
91
92static const char *
93state2str(int state)
94{
95 switch (state) {
96 S2S(S_START);
97 S2S(S_COMMENT);
98 S2S(S_PRIVATE_KEY);
99 S2S(S_CIPHERTEXT);
100 S2S(S_RESULT);
101 S2S(S_SHARED_SECRET);
102 default:
103 errx(1, "unknown state %d", state);
104 }
105}
57 106
58int 107int
59main(int argc, char **argv) 108main(int argc, char **argv)
60{ 109{
61 CBS ciphertext, shared_secret, private_key; 110 CBB ciphertext = { 0 }, shared_secret = { 0 }, private_key = { 0 };
62 const uint8_t *p = NULL;
63 int should_fail = 0; 111 int should_fail = 0;
64 char *buf; 112 const char *test;
113 size_t line = 0;
114 char *buf = NULL;
115 size_t buflen = 0;
116 ssize_t len;
65 FILE *fp; 117 FILE *fp;
66 int state; 118 int state;
119 int failed = 0;
120
121 if (argc < 2)
122 errx(1, "%s: missing test file", argv[0]);
123
124 test = argv[1];
125
126 if ((fp = fopen(test, "r")) == NULL)
127 err(1, "cant't open test file");
67 128
68 fprintf(stderr, "Testing decap test vectors in %s\n", argv[1]);
69 TEST((fp = fopen(argv[1], "r")) == NULL, "can't open test file");
70 MALLOC(buf, 16*1024);
71 state = S_COMMENT; 129 state = S_COMMENT;
72 test_number = 1; 130 line = 0;
73 while (fgets(buf, 16*1024, fp) != NULL) { 131
132 while ((len = getline(&buf, &buflen, fp)) != -1) {
133 const char *msg = state2str(state);
134 CBS cbs;
135 uint8_t u8;
136
137 line++;
138 CBS_init(&cbs, buf, len);
139
140 if (!CBS_get_last_u8(&cbs, &u8))
141 errx(1, "#%zu %s: CBB_get_last_u8", line, msg);
142 assert(u8 == '\n');
143
74 switch (state) { 144 switch (state) {
75 case S_START: 145 case S_START:
76 if (strcmp(buf, "\n") != 0)
77 break;
78 state = S_COMMENT; 146 state = S_COMMENT;
79 break; 147 break;
80 case S_COMMENT: 148 case S_COMMENT:
81 if (strncmp(buf, "#", 1) != 0) 149 if (!CBS_get_u8(&cbs, &u8))
82 break; 150 errx(1, "#%zu %s: CBB_get_u8", line, msg);
151 assert(u8 == '#');
152 if (!CBS_skip(&cbs, CBS_len(&cbs)))
153 errx(1, "#%zu %s: CBB_skip", line, msg);
83 state = S_PRIVATE_KEY; 154 state = S_PRIVATE_KEY;
84 break; 155 break;
85 case S_PRIVATE_KEY: 156 case S_PRIVATE_KEY:
86 if (strncmp(buf, "private_key: ", 157 if (!get_string_cbs(&cbs, "private_key: ", line, msg))
87 strlen("private_key: ")) != 0) 158 errx(1, "#%zu %s: get_string_cbs", line, msg);
88 break; 159 hex_decode_cbs(&cbs, &private_key, line, msg);
89 grab_data(&private_key, buf, strlen("private_key: "));
90 p = CBS_data(&private_key);
91 state = S_CIPHERTEXT; 160 state = S_CIPHERTEXT;
92 break; 161 break;
93 case S_CIPHERTEXT: 162 case S_CIPHERTEXT:
94 if (strncmp(buf, "ciphertext: ", 163 if (!get_string_cbs(&cbs, "ciphertext: ", line, msg))
95 strlen("ciphertext: ")) != 0) 164 errx(1, "#%zu %s: get_string_cbs", line, msg);
96 break; 165 hex_decode_cbs(&cbs, &ciphertext, line, msg);
97 grab_data(&ciphertext, buf, strlen("ciphertext: "));
98 state = S_RESULT; 166 state = S_RESULT;
99 break; 167 break;
100 case S_RESULT: 168 case S_RESULT:
101 if (strncmp(buf, "result: pass", 169 if (!get_string_cbs(&cbs, "result: ", line, msg))
102 strlen("result: pass")) != 0) 170 errx(1, "#%zu %s: get_string_cbs", line, msg);
103 should_fail = 1; 171 should_fail = get_string_cbs(&cbs, "fail", line, msg);
104 else
105 should_fail = 0;
106 state = S_SHARED_SECRET; 172 state = S_SHARED_SECRET;
107 break; 173 break;
108 case S_SHARED_SECRET: 174 case S_SHARED_SECRET:
109 if (strncmp(buf, "shared_secret: ", 175 if (!get_string_cbs(&cbs, "shared_secret: ", line, msg))
110 strlen("shared_secret: ")) != 0) 176 errx(1, "#%zu %s: get_string_cbs", line, msg);
111 break; 177 hex_decode_cbs(&cbs, &shared_secret, line, msg);
112 grab_data(&shared_secret, buf, 178
113 strlen("shared_secret: ")); 179 failed |= MlkemDecapFileTest(&ciphertext, &shared_secret,
114 MlkemDecapFileTest(&ciphertext, &shared_secret, 180 &private_key, should_fail, line);
115 &private_key, should_fail); 181
116 free((void *)CBS_data(&ciphertext));
117 free((void *)CBS_data(&shared_secret));
118 free((void *)p);
119
120 test_number++;
121 state = S_START; 182 state = S_START;
122 break; 183 break;
123 } 184 }
185 if (CBS_len(&cbs) > 0)
186 errx(1, "#%zu %s: CBS_len", line, msg);
124 } 187 }
125
126 free(buf); 188 free(buf);
127 exit(failure); 189
190 if (ferror(fp))
191 err(1, NULL);
192 fclose(fp);
193
194 return failed;
128} 195}
diff --git a/src/regress/lib/libcrypto/mlkem/mlkem768_encap_tests.c b/src/regress/lib/libcrypto/mlkem/mlkem768_encap_tests.c
index be6c6149da..55e3fe66bb 100644
--- a/src/regress/lib/libcrypto/mlkem/mlkem768_encap_tests.c
+++ b/src/regress/lib/libcrypto/mlkem/mlkem768_encap_tests.c
@@ -1,7 +1,8 @@
1/* $OpenBSD: mlkem768_encap_tests.c,v 1.2 2024/12/14 19:16:24 tb Exp $ */ 1/* $OpenBSD: mlkem768_encap_tests.c,v 1.3 2024/12/20 00:07:12 tb Exp $ */
2/* 2/*
3 * Copyright (c) 2024, Google Inc. 3 * Copyright (c) 2024 Google Inc.
4 * Copyright (c) 2024, Bob Beck <beck@obtuse.com> 4 * Copyright (c) 2024 Bob Beck <beck@obtuse.com>
5 * Copyright (c) 2024 Theo Buehler <tb@openbsd.org>
5 * 6 *
6 * Permission to use, copy, modify, and/or distribute this software for any 7 * Permission to use, copy, modify, and/or distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above 8 * purpose with or without fee is hereby granted, provided that the above
@@ -16,120 +17,194 @@
16 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */ 18 */
18 19
20#include <assert.h>
21#include <err.h>
19#include <stdint.h> 22#include <stdint.h>
20#include <stdio.h> 23#include <stdio.h>
21#include <stdlib.h> 24#include <stdlib.h>
22#include <string.h>
23 25
24#include <openssl/bytestring.h> 26#include "bytestring.h"
25#include <openssl/mlkem.h> 27#include "mlkem.h"
26 28
29#include "mlkem_internal.h"
27#include "mlkem_tests_util.h" 30#include "mlkem_tests_util.h"
28 31
29static void 32static int
30MlkemEncapFileTest(CBS *entropy, CBS *public_key, CBS *expected_ciphertext, 33MlkemEncapFileTest(CBB *entropy_cbb, CBB *pubkey_cbb, CBB *ciphertext_cbb,
31 CBS *expected_shared_secret, int should_fail) 34 CBB *shared_secret_cbb, int should_fail, size_t line)
32{ 35{
33 uint8_t shared_secret[MLKEM_SHARED_SECRET_BYTES];
34 uint8_t ciphertext[MLKEM768_CIPHERTEXT_BYTES];
35 struct MLKEM768_public_key pub; 36 struct MLKEM768_public_key pub;
36 int parse_ok; 37 uint8_t *entropy = NULL, *public_key = NULL, *ciphertext = NULL;
38 uint8_t *shared_secret = NULL;
39 size_t entropy_len = 0, public_key_len = 0, ciphertext_len = 0;
40 size_t shared_secret_len = 0;
41 uint8_t shared_secret_buf[MLKEM_SHARED_SECRET_BYTES];
42 uint8_t ciphertext_buf[MLKEM768_CIPHERTEXT_BYTES];
43 CBS public_key_cbs;
44 int failed = 1;
37 45
38 parse_ok = MLKEM768_parse_public_key(&pub, public_key); 46 if (!CBB_finish(entropy_cbb, &entropy, &entropy_len))
39 if (!parse_ok) { 47 goto err;
40 TEST(!should_fail, "parse_public_key"); 48 if (!CBB_finish(pubkey_cbb, &public_key, &public_key_len))
41 return; 49 goto err;
50 if (!CBB_finish(ciphertext_cbb, &ciphertext, &ciphertext_len))
51 goto err;
52 if (!CBB_finish(shared_secret_cbb, &shared_secret, &shared_secret_len))
53 goto err;
54
55 CBS_init(&public_key_cbs, public_key, public_key_len);
56
57 if (!MLKEM768_parse_public_key(&pub, &public_key_cbs)) {
58 if ((failed = !should_fail))
59 warnx("#%zu: parse_public_key", line);
60 goto err;
42 } 61 }
43 MLKEM768_encap(ciphertext, shared_secret, &pub); 62 MLKEM768_encap_external_entropy(ciphertext_buf, shared_secret_buf,
44 TEST_DATAEQ(shared_secret, CBS_data(expected_shared_secret), 63 &pub, entropy);
45 MLKEM_SHARED_SECRET_BYTES, "shared_secret"); 64
46 TEST_DATAEQ(ciphertext, CBS_data(expected_ciphertext), 65 failed = compare_data(shared_secret, shared_secret_buf,
47 MLKEM768_CIPHERTEXT_BYTES, "shared_secret"); 66 MLKEM_SHARED_SECRET_BYTES, line, "shared_secret");
67 failed |= compare_data(ciphertext, ciphertext_buf,
68 MLKEM768_CIPHERTEXT_BYTES, line, "ciphertext");
69
70 if (should_fail != failed) {
71 warnx("FAIL: #%zu: should_fail %d, failed %d",
72 line, should_fail, failed);
73 failed = 1;
74 }
75
76 err:
77 CBB_cleanup(entropy_cbb);
78 CBB_cleanup(pubkey_cbb);
79 CBB_cleanup(ciphertext_cbb);
80 CBB_cleanup(shared_secret_cbb);
81 freezero(entropy, entropy_len);
82 freezero(public_key, public_key_len);
83 freezero(ciphertext, ciphertext_len);
84 freezero(shared_secret, shared_secret_len);
85
86 return failed;
48} 87}
49 88
50#define S_START 0 89#define S_START 0
51#define S_COMMENT 1 90#define S_COMMENT 1
52#define S_ENTROPY 2 91#define S_ENTROPY 2
53#define S_PUBLIC_KEY 3 92#define S_PUBLIC_KEY 3
54#define S_RESULT 4 93#define S_RESULT 4
55#define S_CIPHERTEXT 5 94#define S_CIPHERTEXT 5
56#define S_SHARED_SECRET 6 95#define S_SHARED_SECRET 6
96
97#define S2S(x) case x: return #x
98
99static const char *
100state2str(int state)
101{
102 switch (state) {
103 S2S(S_START);
104 S2S(S_COMMENT);
105 S2S(S_ENTROPY);
106 S2S(S_PUBLIC_KEY);
107 S2S(S_RESULT);
108 S2S(S_CIPHERTEXT);
109 S2S(S_SHARED_SECRET);
110 default:
111 errx(1, "unknown state %d", state);
112 }
113}
57 114
58int 115int
59main(int argc, char **argv) 116main(int argc, char **argv)
60{ 117{
61 CBS entropy, public_key, ciphertext, shared_secret; 118 CBB entropy = { 0 }, public_key = { 0 }, ciphertext = { 0 }, shared_secret = { 0 };
62 const uint8_t *p = NULL;
63 int should_fail = 0; 119 int should_fail = 0;
64 char *buf; 120 const char *test;
121 size_t line;
122 char *buf = NULL;
123 size_t buflen = 0;
124 ssize_t len;
65 FILE *fp; 125 FILE *fp;
66 int state; 126 int state;
127 int failed = 0;
128
129 if (argc < 2)
130 errx(1, "%s: missing test file", argv[0]);
131
132 test = argv[1];
133 line = 0;
134
135 if ((fp = fopen(test, "r")) == NULL)
136 err(1, "cant't open test file");
67 137
68 fprintf(stderr, "Testing encap test vectors in %s\n", argv[1]);
69 TEST((fp = fopen(argv[1], "r")) == NULL, "can't open test file");
70 MALLOC(buf, 16*1024);
71 state = S_COMMENT; 138 state = S_COMMENT;
72 test_number = 1; 139 line = 0;
73 while (fgets(buf, 16*1024, fp) != NULL) { 140
141 while ((len = getline(&buf, &buflen, fp)) != -1) {
142 const char *msg = state2str(state);
143 CBS cbs;
144 uint8_t u8;
145
146 line++;
147 CBS_init(&cbs, buf, len);
148
149 if (!CBS_get_last_u8(&cbs, &u8))
150 errx(1, "#%zu %s: CBB_get_last_u8", line, msg);
151 assert(u8 == '\n');
152
74 switch (state) { 153 switch (state) {
75 case S_START: 154 case S_START:
76 if (strcmp(buf, "\n") != 0)
77 break;
78 state = S_COMMENT; 155 state = S_COMMENT;
79 break; 156 break;
80 case S_COMMENT: 157 case S_COMMENT:
81 if (strncmp(buf, "#", 1) != 0) 158 if (!CBS_get_u8(&cbs, &u8))
82 break; 159 errx(1, "#%zu %s: CBB_get_u8", line, msg);
160 assert(u8 == '#');
161 if (!CBS_skip(&cbs, CBS_len(&cbs)))
162 errx(1, "#%zu %s: CBB_skip", line, msg);
83 state = S_ENTROPY; 163 state = S_ENTROPY;
84 break; 164 break;
85 case S_ENTROPY: 165 case S_ENTROPY:
86 if (strncmp(buf, "entropy: ", strlen("entropy: ")) != 0) 166 if (!get_string_cbs(&cbs, "entropy: ", line, msg))
87 break; 167 errx(1, "#%zu %s: get_string_cbs", line, msg);
88 grab_data(&entropy, buf, strlen("entropy: ")); 168 hex_decode_cbs(&cbs, &entropy, line, msg);
89 p = CBS_data(&entropy);
90 state = S_PUBLIC_KEY; 169 state = S_PUBLIC_KEY;
91 break; 170 break;
92 case S_PUBLIC_KEY: 171 case S_PUBLIC_KEY:
93 if (strncmp(buf, "public_key: ", 172 if (!get_string_cbs(&cbs, "public_key = ", line, msg))
94 strlen("public_key: ")) != 0) 173 errx(1, "#%zu %s: get_string_cbs", line, msg);
95 break; 174 hex_decode_cbs(&cbs, &public_key, line, msg);
96 grab_data(&public_key, buf, strlen("public_key: "));
97 p = CBS_data(&public_key);
98 state = S_RESULT; 175 state = S_RESULT;
99 break; 176 break;
100 case S_RESULT: 177 case S_RESULT:
101 if (strncmp(buf, "result: pass", 178 if (!get_string_cbs(&cbs, "result: ", line, msg))
102 strlen("result: pass")) != 0) 179 errx(1, "#%zu %s: get_string_cbs", line, msg);
103 should_fail = 1; 180 should_fail = get_string_cbs(&cbs, "fail", line, msg);
104 else
105 should_fail = 0;
106 state = S_CIPHERTEXT; 181 state = S_CIPHERTEXT;
107 break; 182 break;
108 case S_CIPHERTEXT: 183 case S_CIPHERTEXT:
109 if (strncmp(buf, "ciphertext: ", 184 if (!get_string_cbs(&cbs, "ciphertext: ", line, msg))
110 strlen("ciphertext: ")) != 0) 185 errx(1, "#%zu %s: get_string_cbs", line, msg);
111 break; 186 hex_decode_cbs(&cbs, &ciphertext, line, msg);
112 grab_data(&ciphertext, buf, strlen("ciphertext: ")); 187 state = S_SHARED_SECRET;
113 state = S_RESULT;
114 break; 188 break;
115 case S_SHARED_SECRET: 189 case S_SHARED_SECRET:
116 if (strncmp(buf, "shared_secret: ", 190 if (!get_string_cbs(&cbs, "shared_secret: ", line, msg))
117 strlen("shared_secret: ")) != 0) 191 errx(1, "#%zu %s: get_string_cbs", line, msg);
118 break; 192 hex_decode_cbs(&cbs, &shared_secret, line, msg);
119 grab_data(&shared_secret, buf, 193
120 strlen("shared_secret: ")); 194 failed |= MlkemEncapFileTest(&entropy, &public_key,
121 MlkemEncapFileTest(&entropy, &public_key, &ciphertext, 195 &ciphertext, &shared_secret, should_fail, line);
122 &shared_secret, should_fail); 196
123 free((void *)CBS_data(&ciphertext));
124 free((void *)CBS_data(&shared_secret));
125 free((void *)p);
126
127 test_number++;
128 state = S_START; 197 state = S_START;
129 break; 198 break;
130 } 199 }
200 if (CBS_len(&cbs) > 0)
201 errx(1, "#%zu %s: CBS_len", line, msg);
131 } 202 }
132
133 free(buf); 203 free(buf);
134 exit(failure); 204
205 if (ferror(fp))
206 err(1, NULL);
207 fclose(fp);
208
209 return failed;
135} 210}
diff --git a/src/regress/lib/libcrypto/mlkem/mlkem768_iteration_test.c b/src/regress/lib/libcrypto/mlkem/mlkem768_iteration_test.c
index e9866134eb..9517980d7b 100644
--- a/src/regress/lib/libcrypto/mlkem/mlkem768_iteration_test.c
+++ b/src/regress/lib/libcrypto/mlkem/mlkem768_iteration_test.c
@@ -1,7 +1,8 @@
1/* $OpenBSD: mlkem768_iteration_test.c,v 1.2 2024/12/14 19:16:24 tb Exp $ */ 1/* $OpenBSD: mlkem768_iteration_test.c,v 1.3 2024/12/20 00:07:12 tb Exp $ */
2/* 2/*
3 * Copyright (c) 2024, Google Inc. 3 * Copyright (c) 2024 Google Inc.
4 * Copyright (c) 2024, Bob Beck <beck@obtuse.com> 4 * Copyright (c) 2024 Bob Beck <beck@obtuse.com>
5 * Copyright (c) 2024 Theo Buehler <tb@openbsd.org>
5 * 6 *
6 * Permission to use, copy, modify, and/or distribute this software for any 7 * Permission to use, copy, modify, and/or distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above 8 * purpose with or without fee is hereby granted, provided that the above
@@ -16,32 +17,17 @@
16 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */ 18 */
18 19
20#include <err.h>
19#include <stdint.h> 21#include <stdint.h>
20#include <stdio.h> 22#include <stdio.h>
21#include <stdlib.h> 23#include <stdlib.h>
22 24
23#include <openssl/bytestring.h> 25#include "mlkem.h"
24#include <openssl/mlkem.h>
25 26
26#include "mlkem_internal.h" 27#include "mlkem_internal.h"
27#include "mlkem_tests_util.h" 28#include "mlkem_tests_util.h"
28#include "sha3_internal.h" 29#include "sha3_internal.h"
29 30
30static int
31encode_private_key(const struct MLKEM768_private_key *priv, uint8_t **out_buf,
32 size_t *out_len)
33{
34 CBB cbb;
35 if (!CBB_init(&cbb, MLKEM768_PUBLIC_KEY_BYTES))
36 return 0;
37 if (!MLKEM768_marshal_private_key(&cbb, priv))
38 return 0;
39 if (!CBB_finish(&cbb, out_buf, out_len))
40 return 0;
41 CBB_cleanup(&cbb);
42 return 1;
43}
44
45/* 31/*
46 * The structure of this test is taken from 32 * The structure of this test is taken from
47 * https://github.com/C2SP/CCTV/blob/main/ML-KEM/README.md?ref=words.filippo.io#accumulated-pq-crystals-vectors 33 * 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,
52 * (The RNG stream starts with 7f9c2ba4e88f827d616045507605853e.) 38 * (The RNG stream starts with 7f9c2ba4e88f827d616045507605853e.)
53 */ 39 */
54 40
55static void 41static int
56MlkemIterativeTest() 42MlkemIterativeTest(void)
57{ 43{
58 /* https://github.com/C2SP/CCTV/tree/main/ML-KEM */ 44 /* https://github.com/C2SP/CCTV/tree/main/ML-KEM */
59 /* 45 /*
@@ -64,6 +50,7 @@ MlkemIterativeTest()
64 0x7f, 0x9c, 0x2b, 0xa4, 0xe8, 0x8f, 0x82, 0x7d, 0x61, 0x60, 0x45, 50 0x7f, 0x9c, 0x2b, 0xa4, 0xe8, 0x8f, 0x82, 0x7d, 0x61, 0x60, 0x45,
65 0x50, 0x76, 0x05, 0x85, 0x3e 51 0x50, 0x76, 0x05, 0x85, 0x3e
66 }; 52 };
53
67 /* 54 /*
68 * Filippo says: 55 * Filippo says:
69 * ML-KEM-768: f7db260e1137a742e05fe0db9525012812b004d29040a5b606aad3d134b548d3 56 * ML-KEM-768: f7db260e1137a742e05fe0db9525012812b004d29040a5b606aad3d134b548d3
@@ -100,8 +87,9 @@ MlkemIterativeTest()
100 */ 87 */
101 shake_out(&drng, seed, sizeof(seed)); 88 shake_out(&drng, seed, sizeof(seed));
102 if (i == 0) { 89 if (i == 0) {
103 TEST_DATAEQ(seed, kExpectedSeedStart, 90 if (compare_data(seed, kExpectedSeedStart,
104 sizeof(kExpectedSeedStart), "seed start"); 91 sizeof(kExpectedSeedStart), 0, "seed start") != 0)
92 errx(1, "compare_data");
105 } 93 }
106 94
107 /* generate ek as encoded_public_key */ 95 /* generate ek as encoded_public_key */
@@ -114,8 +102,9 @@ MlkemIterativeTest()
114 sizeof(encoded_public_key)); 102 sizeof(encoded_public_key));
115 103
116 /* marshal priv to dk as encoded_private_key */ 104 /* marshal priv to dk as encoded_private_key */
117 TEST(!encode_private_key(&priv, &encoded_private_key, 105 if (!mlkem768_encode_private_key(&priv, &encoded_private_key,
118 &encoded_private_key_len), "encode_private_key"); 106 &encoded_private_key_len))
107 errx(1, "mlkem768_encode_private_key");
119 108
120 /* hash in dk */ 109 /* hash in dk */
121 shake_update(&results, encoded_private_key, 110 shake_update(&results, encoded_private_key,
@@ -140,21 +129,21 @@ MlkemIterativeTest()
140 sizeof(invalid_ciphertext)); 129 sizeof(invalid_ciphertext));
141 130
142 /* generte k as shared secret from invalid ciphertext */ 131 /* generte k as shared secret from invalid ciphertext */
143 TEST(!MLKEM768_decap(shared_secret, invalid_ciphertext, 132 if (!MLKEM768_decap(shared_secret, invalid_ciphertext,
144 sizeof(invalid_ciphertext), &priv), "decap failed!"); 133 sizeof(invalid_ciphertext), &priv))
134 errx(1, "decap failed");
145 135
146 /* hash in k */ 136 /* hash in k */
147 shake_update(&results, shared_secret, sizeof(shared_secret)); 137 shake_update(&results, shared_secret, sizeof(shared_secret));
148 } 138 }
149 shake_xof(&results); 139 shake_xof(&results);
150 shake_out(&results, out, 32); 140 shake_out(&results, out, sizeof(out));
151 141
152 TEST_DATAEQ(out, kExpectedAdam, 32, "final result hash"); 142 return compare_data(kExpectedAdam, out, sizeof(out), i, "final result hash");
153} 143}
154 144
155int 145int
156main(int argc, char **argv) 146main(int argc, char **argv)
157{ 147{
158 MlkemIterativeTest(); 148 return MlkemIterativeTest();
159 exit(failure);
160} 149}
diff --git a/src/regress/lib/libcrypto/mlkem/mlkem768_keygen_tests.c b/src/regress/lib/libcrypto/mlkem/mlkem768_keygen_tests.c
index 7214dd8a80..be1aff3d04 100644
--- a/src/regress/lib/libcrypto/mlkem/mlkem768_keygen_tests.c
+++ b/src/regress/lib/libcrypto/mlkem/mlkem768_keygen_tests.c
@@ -1,7 +1,8 @@
1/* $OpenBSD: mlkem768_keygen_tests.c,v 1.4 2024/12/17 07:20:10 tb Exp $ */ 1/* $OpenBSD: mlkem768_keygen_tests.c,v 1.5 2024/12/20 00:07:12 tb Exp $ */
2/* 2/*
3 * Copyright (c) 2024, Google Inc. 3 * Copyright (c) 2024 Google Inc.
4 * Copyright (c) 2024, Bob Beck <beck@obtuse.com> 4 * Copyright (c) 2024 Bob Beck <beck@obtuse.com>
5 * Copyright (c) 2024 Theo Buehler <tb@openbsd.org>
5 * 6 *
6 * Permission to use, copy, modify, and/or distribute this software for any 7 * Permission to use, copy, modify, and/or distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above 8 * purpose with or without fee is hereby granted, provided that the above
@@ -16,115 +17,174 @@
16 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */ 18 */
18 19
20#include <assert.h>
21#include <err.h>
19#include <stdint.h> 22#include <stdint.h>
20#include <stdio.h> 23#include <stdio.h>
21#include <stdlib.h> 24#include <stdlib.h>
22#include <string.h>
23 25
24#include <openssl/bytestring.h> 26#include "bytestring.h"
25#include <openssl/mlkem.h> 27#include "mlkem.h"
26 28
27#include "mlkem_internal.h" 29#include "mlkem_internal.h"
28#include "mlkem_tests_util.h" 30#include "mlkem_tests_util.h"
29 31
30static int 32static int
31encode_private_key(const struct MLKEM768_private_key *priv, uint8_t **out_buf, 33MlkemKeygenFileTest(CBB *seed_cbb, CBB *public_key_cbb, CBB *private_key_cbb,
32 size_t *out_len) 34 size_t line)
33{
34 CBB cbb;
35 if (!CBB_init(&cbb, MLKEM768_PUBLIC_KEY_BYTES))
36 return 0;
37 if (!MLKEM768_marshal_private_key(&cbb, priv))
38 return 0;
39 if (!CBB_finish(&cbb, out_buf, out_len))
40 return 0;
41 CBB_cleanup(&cbb);
42 return 1;
43}
44
45static void
46MlkemKeygenFileTest(CBS *seed, CBS *public_key, CBS *private_key)
47{ 35{
48 struct MLKEM768_private_key priv; 36 struct MLKEM768_private_key priv;
37 uint8_t *seed = NULL, *public_key = NULL, *private_key = NULL;
38 size_t seed_len = 0, public_key_len = 0, private_key_len = 0;
49 uint8_t *encoded_private_key = NULL; 39 uint8_t *encoded_private_key = NULL;
50 uint8_t encoded_public_key[MLKEM768_PUBLIC_KEY_BYTES]; 40 uint8_t encoded_public_key[MLKEM768_PUBLIC_KEY_BYTES];
51 size_t len; 41 size_t len;
42 int failed = 1;
43
44 if (!CBB_finish(seed_cbb, &seed, &seed_len))
45 goto err;
46 if (!compare_length(MLKEM_SEED_BYTES, seed_len, line, "seed length"))
47 goto err;
48 if (!CBB_finish(public_key_cbb, &public_key, &public_key_len))
49 goto err;
50 if (!compare_length(MLKEM768_PUBLIC_KEY_BYTES, public_key_len, line,
51 "public key length"))
52 goto err;
53 if (!CBB_finish(private_key_cbb, &private_key, &private_key_len))
54 goto err;
55 if (!compare_length(MLKEM768_PUBLIC_KEY_BYTES, public_key_len, line,
56 "public key length"))
57 goto err;
52 58
53 TEST(CBS_len(seed) != MLKEM_SEED_BYTES, "seed len bogus");
54 TEST(CBS_len(private_key) != MLKEM768_PRIVATE_KEY_BYTES,
55 "expected private key len bogus");
56 TEST(CBS_len(public_key) != MLKEM768_PUBLIC_KEY_BYTES,
57 "expected public key len bogus");
58 MLKEM768_generate_key_external_entropy(encoded_public_key, &priv, 59 MLKEM768_generate_key_external_entropy(encoded_public_key, &priv,
59 CBS_data(seed)); 60 seed);
60 TEST(!encode_private_key(&priv, &encoded_private_key, 61 if (!mlkem768_encode_private_key(&priv, &encoded_private_key, &len)) {
61 &len), "encode_private_key"); 62 warnx("#%zu: encoded_private_key", line);
62 TEST(len != MLKEM768_PRIVATE_KEY_BYTES, "private key len bogus"); 63 goto err;
63 TEST_DATAEQ(encoded_public_key, CBS_data(public_key), 64 }
64 MLKEM768_PUBLIC_KEY_BYTES, "public key"); 65
65 TEST_DATAEQ(encoded_private_key, CBS_data(private_key), 66 if (!compare_length(MLKEM768_PRIVATE_KEY_BYTES, len, line,
66 MLKEM768_PRIVATE_KEY_BYTES, "private key"); 67 "private key length"))
68 goto err;
69
70 failed = compare_data(private_key, encoded_private_key,
71 MLKEM768_PRIVATE_KEY_BYTES, line, "private key");
72 failed |= compare_data(public_key, encoded_public_key,
73 MLKEM768_PUBLIC_KEY_BYTES, line, "public key");
74
75 err:
76 CBB_cleanup(seed_cbb);
77 CBB_cleanup(public_key_cbb);
78 CBB_cleanup(private_key_cbb);
79 freezero(seed, seed_len);
80 freezero(public_key, public_key_len);
81 freezero(private_key, private_key_len);
67 free(encoded_private_key); 82 free(encoded_private_key);
83
84 return failed;
68} 85}
69 86
70#define S_START 0 87#define S_START 0
71#define S_SEED 1 88#define S_COMMENT 1
72#define S_PUBLIC_KEY 2 89#define S_SEED 2
73#define S_PRIVATE_KEY 3 90#define S_PUBLIC_KEY 3
91#define S_PRIVATE_KEY 4
92
93#define S2S(x) case x: return #x
94
95static const char *
96state2str(int state)
97{
98 switch (state) {
99 S2S(S_START);
100 S2S(S_COMMENT);
101 S2S(S_SEED);
102 S2S(S_PUBLIC_KEY);
103 S2S(S_PRIVATE_KEY);
104 default:
105 errx(1, "unknown state %d", state);
106 }
107}
74 108
75int 109int
76main(int argc, char **argv) 110main(int argc, char **argv)
77{ 111{
78 CBS seed, public_key, private_key; 112 CBB seed = { 0 }, public_key = { 0 }, private_key = { 0 };
79 char *buf; 113 const char *test;
114 size_t line = 0;
115 char *buf = NULL;
116 size_t buflen = 0;
117 ssize_t len;
80 FILE *fp; 118 FILE *fp;
81 int state; 119 int state;
120 int failed = 0;
121
122 if (argc < 2)
123 errx(1, "%s: missing test file", argv[0]);
124
125 test = argv[1];
126
127 if ((fp = fopen(test, "r")) == NULL)
128 err(1, "cant't open test file");
129
130 state = S_COMMENT;
131 line = 0;
132
133 while ((len = getline(&buf, &buflen, fp)) != -1) {
134 const char *msg = state2str(state);
135 CBS cbs;
136 uint8_t u8;
137
138 line++;
139 CBS_init(&cbs, buf, len);
140
141 if (!CBS_get_last_u8(&cbs, &u8))
142 errx(1, "#%zu %s: CBB_get_last_u8", line, msg);
143 assert(u8 == '\n');
82 144
83 fprintf(stderr, "Testing keygen test vectors in %s\n", argv[1]);
84 TEST((fp = fopen(argv[1], "r")) == NULL, "can't open test file");
85 MALLOC(buf, 16*1024);
86 state = S_SEED;
87 test_number = 1;
88 while (fgets(buf, 16*1024, fp) != NULL) {
89 switch (state) { 145 switch (state) {
90 case S_START: 146 case S_START:
91 if (strcmp(buf, "\n") != 0) 147 state = S_COMMENT;
92 break; 148 break;
149 case S_COMMENT:
150 if (!CBS_get_u8(&cbs, &u8))
151 errx(1, "#%zu %s: CBB_get_u8", line, msg);
152 assert(u8 == '#');
153 if (!CBS_skip(&cbs, CBS_len(&cbs)))
154 errx(1, "#%zu %s: CBB_skip", line, msg);
93 state = S_SEED; 155 state = S_SEED;
94 break; 156 break;
95 case S_SEED: 157 case S_SEED:
96 if (strncmp(buf, "seed: ", strlen("seed: ")) != 0) { 158 if (!get_string_cbs(&cbs, "seed: ", line, msg))
97 break; 159 errx(1, "#%zu %s: get_string_cbs", line, msg);
98 } 160 hex_decode_cbs(&cbs, &seed, line, msg);
99 grab_data(&seed, buf, strlen("seed: "));
100 state = S_PUBLIC_KEY; 161 state = S_PUBLIC_KEY;
101 break; 162 break;
102 case S_PUBLIC_KEY: 163 case S_PUBLIC_KEY:
103 if (strncmp(buf, "public_key: ", 164 if (!get_string_cbs(&cbs, "public_key: ", line, msg))
104 strlen("public_key: ")) != 0) 165 errx(1, "#%zu %s: get_string_cbs", line, msg);
105 break; 166 hex_decode_cbs(&cbs, &public_key, line, msg);
106 grab_data(&public_key, buf, strlen("public_key: "));
107 state = S_PRIVATE_KEY; 167 state = S_PRIVATE_KEY;
108 break; 168 break;
109 case S_PRIVATE_KEY: 169 case S_PRIVATE_KEY:
110 if (strncmp(buf, "private_key: ", 170 if (!get_string_cbs(&cbs, "private_key: ", line, msg))
111 strlen("private_key: ")) != 0) 171 errx(1, "#%zu %s: get_string_cbs", line, msg);
112 break; 172 hex_decode_cbs(&cbs, &private_key, line, msg);
113 grab_data(&private_key, buf, strlen("private_key: "));
114 state = S_START;
115 173
116 MlkemKeygenFileTest(&seed, &public_key, &private_key); 174 failed |= MlkemKeygenFileTest(&seed, &public_key,
117 free((void *)CBS_data(&seed)); 175 &private_key, line);
118 free((void *)CBS_data(&public_key));
119 free((void *)CBS_data(&private_key));
120 176
121 test_number++;
122 state = S_START; 177 state = S_START;
123 break; 178 break;
124 } 179 }
180 if (CBS_len(&cbs) > 0)
181 errx(1, "#%zu %s: CBS_len", line, msg);
125 } 182 }
126
127 free(buf); 183 free(buf);
184
185 if (ferror(fp))
186 err(1, NULL);
128 fclose(fp); 187 fclose(fp);
129 exit(failure); 188
189 return failed;
130} 190}
diff --git a/src/regress/lib/libcrypto/mlkem/mlkem768_nist_decap_tests.c b/src/regress/lib/libcrypto/mlkem/mlkem768_nist_decap_tests.c
index 0778c921b6..c72ad5c388 100644
--- a/src/regress/lib/libcrypto/mlkem/mlkem768_nist_decap_tests.c
+++ b/src/regress/lib/libcrypto/mlkem/mlkem768_nist_decap_tests.c
@@ -1,7 +1,8 @@
1/* $OpenBSD: mlkem768_nist_decap_tests.c,v 1.2 2024/12/14 19:16:24 tb Exp $ */ 1/* $OpenBSD: mlkem768_nist_decap_tests.c,v 1.3 2024/12/20 00:07:12 tb Exp $ */
2/* 2/*
3 * Copyright (c) 2024, Google Inc. 3 * Copyright (c) 2024 Google Inc.
4 * Copyright (c) 2024, Bob Beck <beck@obtuse.com> 4 * Copyright (c) 2024 Bob Beck <beck@obtuse.com>
5 * Copyright (c) 2024 Theo Buehler <tb@openbsd.org>
5 * 6 *
6 * Permission to use, copy, modify, and/or distribute this software for any 7 * Permission to use, copy, modify, and/or distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above 8 * purpose with or without fee is hereby granted, provided that the above
@@ -16,96 +17,177 @@
16 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */ 18 */
18 19
20#include <assert.h>
21#include <err.h>
19#include <stdint.h> 22#include <stdint.h>
20#include <stdio.h> 23#include <stdio.h>
21#include <stdlib.h> 24#include <stdlib.h>
22#include <string.h>
23 25
24#include <openssl/bytestring.h> 26#include "bytestring.h"
25#include <openssl/mlkem.h> 27#include "mlkem.h"
26 28
27#include "mlkem_internal.h" 29#include "mlkem_internal.h"
28#include "mlkem_tests_util.h" 30#include "mlkem_tests_util.h"
29 31
30static void 32static int
31MlkemNistDecapFileTest(CBS *c, CBS *k, CBS *dk) 33MlkemNistDecapFileTest(CBB *c_cbb, CBB *k_cbb, CBS *dk, size_t line)
32{ 34{
35 uint8_t *c = NULL, *k = NULL;
36 size_t c_len = 0, k_len = 0;
33 uint8_t shared_secret[MLKEM_SHARED_SECRET_BYTES]; 37 uint8_t shared_secret[MLKEM_SHARED_SECRET_BYTES];
34 struct MLKEM768_private_key priv; 38 struct MLKEM768_private_key priv;
39 int failed = 1;
35 40
36 TEST(CBS_len(dk) != MLKEM768_PRIVATE_KEY_BYTES, 41 if (!CBB_finish(c_cbb, &c, &c_len))
37 "private key len bogus"); 42 goto err;
38 TEST(CBS_len(k) != MLKEM_SHARED_SECRET_BYTES, 43 if (!CBB_finish(k_cbb, &k, &k_len))
39 "shared secret len bogus"); 44 goto err;
40 45
41 TEST(!MLKEM768_parse_private_key(&priv, dk), "parse_private_key"); 46 if (!compare_length(MLKEM768_PRIVATE_KEY_BYTES, CBS_len(dk), line,
42 TEST(!MLKEM768_decap(shared_secret, CBS_data(c), CBS_len(c), &priv), 47 "private key len bogus"))
43 "decap"); 48 goto err;
44 TEST_DATAEQ(shared_secret, CBS_data(k), 49 if (!compare_length(MLKEM_SHARED_SECRET_BYTES, k_len, line,
45 MLKEM_SHARED_SECRET_BYTES, "shared_secret"); 50 "shared secret len bogus"))
51 goto err;
52
53 if (!MLKEM768_parse_private_key(&priv, dk)) {
54 warnx("#%zu MLKEM768_parse_private_key", line);
55 goto err;
56 }
57 if (!MLKEM768_decap(shared_secret, c, c_len, &priv)) {
58 warnx("#%zu MLKEM768_decap", line);
59 goto err;
60 }
61
62 failed = compare_data(shared_secret, k, k_len, line, "shared_secret");
63
64 err:
65 CBB_cleanup(c_cbb);
66 CBB_cleanup(k_cbb);
67 freezero(c, c_len);
68 freezero(k, k_len);
69
70 return failed;
46} 71}
47 72
48#define S_START 0 73#define S_START 0
49#define S_CIPHERTEXT 1 74#define S_C 1
50#define S_SHARED_SECRET 2 75#define S_K 2
51#define S_PRIVATE_KEY 3 76#define S_EMPTY 3
77
78#define S2S(x) case x: return #x
79
80static const char *
81state2str(int state)
82{
83 switch (state) {
84 S2S(S_START);
85 S2S(S_C);
86 S2S(S_K);
87 S2S(S_EMPTY);
88 default:
89 errx(1, "unknown state %d", state);
90 }
91}
52 92
53int 93int
54main(int argc, char **argv) 94main(int argc, char **argv)
55{ 95{
56 CBS ciphertext, shared_secret, private_key; 96 CBB dk_cbb = { 0 }, c = { 0 }, k = { 0 };
57 const uint8_t *p; 97 CBS instr;
58 char *buf; 98 uint8_t *dk = NULL;
99 size_t dk_len = 0;
100 uint8_t bracket, newline;
101 const char *test;
102 size_t line;
103 char *buf = NULL;
104 size_t buflen = 0;
105 ssize_t len;
59 FILE *fp; 106 FILE *fp;
60 int state; 107 int state;
108 int failed = 0;
109
110 if (argc < 2)
111 errx(1, "%s: missing test file", argv[0]);
112
113 test = argv[1];
114
115 if ((fp = fopen(test, "r")) == NULL)
116 err(1, "cant't open test file");
117
118 if ((len = getline(&buf, &buflen, fp)) == -1)
119 err(1, "failed to read instruction line");
120
121 /*
122 * The private key is enclosed in brackets in an "instruction line".
123 */
124 line = 1;
125 CBS_init(&instr, buf, len);
126 if (!CBS_get_u8(&instr, &bracket))
127 err(1, "failed to parse instruction line '['");
128 assert(bracket == '[');
129 if (!CBS_get_last_u8(&instr, &newline))
130 errx(1, "failed to parse instruction line '\\n'");
131 assert(newline == '\n');
132 if (!CBS_get_last_u8(&instr, &bracket))
133 errx(1, "failed to parse instruction line ']'");
134 assert(bracket == ']');
135 if (!get_string_cbs(&instr, "dk: ", line, "private key"))
136 errx(1, "failed to read instruction line 'dk: '");
137 hex_decode_cbs(&instr, &dk_cbb, line, "private key");
138 assert(CBS_len(&instr) == 0);
139
140 if (!CBB_finish(&dk_cbb, &dk, &dk_len))
141 errx(1, "CBB finish instruction line");
142
143 state = S_START;
144
145 while ((len = getline(&buf, &buflen, fp)) != -1) {
146 const char *msg = state2str(state);
147 CBS cbs, dk_cbs;
148 uint8_t u8;
149
150 line++;
151 CBS_init(&cbs, buf, len);
152
153 if (!CBS_get_last_u8(&cbs, &u8))
154 errx(1, "#%zu %s: CBB_get_last_u8", line, msg);
155 assert(u8 == '\n');
61 156
62 fprintf(stderr, "Testing NIST decap test vectors in %s\n", argv[1]);
63 TEST((fp = fopen(argv[1], "r")) == NULL, "can't open test file");
64 MALLOC(buf, 16*1024);
65 state = S_CIPHERTEXT;
66 test_number = 1;
67 while (fgets(buf, 16*1024, fp) != NULL) {
68 switch (state) { 157 switch (state) {
69 case S_START: 158 case S_START:
70 if (strcmp(buf, "\n") != 0) 159 state = S_C;
71 break;
72 state = S_CIPHERTEXT;
73 break; 160 break;
74 case S_CIPHERTEXT: 161 case S_C:
75 if (strncmp(buf, "ciphertext: ", 162 if (!get_string_cbs(&cbs, "c: ", line, msg))
76 strlen("ciphertext: ")) != 0) { 163 errx(1, "#%zu %s: get_string_cbs", line, msg);
77 break; 164 hex_decode_cbs(&cbs, &c, line, msg);
78 } 165 state = S_K;
79 grab_data(&ciphertext, buf, strlen("ciphertext: "));
80 state = S_SHARED_SECRET;
81 break; 166 break;
82 case S_SHARED_SECRET: 167 case S_K:
83 if (strncmp(buf, "shared_secret: ", 168 if (!get_string_cbs(&cbs, "k: ", line, msg))
84 strlen("shared_secret: ")) != 0) 169 errx(1, "#%zu %s: get_string_cbs", line, msg);
85 break; 170 hex_decode_cbs(&cbs, &k, line, msg);
86 grab_data(&shared_secret, buf, 171 state = S_EMPTY;
87 strlen("shared_secret: "));
88 state = S_PRIVATE_KEY;
89 break; 172 break;
90 case S_PRIVATE_KEY: 173 case S_EMPTY:
91 if (strncmp(buf, "private_key: ", 174 CBS_init(&dk_cbs, dk, dk_len);
92 strlen("private_key: ")) != 0) 175
93 break; 176 failed |= MlkemNistDecapFileTest(&c, &k, &dk_cbs, line);
94 grab_data(&private_key, buf, strlen("private_key: ")); 177
95 p = CBS_data(&private_key); 178 state = S_C;
96
97 MlkemNistDecapFileTest(&ciphertext, &shared_secret,
98 &private_key);
99 free((void *)CBS_data(&ciphertext));
100 free((void *)CBS_data(&shared_secret));
101 free((void *)p);
102
103 state = S_START;
104 test_number++;
105 break; 179 break;
106 } 180 }
181 if (CBS_len(&cbs) > 0)
182 errx(1, "#%zu %s: CBS_len", line, msg);
107 } 183 }
108
109 free(buf); 184 free(buf);
110 exit(failure); 185
186 if (ferror(fp))
187 err(1, NULL);
188 fclose(fp);
189
190 freezero(dk, dk_len);
191
192 return failed;
111} 193}
diff --git a/src/regress/lib/libcrypto/mlkem/mlkem768_nist_keygen_tests.c b/src/regress/lib/libcrypto/mlkem/mlkem768_nist_keygen_tests.c
index c239a54d5e..1f58c4c699 100644
--- a/src/regress/lib/libcrypto/mlkem/mlkem768_nist_keygen_tests.c
+++ b/src/regress/lib/libcrypto/mlkem/mlkem768_nist_keygen_tests.c
@@ -1,7 +1,8 @@
1/* $OpenBSD: mlkem768_nist_keygen_tests.c,v 1.3 2024/12/17 07:20:10 tb Exp $ */ 1/* $OpenBSD: mlkem768_nist_keygen_tests.c,v 1.4 2024/12/20 00:07:12 tb Exp $ */
2/* 2/*
3 * Copyright (c) 2024, Google Inc. 3 * Copyright (c) 2024 Google Inc.
4 * Copyright (c) 2024, Bob Beck <beck@obtuse.com> 4 * Copyright (c) 2024 Bob Beck <beck@obtuse.com>
5 * Copyright (c) 2024 Theo Buehler <tb@openbsd.org>
5 * 6 *
6 * Permission to use, copy, modify, and/or distribute this software for any 7 * Permission to use, copy, modify, and/or distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above 8 * purpose with or without fee is hereby granted, provided that the above
@@ -16,123 +17,181 @@
16 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */ 18 */
18 19
20#include <assert.h>
21#include <err.h>
19#include <stdint.h> 22#include <stdint.h>
20#include <stdio.h> 23#include <stdio.h>
21#include <stdlib.h> 24#include <stdlib.h>
22#include <string.h>
23 25
24#include <openssl/bytestring.h> 26#include "bytestring.h"
25#include <openssl/mlkem.h> 27#include "mlkem.h"
26 28
27#include "mlkem_internal.h" 29#include "mlkem_internal.h"
28#include "mlkem_tests_util.h" 30#include "mlkem_tests_util.h"
29 31
30static int 32static int
31encode_private_key(const struct MLKEM768_private_key *priv, uint8_t **out_buf, 33MlkemNistKeygenFileTest(CBB *z_cbb, CBB *d_cbb, CBB *ek_cbb, CBB *dk_cbb,
32 size_t *out_len) 34 size_t line)
33{
34 CBB cbb;
35 if (!CBB_init(&cbb, MLKEM768_PUBLIC_KEY_BYTES))
36 return 0;
37 if (!MLKEM768_marshal_private_key(&cbb, priv))
38 return 0;
39 if (!CBB_finish(&cbb, out_buf, out_len))
40 return 0;
41 CBB_cleanup(&cbb);
42 return 1;
43}
44
45static void
46MlkemNistKeygenFileTest(CBS *z, CBS *d, CBS *ek, CBS *dk)
47{ 35{
36 CBB seed_cbb;
37 uint8_t *z = NULL, *d = NULL, *ek = NULL, *dk = NULL;
38 size_t z_len = 0, d_len = 0, ek_len = 0, dk_len = 0;
48 uint8_t seed[MLKEM_SEED_BYTES]; 39 uint8_t seed[MLKEM_SEED_BYTES];
49 struct MLKEM768_private_key priv; 40 struct MLKEM768_private_key priv;
50 uint8_t *encoded_private_key = NULL; 41 uint8_t *encoded_private_key = NULL;
51 uint8_t encoded_public_key[MLKEM768_PUBLIC_KEY_BYTES]; 42 uint8_t encoded_public_key[MLKEM768_PUBLIC_KEY_BYTES];
52 size_t len; 43 size_t len;
44 int failed = 1;
45
46 if (!CBB_init_fixed(&seed_cbb, seed, sizeof(seed)))
47 goto err;
48
49 if (!CBB_finish(z_cbb, &z, &z_len))
50 goto err;
51 if (!CBB_finish(d_cbb, &d, &d_len))
52 goto err;
53 if (!CBB_finish(ek_cbb, &ek, &ek_len))
54 goto err;
55 if (!CBB_finish(dk_cbb, &dk, &dk_len))
56 goto err;
57
58 if (!CBB_add_bytes(&seed_cbb, d, d_len))
59 goto err;
60 if (!CBB_add_bytes(&seed_cbb, z, z_len))
61 goto err;
62 if (!CBB_finish(&seed_cbb, NULL, &len))
63 goto err;
64
65 if (!compare_length(MLKEM_SEED_BYTES, len, line, "z or d length bogus"))
66 goto err;
53 67
54 TEST(CBS_len(d) != (MLKEM_SEED_BYTES / 2), "d len bogus");
55 TEST(CBS_len(z) != (MLKEM_SEED_BYTES / 2), "z len bogus");
56 TEST(CBS_len(dk) != MLKEM768_PRIVATE_KEY_BYTES,
57 "expected private key len bogus");
58 TEST(CBS_len(ek) != MLKEM768_PUBLIC_KEY_BYTES,
59 "expected public key len bogus");
60 memcpy(&seed[0], CBS_data(d), CBS_len(d));
61 memcpy(&seed[MLKEM_SEED_BYTES / 2], CBS_data(z), CBS_len(z));
62 MLKEM768_generate_key_external_entropy(encoded_public_key, &priv, seed); 68 MLKEM768_generate_key_external_entropy(encoded_public_key, &priv, seed);
63 TEST(!encode_private_key(&priv, &encoded_private_key, 69
64 &len), "encode_private_key"); 70 if (!mlkem768_encode_private_key(&priv, &encoded_private_key, &len)) {
65 TEST(len != MLKEM768_PRIVATE_KEY_BYTES, "private key len bogus"); 71 warnx("#%zu mlkem768_encode_private_key", line);
66 TEST_DATAEQ(encoded_public_key, CBS_data(ek), 72 goto err;
67 MLKEM768_PUBLIC_KEY_BYTES, "public key"); 73 }
68 TEST_DATAEQ(encoded_private_key, CBS_data(dk), 74
69 MLKEM768_PRIVATE_KEY_BYTES, "private key"); 75 if (!compare_length(MLKEM768_PRIVATE_KEY_BYTES, len, line,
76 "private key length"))
77 goto err;
78
79 failed = compare_data(ek, encoded_public_key, MLKEM768_PUBLIC_KEY_BYTES,
80 line, "public key");
81 failed |= compare_data(dk, encoded_private_key, MLKEM768_PRIVATE_KEY_BYTES,
82 line, "private key");
83
84 err:
85 CBB_cleanup(&seed_cbb);
86 CBB_cleanup(z_cbb);
87 CBB_cleanup(d_cbb);
88 CBB_cleanup(ek_cbb);
89 CBB_cleanup(dk_cbb);
90 freezero(z, z_len);
91 freezero(d, d_len);
92 freezero(ek, ek_len);
93 freezero(dk, dk_len);
70 free(encoded_private_key); 94 free(encoded_private_key);
95
96 return failed;
71} 97}
72 98
73#define S_START 0 99#define S_START 0
74#define S_Z 1 100#define S_Z 1
75#define S_D 2 101#define S_D 2
76#define S_EK 3 102#define S_EK 3
77#define S_DK 4 103#define S_DK 4
104
105#define S2S(x) case x: return #x
106
107static const char *
108state2str(int state)
109{
110 switch (state) {
111 S2S(S_START);
112 S2S(S_Z);
113 S2S(S_D);
114 S2S(S_EK);
115 S2S(S_DK);
116 default:
117 errx(1, "unknown state %d", state);
118 }
119}
78 120
79int 121int
80main(int argc, char **argv) 122main(int argc, char **argv)
81{ 123{
82 CBS z, d, ek, dk; 124 CBB z = { 0 }, d = { 0 }, ek = { 0 }, dk = { 0 };
83 char *buf; 125 const char *test;
126 size_t line = 0;
127 char *buf = NULL;
128 size_t buflen = 0;
129 ssize_t len;
84 FILE *fp; 130 FILE *fp;
85 int state; 131 int state;
132 int failed = 0;
133
134 if (argc < 2)
135 errx(1, "%s: missing test file", argv[0]);
136
137 test = argv[1];
138
139 if ((fp = fopen(test, "r")) == NULL)
140 err(1, "cant't open test file");
86 141
87 fprintf(stderr, "Testing NIST keygen test vectors in %s\n", argv[1]);
88 TEST((fp = fopen(argv[1], "r")) == NULL, "can't open test file");
89 MALLOC(buf, 16*1024);
90 state = S_Z; 142 state = S_Z;
91 test_number = 1; 143 line = 0;
92 while (fgets(buf, 16*1024, fp) != NULL) { 144
145 while ((len = getline(&buf, &buflen, fp)) != -1) {
146 const char *msg = state2str(state);
147 CBS cbs;
148 uint8_t u8;
149
150 line++;
151 CBS_init(&cbs, buf, len);
152
153 if (!CBS_get_last_u8(&cbs, &u8))
154 errx(1, "#%zu %s: CBB_get_last_u8", line, msg);
155 assert(u8 == '\n');
156
93 switch (state) { 157 switch (state) {
94 case S_START: 158 case S_START:
95 if (strcmp(buf, "\n") != 0)
96 break;
97 state = S_Z; 159 state = S_Z;
98 break; 160 break;
99 case S_Z: 161 case S_Z:
100 if (strncmp(buf, "z: ", strlen("z: ")) != 0) { 162 if (!get_string_cbs(&cbs, "z: ", line, msg))
101 break; 163 errx(1, "#%zu %s: get_string_cbs", line, msg);
102 } 164 hex_decode_cbs(&cbs, &z, line, msg);
103 grab_data(&z, buf, strlen("z: "));
104 state = S_D; 165 state = S_D;
105 break; 166 break;
106 case S_D: 167 case S_D:
107 if (strncmp(buf, "d: ", strlen("d: ")) != 0) 168 if (!get_string_cbs(&cbs, "d: ", line, msg))
108 break; 169 errx(1, "#%zu %s: get_string_cbs", line, msg);
109 grab_data(&d, buf, strlen("d: ")); 170 hex_decode_cbs(&cbs, &d, line, msg);
110 state = S_EK; 171 state = S_EK;
111 break; 172 break;
112 case S_EK: 173 case S_EK:
113 if (strncmp(buf, "ek: ", strlen("ek: ")) != 0) 174 if (!get_string_cbs(&cbs, "ek: ", line, msg))
114 break; 175 errx(1, "#%zu %s: get_string_cbs", line, msg);
115 grab_data(&ek, buf, strlen("ek: ")); 176 hex_decode_cbs(&cbs, &ek, line, msg);
116 state = S_DK; 177 state = S_DK;
117 break; 178 break;
118 case S_DK: 179 case S_DK:
119 if (strncmp(buf, "dk: ", strlen("dk: ")) != 0) 180 if (!get_string_cbs(&cbs, "dk: ", line, msg))
120 break; 181 errx(1, "#%zu %s: get_string_cbs", line, msg);
121 grab_data(&dk, buf, strlen("dk: ")); 182 hex_decode_cbs(&cbs, &dk, line, msg);
122 183
123 MlkemNistKeygenFileTest(&z, &d, &ek, &dk); 184 failed |= MlkemNistKeygenFileTest(&z, &d, &ek, &dk, line);
124 free((void *)CBS_data(&z));
125 free((void *)CBS_data(&d));
126 free((void *)CBS_data(&ek));
127 free((void *)CBS_data(&dk));
128 185
129 test_number++;
130 state = S_START; 186 state = S_START;
131 break; 187 break;
132 } 188 }
133 } 189 }
134
135 free(buf); 190 free(buf);
191
192 if (ferror(fp))
193 err(1, NULL);
136 fclose(fp); 194 fclose(fp);
137 exit(failure); 195
196 return failed;
138} 197}
diff --git a/src/regress/lib/libcrypto/mlkem/mlkem_tests_util.c b/src/regress/lib/libcrypto/mlkem/mlkem_tests_util.c
index c4c13f0e7a..50a93027e2 100644
--- a/src/regress/lib/libcrypto/mlkem/mlkem_tests_util.c
+++ b/src/regress/lib/libcrypto/mlkem/mlkem_tests_util.c
@@ -1,7 +1,8 @@
1/* $OpenBSD: mlkem_tests_util.c,v 1.2 2024/12/14 19:16:24 tb Exp $ */ 1/* $OpenBSD: mlkem_tests_util.c,v 1.3 2024/12/20 00:07:12 tb Exp $ */
2/* 2/*
3 * Copyright (c) 2024, Google Inc. 3 * Copyright (c) 2024 Google Inc.
4 * Copyright (c) 2024, Bob Beck <beck@obtuse.com> 4 * Copyright (c) 2024 Bob Beck <beck@obtuse.com>
5 * Copyright (c) 2024 Theo Buehler <tb@openbsd.org>
5 * 6 *
6 * Permission to use, copy, modify, and/or distribute this software for any 7 * Permission to use, copy, modify, and/or distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above 8 * purpose with or without fee is hereby granted, provided that the above
@@ -19,15 +20,19 @@
19#include <err.h> 20#include <err.h>
20#include <stdint.h> 21#include <stdint.h>
21#include <stdio.h> 22#include <stdio.h>
22#include <stdlib.h>
23#include <string.h> 23#include <string.h>
24 24
25#include "bytestring.h"
26#include "mlkem.h"
27
28#include "mlkem_internal.h"
29
25#include "mlkem_tests_util.h" 30#include "mlkem_tests_util.h"
26 31
27int failure; 32int failure;
28int test_number; 33int test_number;
29 34
30void 35static void
31hexdump(const uint8_t *buf, size_t len, const uint8_t *compare) 36hexdump(const uint8_t *buf, size_t len, const uint8_t *compare)
32{ 37{
33 const char *mark = ""; 38 const char *mark = "";
@@ -43,32 +48,171 @@ hexdump(const uint8_t *buf, size_t len, const uint8_t *compare)
43} 48}
44 49
45int 50int
46hex_decode(char *buf, size_t len, uint8_t **out_buf, size_t *out_len) 51compare_data(const uint8_t *want, const uint8_t *got, size_t len, size_t line,
52 const char *msg)
47{ 53{
48 size_t i; 54 if (memcmp(want, got, len) == 0)
49 if (*out_buf != NULL) 55 return 0;
50 abort(); /* Du hast einin rotweinflarsche... */
51 56
52 MALLOC(*out_buf, len); 57 warnx("FAIL: #%zu - %s differs", line, msg);
53 *out_len = 0; 58 fprintf(stderr, "want:\n");
59 hexdump(want, len, got);
60 fprintf(stderr, "got:\n");
61 hexdump(got, len, want);
62 fprintf(stderr, "\n");
54 63
55 for (i = 0; i < len; i += 2) {
56 if (sscanf(buf + i, "%2hhx", *out_buf + *out_len) != 1)
57 err(1, "FAIL- hex decode failed for %d\n",
58 (int)*out_len);
59 (*out_len)++;
60 }
61 return 1; 64 return 1;
62} 65}
63 66
67int
68compare_length(size_t want, size_t got, size_t line, const char *msg)
69{
70 if (want == got)
71 return 1;
72
73 warnx("#%zu: %s: want %zu, got %zu", line, msg, want, got);
74 return 0;
75}
76
77static int
78hex_get_nibble_cbs(CBS *cbs, uint8_t *out_nibble)
79{
80 uint8_t c;
81
82 if (!CBS_get_u8(cbs, &c))
83 return 0;
84
85 if (c >= '0' && c <= '9') {
86 *out_nibble = c - '0';
87 return 1;
88 }
89 if (c >= 'a' && c <= 'f') {
90 *out_nibble = c - 'a' + 10;
91 return 1;
92 }
93 if (c >= 'A' && c <= 'F') {
94 *out_nibble = c - 'A' + 10;
95 return 1;
96 }
97
98 return 0;
99}
100
64void 101void
65grab_data(CBS *cbs, char *buf, size_t offset) 102hex_decode_cbs(CBS *cbs, CBB *cbb, size_t line, const char *msg)
103{
104 if (!CBB_init(cbb, 0))
105 errx(1, "#%zu %s: %s CBB_init", line, msg, __func__);
106
107 while (CBS_len(cbs) > 0) {
108 uint8_t hi, lo;
109
110 if (!hex_get_nibble_cbs(cbs, &hi))
111 errx(1, "#%zu %s: %s nibble", line, msg, __func__);
112 if (!hex_get_nibble_cbs(cbs, &lo))
113 errx(1, "#%zu %s: %s nibble", line, msg, __func__);
114
115 if (!CBB_add_u8(cbb, hi << 4 | lo))
116 errx(1, "#%zu %s: %s CBB_add_u8", line, msg, __func__);
117 }
118}
119
120int
121get_string_cbs(CBS *cbs_in, const char *str, size_t line, const char *msg)
122{
123 CBS cbs;
124 size_t len = strlen(str);
125
126 if (!CBS_get_bytes(cbs_in, &cbs, len))
127 errx(1, "#%zu %s: %s CBB_get_bytes", line, msg, __func__);
128
129 return CBS_mem_equal(&cbs, str, len);
130}
131
132int
133mlkem768_encode_private_key(const struct MLKEM768_private_key *priv,
134 uint8_t **out_buf, size_t *out_len)
135{
136 CBB cbb;
137 int ret = 0;
138
139 if (!CBB_init(&cbb, MLKEM768_PUBLIC_KEY_BYTES))
140 goto err;
141 if (!MLKEM768_marshal_private_key(&cbb, priv))
142 goto err;
143 if (!CBB_finish(&cbb, out_buf, out_len))
144 goto err;
145
146 ret = 1;
147
148 err:
149 CBB_cleanup(&cbb);
150
151 return ret;
152}
153
154int
155mlkem768_encode_public_key(const struct MLKEM768_public_key *pub,
156 uint8_t **out_buf, size_t *out_len)
66{ 157{
67 char *start = buf + offset; 158 CBB cbb;
68 size_t len = strlen(start); 159 int ret = 0;
69 uint8_t *new = NULL; 160
70 size_t new_len = 0; 161 if (!CBB_init(&cbb, MLKEM768_PUBLIC_KEY_BYTES))
71 /* This is hex encoded - decode it. */ 162 goto err;
72 TEST(!hex_decode(start, len - 1, &new, &new_len), "hex decode failed"); 163 if (!MLKEM768_marshal_public_key(&cbb, pub))
73 CBS_init(cbs, new, new_len); 164 goto err;
165 if (!CBB_finish(&cbb, out_buf, out_len))
166 goto err;
167
168 ret = 1;
169
170 err:
171 CBB_cleanup(&cbb);
172
173 return ret;
174}
175
176int
177mlkem1024_encode_private_key(const struct MLKEM1024_private_key *priv,
178 uint8_t **out_buf, size_t *out_len)
179{
180 CBB cbb;
181 int ret = 0;
182
183 if (!CBB_init(&cbb, MLKEM1024_PUBLIC_KEY_BYTES))
184 goto err;
185 if (!MLKEM1024_marshal_private_key(&cbb, priv))
186 goto err;
187 if (!CBB_finish(&cbb, out_buf, out_len))
188 goto err;
189
190 ret = 1;
191
192 err:
193 CBB_cleanup(&cbb);
194
195 return ret;
196}
197
198int
199mlkem1024_encode_public_key(const struct MLKEM1024_public_key *pub,
200 uint8_t **out_buf, size_t *out_len)
201{
202 CBB cbb;
203 int ret = 0;
204
205 if (!CBB_init(&cbb, MLKEM1024_PUBLIC_KEY_BYTES))
206 goto err;
207 if (!MLKEM1024_marshal_public_key(&cbb, pub))
208 goto err;
209 if (!CBB_finish(&cbb, out_buf, out_len))
210 goto err;
211
212 ret = 1;
213
214 err:
215 CBB_cleanup(&cbb);
216
217 return ret;
74} 218}
diff --git a/src/regress/lib/libcrypto/mlkem/mlkem_tests_util.h b/src/regress/lib/libcrypto/mlkem/mlkem_tests_util.h
index 934de44009..cbb0f83f8c 100644
--- a/src/regress/lib/libcrypto/mlkem/mlkem_tests_util.h
+++ b/src/regress/lib/libcrypto/mlkem/mlkem_tests_util.h
@@ -1,6 +1,7 @@
1/* $OpenBSD: mlkem_tests_util.h,v 1.2 2024/12/14 19:16:24 tb Exp $ */ 1/* $OpenBSD: mlkem_tests_util.h,v 1.3 2024/12/20 00:07:12 tb Exp $ */
2/* 2/*
3 * Copyright (c) 2024, Bob Beck <beck@obtuse.com> 3 * Copyright (c) 2024 Bob Beck <beck@obtuse.com>
4 * Copyright (c) 2024 Theo Buehler <tb@openbsd.org>
4 * 5 *
5 * Permission to use, copy, modify, and/or distribute this software for any 6 * Permission to use, copy, modify, and/or distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above 7 * purpose with or without fee is hereby granted, provided that the above
@@ -18,47 +19,31 @@
18#ifndef MLKEM_TEST_UTIL_H 19#ifndef MLKEM_TEST_UTIL_H
19#define MLKEM_TEST_UTIL_H 20#define MLKEM_TEST_UTIL_H
20 21
22#include <stddef.h>
21#include <stdint.h> 23#include <stdint.h>
22#include <stdio.h>
23#include <stdlib.h>
24#include <string.h>
25 24
26#include <openssl/bytestring.h> 25#include "bytestring.h"
27 26
28#define TEST(cond, msg) do { \ 27struct MLKEM1024_private_key;
29 if ((cond)) { \ 28struct MLKEM1024_public_key;
30 failure = 1; \ 29struct MLKEM768_private_key;
31 fprintf(stderr, "FAIL: %s:%d - Test %d: %s\n", \ 30struct MLKEM768_public_key;
32 __FILE__, __LINE__, test_number, msg); \
33 } \
34} while(0)
35 31
36#define MALLOC(A, B) do { \ 32/* XXX - return values of the two compare functions are inconsistent */
37 if (((A) = malloc(B)) == NULL) { \ 33int compare_data(const uint8_t *want, const uint8_t *got, size_t len,
38 failure = 1; \ 34 size_t line, const char *msg);
39 fprintf(stderr, "FAIL: %s:%d - Test %d: malloc\n", \ 35int compare_length(size_t want, size_t got, size_t line, const char *msg);
40 __FILE__, __LINE__, test_number); \
41 exit(1); \
42 } \
43} while(0)
44 36
45#define TEST_DATAEQ(values, expected, len, msg) do { \ 37void hex_decode_cbs(CBS *cbs, CBB *cbb, size_t line, const char *msg);
46 if (memcmp((values), (expected), (len)) != 0) { \ 38int get_string_cbs(CBS *cbs, const char *str, size_t line, const char *msg);
47 failure = 1; \
48 fprintf(stderr, "FAIL: %s:%d - Test %d: %s differs\n", \
49 __FILE__, __LINE__, test_number, msg); \
50 fprintf(stderr, "values:\n"); \
51 hexdump(values, len, expected); \
52 fprintf(stderr, "expected:\n"); \
53 hexdump(expected, len, values); \
54 fprintf(stderr, "\n"); \
55 } \
56} while(0)
57 39
58extern int failure, test_number; 40int mlkem768_encode_private_key(const struct MLKEM768_private_key *priv,
41 uint8_t **out_buf, size_t *out_len);
42int mlkem768_encode_public_key(const struct MLKEM768_public_key *pub,
43 uint8_t **out_buf, size_t *out_len);
44int mlkem1024_encode_private_key(const struct MLKEM1024_private_key *priv,
45 uint8_t **out_buf, size_t *out_len);
46int mlkem1024_encode_public_key(const struct MLKEM1024_public_key *pub,
47 uint8_t **out_buf, size_t *out_len);
59 48
60void hexdump(const uint8_t *buf, size_t len, const uint8_t *compare); 49#endif /* MLKEM_TEST_UTIL_H */
61int hex_decode(char *buf, size_t len, uint8_t **out_buf, size_t *out_len);
62void grab_data(CBS *cbs, char *buf, size_t offset);
63
64#endif
diff --git a/src/regress/lib/libcrypto/mlkem/mlkem_unittest.c b/src/regress/lib/libcrypto/mlkem/mlkem_unittest.c
index b8779135e5..18bf128bea 100644
--- a/src/regress/lib/libcrypto/mlkem/mlkem_unittest.c
+++ b/src/regress/lib/libcrypto/mlkem/mlkem_unittest.c
@@ -1,7 +1,7 @@
1/* $OpenBSD: mlkem_unittest.c,v 1.3 2024/12/14 19:16:24 tb Exp $ */ 1/* $OpenBSD: mlkem_unittest.c,v 1.4 2024/12/20 00:07:12 tb Exp $ */
2/* 2/*
3 * Copyright (c) 2024, Google Inc. 3 * Copyright (c) 2024 Google Inc.
4 * Copyright (c) 2024, Bob Beck <beck@obtuse.com> 4 * Copyright (c) 2024 Bob Beck <beck@obtuse.com>
5 * 5 *
6 * Permission to use, copy, modify, and/or distribute this software for any 6 * Permission to use, copy, modify, and/or distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above 7 * purpose with or without fee is hereby granted, provided that the above
@@ -16,52 +16,22 @@
16 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */ 17 */
18 18
19#include <err.h>
19#include <stdint.h> 20#include <stdint.h>
20#include <stdio.h> 21#include <stdio.h>
21#include <stdlib.h> 22#include <stdlib.h>
22#include <string.h> 23#include <string.h>
23 24
24#include <openssl/bytestring.h> 25#include "bytestring.h"
25#include <openssl/mlkem.h> 26#include "mlkem.h"
26 27
27#include "mlkem_internal.h"
28#include "mlkem_tests_util.h" 28#include "mlkem_tests_util.h"
29 29
30static int 30static int
31encode_public_key(const struct MLKEM768_public_key *pub, uint8_t **out_buf, 31MlKem768UnitTest(void)
32 size_t *out_len)
33{ 32{
34 CBB cbb; 33 struct MLKEM768_private_key priv = { 0 }, priv2 = { 0 };
35 if (!CBB_init(&cbb, MLKEM768_PUBLIC_KEY_BYTES)) 34 struct MLKEM768_public_key pub = { 0 }, pub2 = { 0 };
36 return 0;
37 if (!MLKEM768_marshal_public_key(&cbb, pub))
38 return 0;
39 if (!CBB_finish(&cbb, out_buf, out_len))
40 return 0;
41 CBB_cleanup(&cbb);
42 return 1;
43}
44
45static int
46encode_private_key(const struct MLKEM768_private_key *priv, uint8_t **out_buf,
47 size_t *out_len)
48{
49 CBB cbb;
50 if (!CBB_init(&cbb, MLKEM768_PUBLIC_KEY_BYTES))
51 return 0;
52 if (!MLKEM768_marshal_private_key(&cbb, priv))
53 return 0;
54 if (!CBB_finish(&cbb, out_buf, out_len))
55 return 0;
56 CBB_cleanup(&cbb);
57 return 1;
58}
59
60static void
61MlKem768UnitTest()
62{
63 struct MLKEM768_private_key *priv, *priv2;
64 struct MLKEM768_public_key *pub, *pub2;
65 uint8_t encoded_public_key[MLKEM768_PUBLIC_KEY_BYTES]; 35 uint8_t encoded_public_key[MLKEM768_PUBLIC_KEY_BYTES];
66 uint8_t ciphertext[MLKEM768_CIPHERTEXT_BYTES]; 36 uint8_t ciphertext[MLKEM768_CIPHERTEXT_BYTES];
67 uint8_t shared_secret1[MLKEM_SHARED_SECRET_BYTES]; 37 uint8_t shared_secret1[MLKEM_SHARED_SECRET_BYTES];
@@ -70,123 +40,138 @@ MlKem768UnitTest()
70 uint8_t *encoded_private_key = NULL, *tmp_buf = NULL; 40 uint8_t *encoded_private_key = NULL, *tmp_buf = NULL;
71 size_t encoded_private_key_len, tmp_buf_len; 41 size_t encoded_private_key_len, tmp_buf_len;
72 CBS cbs; 42 CBS cbs;
43 int failed = 0;
73 44
74 fprintf(stderr, "ML-KEM 768...\n"); 45 MLKEM768_generate_key(encoded_public_key, NULL, &priv);
75
76 MALLOC(priv, sizeof(struct MLKEM768_private_key));
77 MLKEM768_generate_key(encoded_public_key, NULL, priv);
78 46
79 memcpy(first_two_bytes, encoded_public_key, sizeof(first_two_bytes)); 47 memcpy(first_two_bytes, encoded_public_key, sizeof(first_two_bytes));
80 memset(encoded_public_key, 0xff, sizeof(first_two_bytes)); 48 memset(encoded_public_key, 0xff, sizeof(first_two_bytes));
81 CBS_init(&cbs, encoded_public_key, 49
82 sizeof(encoded_public_key)); 50 CBS_init(&cbs, encoded_public_key, sizeof(encoded_public_key));
83 MALLOC(pub, sizeof(struct MLKEM768_public_key)); 51
84 /* Parsing should fail because the first coefficient is >= kPrime; */ 52 /* Parsing should fail because the first coefficient is >= kPrime. */
85 TEST(MLKEM768_parse_public_key(pub, &cbs), 53 if (MLKEM768_parse_public_key(&pub, &cbs)) {
86 "Kyber_parse_public_key should have failed"); 54 warnx("MLKEM768_parse_public_key should have failed");
55 failed |= 1;
56 }
87 57
88 memcpy(encoded_public_key, first_two_bytes, sizeof(first_two_bytes)); 58 memcpy(encoded_public_key, first_two_bytes, sizeof(first_two_bytes));
89 CBS_init(&cbs, encoded_public_key, sizeof(encoded_public_key)); 59 CBS_init(&cbs, encoded_public_key, sizeof(encoded_public_key));
90 TEST(!MLKEM768_parse_public_key(pub, &cbs), 60 if (!MLKEM768_parse_public_key(&pub, &cbs)) {
91 "MLKEM768_parse_public_key"); 61 warnx("MLKEM768_parse_public_key");
92 TEST(CBS_len(&cbs) != 0u, "CBS_len must be 0"); 62 failed |= 1;
93 63 }
94 TEST(!encode_public_key(pub, &tmp_buf, &tmp_buf_len), 64
95 "encode_public_key"); 65 if (CBS_len(&cbs) != 0u) {
96 TEST(sizeof(encoded_public_key) != tmp_buf_len, 66 warnx("CBS_len must be 0");
97 "encoded public key lengths differ"); 67 failed |= 1;
98 TEST_DATAEQ(tmp_buf, encoded_public_key, tmp_buf_len, 68 }
99 "encoded public keys"); 69
70 if (!mlkem768_encode_public_key(&pub, &tmp_buf, &tmp_buf_len)) {
71 warnx("encode_public_key");
72 failed |= 1;
73 }
74 if (sizeof(encoded_public_key) != tmp_buf_len) {
75 warnx("mlkem768 encoded public key lengths differ");
76 failed |= 1;
77 }
78
79 if (compare_data(encoded_public_key, tmp_buf, tmp_buf_len, 768,
80 "encoded public keys") != 0) {
81 warnx("compare_data");
82 failed |= 1;
83 }
100 free(tmp_buf); 84 free(tmp_buf);
101 tmp_buf = NULL; 85 tmp_buf = NULL;
102 86
103 MALLOC(pub2, sizeof(struct MLKEM768_public_key)); 87 MLKEM768_public_from_private(&pub2, &priv);
104 MLKEM768_public_from_private(pub2, priv); 88 if (!mlkem768_encode_public_key(&pub2, &tmp_buf, &tmp_buf_len)) {
105 TEST(!encode_public_key(pub2, &tmp_buf, &tmp_buf_len), 89 warnx("mlkem768_encode_public_key");
106 "encode_public_key"); 90 failed |= 1;
107 TEST(sizeof(encoded_public_key) != tmp_buf_len, 91 }
108 "encoded public key lengths differ"); 92 if (sizeof(encoded_public_key) != tmp_buf_len) {
109 TEST_DATAEQ(tmp_buf, encoded_public_key, tmp_buf_len, 93 warnx("mlkem768 encoded public key lengths differ");
110 "encoded pubic keys"); 94 failed |= 1;
95 }
96
97 if (compare_data(encoded_public_key, tmp_buf, tmp_buf_len, 768,
98 "encoded public keys") != 0) {
99 warnx("compare_data");
100 failed |= 1;
101 }
111 free(tmp_buf); 102 free(tmp_buf);
112 tmp_buf = NULL; 103 tmp_buf = NULL;
113 104
114 TEST(!encode_private_key(priv, &encoded_private_key, 105 if (!mlkem768_encode_private_key(&priv, &encoded_private_key,
115 &encoded_private_key_len), "encode_private_key"); 106 &encoded_private_key_len)) {
107 warnx("mlkem768_encode_private_key");
108 failed |= 1;
109 }
116 110
117 memcpy(first_two_bytes, encoded_private_key, sizeof(first_two_bytes)); 111 memcpy(first_two_bytes, encoded_private_key, sizeof(first_two_bytes));
118 memset(encoded_private_key, 0xff, sizeof(first_two_bytes)); 112 memset(encoded_private_key, 0xff, sizeof(first_two_bytes));
119 CBS_init(&cbs, encoded_private_key, encoded_private_key_len); 113 CBS_init(&cbs, encoded_private_key, encoded_private_key_len);
120 MALLOC(priv2, sizeof(struct MLKEM768_private_key)); 114
121 /* Parsing should fail because the first coefficient is >= kPrime. */ 115 /* Parsing should fail because the first coefficient is >= kPrime. */
122 TEST(MLKEM768_parse_private_key(priv2, &cbs), "Should not have parsed"); 116 if (MLKEM768_parse_private_key(&priv2, &cbs)) {
117 warnx("MLKEM768_parse_private_key should have failed");
118 failed |= 1;
119 }
123 120
124 memcpy(encoded_private_key, first_two_bytes, sizeof(first_two_bytes)); 121 memcpy(encoded_private_key, first_two_bytes, sizeof(first_two_bytes));
125 CBS_init(&cbs, encoded_private_key, encoded_private_key_len); 122 CBS_init(&cbs, encoded_private_key, encoded_private_key_len);
126 TEST(!MLKEM768_parse_private_key(priv2, &cbs), 123
127 "MLKEM768_parse_private_key"); 124 if (!MLKEM768_parse_private_key(&priv2, &cbs)) {
128 TEST(!encode_private_key(priv2, &tmp_buf, &tmp_buf_len), 125 warnx("MLKEM768_parse_private_key");
129 "encode_private_key"); 126 failed |= 1;
130 TEST(encoded_private_key_len != tmp_buf_len, 127 }
131 "encoded private key lengths differ"); 128
132 TEST_DATAEQ(tmp_buf, encoded_private_key, encoded_private_key_len, 129 if (!mlkem768_encode_private_key(&priv2, &tmp_buf, &tmp_buf_len)) {
133 "encoded private keys"); 130 warnx("mlkem768_encode_private_key");
131 failed |= 1;
132 }
133
134 if (encoded_private_key_len != tmp_buf_len) {
135 warnx("mlkem768 encode private key lengths differ");
136 failed |= 1;
137 }
138
139 if (compare_data(encoded_private_key, tmp_buf, tmp_buf_len, 768,
140 "encoded private key") != 0) {
141 warnx("compare_data");
142 failed |= 1;
143 }
144
134 free(tmp_buf); 145 free(tmp_buf);
135 tmp_buf = NULL; 146 tmp_buf = NULL;
136 147
137 MLKEM768_encap(ciphertext, shared_secret1, pub); 148 MLKEM768_encap(ciphertext, shared_secret1, &pub);
138 MLKEM768_decap(shared_secret2, ciphertext, MLKEM768_CIPHERTEXT_BYTES, 149 MLKEM768_decap(shared_secret2, ciphertext, MLKEM768_CIPHERTEXT_BYTES,
139 priv); 150 &priv);
140 TEST_DATAEQ(shared_secret1, shared_secret2, MLKEM_SHARED_SECRET_BYTES, 151 if (compare_data(shared_secret1, shared_secret2, MLKEM_SHARED_SECRET_BYTES,
141 "shared secrets with priv"); 152 768, "shared secrets with priv") != 0) {
153 warnx("compare_data");
154 failed |= 1;
155 }
156
142 MLKEM768_decap(shared_secret2, ciphertext, MLKEM768_CIPHERTEXT_BYTES, 157 MLKEM768_decap(shared_secret2, ciphertext, MLKEM768_CIPHERTEXT_BYTES,
143 priv2); 158 &priv2);
144 TEST_DATAEQ(shared_secret1, shared_secret2, MLKEM_SHARED_SECRET_BYTES, 159 if (compare_data(shared_secret1, shared_secret2, MLKEM_SHARED_SECRET_BYTES,
145 "shared secrets with priv2"); 160 768, "shared secrets with priv2") != 0) {
161 warnx("compare_data");
162 failed |= 1;
163 }
146 164
147 free(encoded_private_key); 165 free(encoded_private_key);
148 free(pub);
149 free(pub2);
150 free(priv);
151 free(priv2);
152
153}
154 166
155static int 167 return failed;
156encode_1024public_key(const struct MLKEM1024_public_key *pub, uint8_t **out_buf,
157 size_t *out_len)
158{
159 CBB cbb;
160 if (!CBB_init(&cbb, MLKEM1024_PUBLIC_KEY_BYTES))
161 return 0;
162 if (!MLKEM1024_marshal_public_key(&cbb, pub))
163 return 0;
164 if (!CBB_finish(&cbb, out_buf, out_len))
165 return 0;
166 CBB_cleanup(&cbb);
167 return 1;
168} 168}
169 169
170static int 170static int
171encode_1024private_key(const struct MLKEM1024_private_key *priv, uint8_t **out_buf, 171MlKem1024UnitTest(void)
172 size_t *out_len)
173{
174 CBB cbb;
175 if (!CBB_init(&cbb, MLKEM1024_PUBLIC_KEY_BYTES))
176 return 0;
177 if (!MLKEM1024_marshal_private_key(&cbb, priv))
178 return 0;
179 if (!CBB_finish(&cbb, out_buf, out_len))
180 return 0;
181 CBB_cleanup(&cbb);
182 return 1;
183}
184
185static void
186MlKem1024UnitTest()
187{ 172{
188 struct MLKEM1024_private_key *priv, *priv2; 173 struct MLKEM1024_private_key priv = { 0 }, priv2 = { 0 };
189 struct MLKEM1024_public_key *pub, *pub2; 174 struct MLKEM1024_public_key pub = { 0 }, pub2 = { 0 };
190 uint8_t encoded_public_key[MLKEM1024_PUBLIC_KEY_BYTES]; 175 uint8_t encoded_public_key[MLKEM1024_PUBLIC_KEY_BYTES];
191 uint8_t ciphertext[MLKEM1024_CIPHERTEXT_BYTES]; 176 uint8_t ciphertext[MLKEM1024_CIPHERTEXT_BYTES];
192 uint8_t shared_secret1[MLKEM_SHARED_SECRET_BYTES]; 177 uint8_t shared_secret1[MLKEM_SHARED_SECRET_BYTES];
@@ -195,92 +180,140 @@ MlKem1024UnitTest()
195 uint8_t *encoded_private_key = NULL, *tmp_buf = NULL; 180 uint8_t *encoded_private_key = NULL, *tmp_buf = NULL;
196 size_t encoded_private_key_len, tmp_buf_len; 181 size_t encoded_private_key_len, tmp_buf_len;
197 CBS cbs; 182 CBS cbs;
183 int failed = 0;
198 184
199 fprintf(stderr, "ML-KEM 1024...\n"); 185 MLKEM1024_generate_key(encoded_public_key, NULL, &priv);
200
201 MALLOC(priv, sizeof(struct MLKEM1024_private_key));
202 MLKEM1024_generate_key(encoded_public_key, NULL, priv);
203 186
204 memcpy(first_two_bytes, encoded_public_key, sizeof(first_two_bytes)); 187 memcpy(first_two_bytes, encoded_public_key, sizeof(first_two_bytes));
205 memset(encoded_public_key, 0xff, sizeof(first_two_bytes)); 188 memset(encoded_public_key, 0xff, sizeof(first_two_bytes));
206 CBS_init(&cbs, encoded_public_key, 189
207 sizeof(encoded_public_key)); 190 CBS_init(&cbs, encoded_public_key, sizeof(encoded_public_key));
208 MALLOC(pub, sizeof(struct MLKEM1024_public_key)); 191
209 /* Parsing should fail because the first coefficient is >= kPrime; */ 192 /* Parsing should fail because the first coefficient is >= kPrime. */
210 TEST(MLKEM1024_parse_public_key(pub, &cbs), 193 if (MLKEM1024_parse_public_key(&pub, &cbs)) {
211 "Kyber_parse_public_key should have failed"); 194 warnx("MLKEM1024_parse_public_key should have failed");
195 failed |= 1;
196 }
212 197
213 memcpy(encoded_public_key, first_two_bytes, sizeof(first_two_bytes)); 198 memcpy(encoded_public_key, first_two_bytes, sizeof(first_two_bytes));
214 CBS_init(&cbs, encoded_public_key, sizeof(encoded_public_key)); 199 CBS_init(&cbs, encoded_public_key, sizeof(encoded_public_key));
215 TEST(!MLKEM1024_parse_public_key(pub, &cbs), 200 if (!MLKEM1024_parse_public_key(&pub, &cbs)) {
216 "MLKEM1024_parse_public_key"); 201 warnx("MLKEM1024_parse_public_key");
217 TEST(CBS_len(&cbs) != 0u, "CBS_len must be 0"); 202 failed |= 1;
218 203 }
219 TEST(!encode_1024public_key(pub, &tmp_buf, &tmp_buf_len), 204
220 "encode_1024public_key"); 205 if (CBS_len(&cbs) != 0u) {
221 TEST(sizeof(encoded_public_key) != tmp_buf_len, 206 warnx("CBS_len must be 0");
222 "encoded public key lengths differ"); 207 failed |= 1;
223 TEST_DATAEQ(tmp_buf, encoded_public_key, tmp_buf_len, 208 }
224 "encoded public keys"); 209
210 if (!mlkem1024_encode_public_key(&pub, &tmp_buf, &tmp_buf_len)) {
211 warnx("encode_public_key");
212 failed |= 1;
213 }
214 if (sizeof(encoded_public_key) != tmp_buf_len) {
215 warnx("mlkem1024 encoded public key lengths differ");
216 failed |= 1;
217 }
218
219 if (compare_data(encoded_public_key, tmp_buf, tmp_buf_len, 1024,
220 "encoded public keys") != 0) {
221 warnx("compare_data");
222 failed |= 1;
223 }
225 free(tmp_buf); 224 free(tmp_buf);
226 tmp_buf = NULL; 225 tmp_buf = NULL;
227 226
228 MALLOC(pub2, sizeof(struct MLKEM1024_public_key)); 227 MLKEM1024_public_from_private(&pub2, &priv);
229 MLKEM1024_public_from_private(pub2, priv); 228 if (!mlkem1024_encode_public_key(&pub2, &tmp_buf, &tmp_buf_len)) {
230 TEST(!encode_1024public_key(pub2, &tmp_buf, &tmp_buf_len), 229 warnx("mlkem1024_encode_public_key");
231 "encode_public_key"); 230 failed |= 1;
232 TEST(sizeof(encoded_public_key) != tmp_buf_len, 231 }
233 "encoded public key lengths differ"); 232 if (sizeof(encoded_public_key) != tmp_buf_len) {
234 TEST_DATAEQ(tmp_buf, encoded_public_key, tmp_buf_len, 233 warnx("mlkem1024 encoded public key lengths differ");
235 "encoded pubic keys"); 234 failed |= 1;
235 }
236
237 if (compare_data(encoded_public_key, tmp_buf, tmp_buf_len, 1024,
238 "encoded public keys") != 0) {
239 warnx("compare_data");
240 failed |= 1;
241 }
236 free(tmp_buf); 242 free(tmp_buf);
237 tmp_buf = NULL; 243 tmp_buf = NULL;
238 244
239 TEST(!encode_1024private_key(priv, &encoded_private_key, 245 if (!mlkem1024_encode_private_key(&priv, &encoded_private_key,
240 &encoded_private_key_len), "encode_1024private_key"); 246 &encoded_private_key_len)) {
247 warnx("mlkem1024_encode_private_key");
248 failed |= 1;
249 }
241 250
242 memcpy(first_two_bytes, encoded_private_key, sizeof(first_two_bytes)); 251 memcpy(first_two_bytes, encoded_private_key, sizeof(first_two_bytes));
243 memset(encoded_private_key, 0xff, sizeof(first_two_bytes)); 252 memset(encoded_private_key, 0xff, sizeof(first_two_bytes));
244 CBS_init(&cbs, encoded_private_key, encoded_private_key_len); 253 CBS_init(&cbs, encoded_private_key, encoded_private_key_len);
245 MALLOC(priv2, sizeof(struct MLKEM1024_private_key)); 254
246 /* Parsing should fail because the first coefficient is >= kPrime. */ 255 /* Parsing should fail because the first coefficient is >= kPrime. */
247 TEST(MLKEM1024_parse_private_key(priv2, &cbs), "Should not have parsed"); 256 if (MLKEM1024_parse_private_key(&priv2, &cbs)) {
257 warnx("MLKEM1024_parse_private_key should have failed");
258 failed |= 1;
259 }
248 260
249 memcpy(encoded_private_key, first_two_bytes, sizeof(first_two_bytes)); 261 memcpy(encoded_private_key, first_two_bytes, sizeof(first_two_bytes));
250 CBS_init(&cbs, encoded_private_key, encoded_private_key_len); 262 CBS_init(&cbs, encoded_private_key, encoded_private_key_len);
251 TEST(!MLKEM1024_parse_private_key(priv2, &cbs), 263
252 "MLKEM1024_parse_private_key"); 264 if (!MLKEM1024_parse_private_key(&priv2, &cbs)) {
253 TEST(!encode_1024private_key(priv2, &tmp_buf, &tmp_buf_len), 265 warnx("MLKEM1024_parse_private_key");
254 "encode_private_key"); 266 failed |= 1;
255 TEST(encoded_private_key_len != tmp_buf_len, 267 }
256 "encoded private key lengths differ"); 268
257 TEST_DATAEQ(tmp_buf, encoded_private_key, encoded_private_key_len, 269 if (!mlkem1024_encode_private_key(&priv2, &tmp_buf, &tmp_buf_len)) {
258 "encoded private keys"); 270 warnx("mlkem1024_encode_private_key");
271 failed |= 1;
272 }
273
274 if (encoded_private_key_len != tmp_buf_len) {
275 warnx("mlkem1024 encode private key lengths differ");
276 failed |= 1;
277 }
278
279 if (compare_data(encoded_private_key, tmp_buf, tmp_buf_len, 1024,
280 "encoded private key") != 0) {
281 warnx("compare_data");
282 failed |= 1;
283 }
284
259 free(tmp_buf); 285 free(tmp_buf);
260 tmp_buf = NULL; 286 tmp_buf = NULL;
261 287
262 MLKEM1024_encap(ciphertext, shared_secret1, pub); 288 MLKEM1024_encap(ciphertext, shared_secret1, &pub);
263 MLKEM1024_decap(shared_secret2, ciphertext, MLKEM1024_CIPHERTEXT_BYTES, 289 MLKEM1024_decap(shared_secret2, ciphertext, MLKEM1024_CIPHERTEXT_BYTES,
264 priv); 290 &priv);
265 TEST_DATAEQ(shared_secret1, shared_secret2, MLKEM_SHARED_SECRET_BYTES, 291 if (compare_data(shared_secret1, shared_secret2, MLKEM_SHARED_SECRET_BYTES,
266 "shared secrets with priv"); 292 1024, "shared secrets with priv") != 0) {
293 warnx("compare_data");
294 failed |= 1;
295 }
296
267 MLKEM1024_decap(shared_secret2, ciphertext, MLKEM1024_CIPHERTEXT_BYTES, 297 MLKEM1024_decap(shared_secret2, ciphertext, MLKEM1024_CIPHERTEXT_BYTES,
268 priv2); 298 &priv2);
269 TEST_DATAEQ(shared_secret1, shared_secret2, MLKEM_SHARED_SECRET_BYTES, 299 if (compare_data(shared_secret1, shared_secret2, MLKEM_SHARED_SECRET_BYTES,
270 "shared secrets with priv2"); 300 1024, "shared secrets with priv2") != 0) {
301 warnx("compare_data");
302 failed |= 1;
303 }
271 304
272 free(encoded_private_key); 305 free(encoded_private_key);
273 free(pub); 306
274 free(pub2); 307 return failed;
275 free(priv);
276 free(priv2);
277} 308}
278 309
279int 310int
280main(int argc, char **argv) 311main(int argc, char **argv)
281{ 312{
282 MlKem768UnitTest(); 313 int failed = 0;
283 MlKem1024UnitTest(); 314
315 failed |= MlKem768UnitTest();
316 failed |= MlKem1024UnitTest();
284 317
285 exit(failure); 318 return failed;
286} 319}