xref: /openbsd-src/regress/lib/libcrypto/mlkem/mlkem_tests.c (revision 1d58e56aa6b8deeafd9c883088a8883dadab7401)
1 /*	$OpenBSD: mlkem_tests.c,v 1.2 2024/12/26 00:10:19 tb Exp $ */
2 /*
3  * Copyright (c) 2024 Google Inc.
4  * Copyright (c) 2024 Theo Buehler <tb@openbsd.org>
5  * Copyright (c) 2024 Bob Beck <beck@obtuse.com>
6  *
7  * Permission to use, copy, modify, and/or distribute this software for any
8  * purpose with or without fee is hereby granted, provided that the above
9  * copyright notice and this permission notice appear in all copies.
10  *
11  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
14  * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
16  * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
17  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18  */
19 
20 #include <err.h>
21 #include <stdint.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 
26 #include "bytestring.h"
27 #include "mlkem.h"
28 
29 #include "mlkem_internal.h"
30 
31 #include "mlkem_tests_util.h"
32 #include "parse_test_file.h"
33 
34 enum test_type {
35 	TEST_TYPE_NORMAL,
36 	TEST_TYPE_NIST,
37 };
38 
39 struct decap_ctx {
40 	struct parse *parse_ctx;
41 
42 	void *private_key;
43 	size_t private_key_len;
44 
45 	mlkem_parse_private_key_fn parse_private_key;
46 	mlkem_decap_fn decap;
47 };
48 
49 enum decap_states {
50 	DECAP_PRIVATE_KEY,
51 	DECAP_CIPHERTEXT,
52 	DECAP_RESULT,
53 	DECAP_SHARED_SECRET,
54 	N_DECAP_STATES,
55 };
56 
57 static const struct line_spec decap_state_machine[] = {
58 	[DECAP_PRIVATE_KEY] = {
59 		.state = DECAP_PRIVATE_KEY,
60 		.type = LINE_HEX,
61 		.name = "private key",
62 		.label = "private_key",
63 	},
64 	[DECAP_CIPHERTEXT] = {
65 		.state = DECAP_CIPHERTEXT,
66 		.type = LINE_HEX,
67 		.name = "cipher text",
68 		.label = "ciphertext",
69 	},
70 	[DECAP_RESULT] = {
71 		.state = DECAP_RESULT,
72 		.type = LINE_STRING_MATCH,
73 		.name = "result",
74 		.label = "result",
75 		.match = "fail",
76 	},
77 	[DECAP_SHARED_SECRET] = {
78 		.state = DECAP_SHARED_SECRET,
79 		.type = LINE_HEX,
80 		.name = "shared secret",
81 		.label = "shared_secret",
82 	},
83 };
84 
85 static int
86 decap_init(void *ctx, void *parse_ctx)
87 {
88 	struct decap_ctx *decap = ctx;
89 
90 	decap->parse_ctx = parse_ctx;
91 
92 	return 1;
93 }
94 
95 static void
96 decap_finish(void *ctx)
97 {
98 	(void)ctx;
99 }
100 
101 static int
102 MlkemDecapFileTest(struct decap_ctx *decap)
103 {
104 	struct parse *p = decap->parse_ctx;
105 	uint8_t shared_secret_buf[MLKEM_SHARED_SECRET_BYTES];
106 	CBS ciphertext, shared_secret, private_key;
107 	int should_fail;
108 	int failed = 1;
109 
110 	parse_get_cbs(p, DECAP_CIPHERTEXT, &ciphertext);
111 	parse_get_cbs(p, DECAP_SHARED_SECRET, &shared_secret);
112 	parse_get_cbs(p, DECAP_PRIVATE_KEY, &private_key);
113 	parse_get_int(p, DECAP_RESULT, &should_fail);
114 
115 	if (!decap->parse_private_key(decap->private_key, &private_key)) {
116 		if ((failed = !should_fail))
117 			parse_info(p, "parse private key");
118 		goto err;
119 	}
120 	if (!decap->decap(shared_secret_buf,
121 	    CBS_data(&ciphertext), CBS_len(&ciphertext), decap->private_key)) {
122 		if ((failed = !should_fail))
123 			parse_info(p, "decap");
124 		goto err;
125 	}
126 
127 	failed = !parse_data_equal(p, "shared_secret", &shared_secret,
128 	    shared_secret_buf, sizeof(shared_secret_buf));
129 
130 	if (should_fail != failed) {
131 		parse_info(p, "FAIL: should_fail %d, failed %d",
132 		    should_fail, failed);
133 		failed = 1;
134 	}
135 
136  err:
137 	return failed;
138 }
139 
140 static int
141 decap_run_test_case(void *ctx)
142 {
143 	return MlkemDecapFileTest(ctx);
144 }
145 
146 static const struct test_parse decap_parse = {
147 	.states = decap_state_machine,
148 	.num_states = N_DECAP_STATES,
149 
150 	.init = decap_init,
151 	.finish = decap_finish,
152 
153 	.run_test_case = decap_run_test_case,
154 };
155 
156 enum nist_decap_instructions {
157 	NIST_DECAP_DK,
158 	N_NIST_DECAP_INSTRUCTIONS,
159 };
160 
161 static const struct line_spec nist_decap_instruction_state_machine[] = {
162 	[NIST_DECAP_DK] = {
163 		.state = NIST_DECAP_DK,
164 		.type = LINE_HEX,
165 		.name = "private key (instruction [dk])",
166 		.label = "dk",
167 	},
168 };
169 
170 enum nist_decap_states {
171 	NIST_DECAP_C,
172 	NIST_DECAP_K,
173 	N_NIST_DECAP_STATES,
174 };
175 
176 static const struct line_spec nist_decap_state_machine[] = {
177 	[NIST_DECAP_C] = {
178 		.state = NIST_DECAP_C,
179 		.type = LINE_HEX,
180 		.name = "ciphertext (c)",
181 		.label = "c",
182 	},
183 	[NIST_DECAP_K] = {
184 		.state = NIST_DECAP_K,
185 		.type = LINE_HEX,
186 		.name = "shared secret (k)",
187 		.label = "k",
188 	},
189 };
190 
191 static int
192 MlkemNistDecapFileTest(struct decap_ctx *decap)
193 {
194 	struct parse *p = decap->parse_ctx;
195 	uint8_t shared_secret[MLKEM_SHARED_SECRET_BYTES];
196 	CBS dk, c, k;
197 	int failed = 1;
198 
199 	parse_instruction_get_cbs(p, NIST_DECAP_DK, &dk);
200 	parse_get_cbs(p, NIST_DECAP_C, &c);
201 	parse_get_cbs(p, NIST_DECAP_K, &k);
202 
203 	if (!parse_length_equal(p, "private key",
204 	    decap->private_key_len, CBS_len(&dk)))
205 		goto err;
206 	if (!parse_length_equal(p, "shared secret",
207 	    MLKEM_SHARED_SECRET_BYTES, CBS_len(&k)))
208 		goto err;
209 
210 	if (!decap->parse_private_key(decap->private_key, &dk)) {
211 		parse_info(p, "parse private key");
212 		goto err;
213 	}
214 	if (!decap->decap(shared_secret, CBS_data(&c), CBS_len(&c),
215 	    decap->private_key)) {
216 		parse_info(p, "decap");
217 		goto err;
218 	}
219 
220 	failed = !parse_data_equal(p, "shared secret", &k,
221 	    shared_secret, MLKEM_SHARED_SECRET_BYTES);
222 
223  err:
224 	return failed;
225 }
226 
227 static int
228 nist_decap_run_test_case(void *ctx)
229 {
230 	return MlkemNistDecapFileTest(ctx);
231 }
232 
233 static const struct test_parse nist_decap_parse = {
234 	.instructions = nist_decap_instruction_state_machine,
235 	.num_instructions = N_NIST_DECAP_INSTRUCTIONS,
236 
237 	.states = nist_decap_state_machine,
238 	.num_states = N_NIST_DECAP_STATES,
239 
240 	.init = decap_init,
241 	.finish = decap_finish,
242 
243 	.run_test_case = nist_decap_run_test_case,
244 };
245 
246 static int
247 mlkem_decap_tests(const char *fn, size_t size, enum test_type test_type)
248 {
249 	struct MLKEM768_private_key private_key768;
250 	struct decap_ctx decap768 = {
251 		.private_key = &private_key768,
252 		.private_key_len = MLKEM768_PRIVATE_KEY_BYTES,
253 
254 		.parse_private_key = mlkem768_parse_private_key,
255 		.decap = mlkem768_decap,
256 	};
257 	struct MLKEM1024_private_key private_key1024;
258 	struct decap_ctx decap1024 = {
259 		.private_key = &private_key1024,
260 		.private_key_len = MLKEM1024_PRIVATE_KEY_BYTES,
261 
262 		.parse_private_key = mlkem1024_parse_private_key,
263 		.decap = mlkem1024_decap,
264 	};
265 
266 	if (size == 768 && test_type == TEST_TYPE_NORMAL)
267 		return parse_test_file(fn, &decap_parse, &decap768);
268 	if (size == 768 && test_type == TEST_TYPE_NIST)
269 		return parse_test_file(fn, &nist_decap_parse, &decap768);
270 	if (size == 1024 && test_type == TEST_TYPE_NORMAL)
271 		return parse_test_file(fn, &decap_parse, &decap1024);
272 	if (size == 1024 && test_type == TEST_TYPE_NIST)
273 		return parse_test_file(fn, &nist_decap_parse, &decap1024);
274 
275 	errx(1, "unknown decap test: size %zu, type %d", size, test_type);
276 }
277 
278 struct encap_ctx {
279 	struct parse *parse_ctx;
280 
281 	void *public_key;
282 	uint8_t *ciphertext;
283 	size_t ciphertext_len;
284 
285 	mlkem_parse_public_key_fn parse_public_key;
286 	mlkem_encap_external_entropy_fn encap_external_entropy;
287 };
288 
289 enum encap_states {
290 	ENCAP_ENTROPY,
291 	ENCAP_PUBLIC_KEY,
292 	ENCAP_RESULT,
293 	ENCAP_CIPHERTEXT,
294 	ENCAP_SHARED_SECRET,
295 	N_ENCAP_STATES,
296 };
297 
298 static const struct line_spec encap_state_machine[] = {
299 	[ENCAP_ENTROPY] = {
300 		.state = ENCAP_ENTROPY,
301 		.type = LINE_HEX,
302 		.name = "entropy",
303 		.label = "entropy",
304 	},
305 	[ENCAP_PUBLIC_KEY] = {
306 		.state = ENCAP_PUBLIC_KEY,
307 		.type = LINE_HEX,
308 		.name = "public key",
309 		.label = "public_key",
310 	},
311 	[ENCAP_RESULT] = {
312 		.state = ENCAP_RESULT,
313 		.type = LINE_STRING_MATCH,
314 		.name = "result",
315 		.label = "result",
316 		.match = "fail",
317 	},
318 	[ENCAP_CIPHERTEXT] = {
319 		.state = ENCAP_CIPHERTEXT,
320 		.type = LINE_HEX,
321 		.name = "ciphertext",
322 		.label = "ciphertext",
323 	},
324 	[ENCAP_SHARED_SECRET] = {
325 		.state = ENCAP_SHARED_SECRET,
326 		.type = LINE_HEX,
327 		.name = "shared secret",
328 		.label = "shared_secret",
329 	},
330 };
331 
332 static int
333 encap_init(void *ctx, void *parse_ctx)
334 {
335 	struct encap_ctx *encap = ctx;
336 
337 	encap->parse_ctx = parse_ctx;
338 
339 	return 1;
340 }
341 
342 static void
343 encap_finish(void *ctx)
344 {
345 	(void)ctx;
346 }
347 
348 static int
349 MlkemEncapFileTest(struct encap_ctx *encap)
350 {
351 	struct parse *p = encap->parse_ctx;
352 	uint8_t shared_secret_buf[MLKEM_SHARED_SECRET_BYTES];
353 	CBS entropy, public_key, ciphertext, shared_secret;
354 	int should_fail;
355 	int failed = 1;
356 
357 	parse_get_cbs(p, ENCAP_ENTROPY, &entropy);
358 	parse_get_cbs(p, ENCAP_PUBLIC_KEY, &public_key);
359 	parse_get_cbs(p, ENCAP_CIPHERTEXT, &ciphertext);
360 	parse_get_cbs(p, ENCAP_SHARED_SECRET, &shared_secret);
361 	parse_get_int(p, ENCAP_RESULT, &should_fail);
362 
363 	if (!encap->parse_public_key(encap->public_key, &public_key)) {
364 		if ((failed = !should_fail))
365 			parse_info(p, "parse public key");
366 		goto err;
367 	}
368 	encap->encap_external_entropy(encap->ciphertext, shared_secret_buf,
369 	    encap->public_key, CBS_data(&entropy));
370 
371 	failed = !parse_data_equal(p, "shared_secret", &shared_secret,
372 	    shared_secret_buf, sizeof(shared_secret_buf));
373 	failed |= !parse_data_equal(p, "ciphertext", &ciphertext,
374 	    encap->ciphertext, encap->ciphertext_len);
375 
376 	if (should_fail != failed) {
377 		parse_info(p, "FAIL: should_fail %d, failed %d",
378 		    should_fail, failed);
379 		failed = 1;
380 	}
381 
382  err:
383 	return failed;
384 }
385 
386 static int
387 encap_run_test_case(void *ctx)
388 {
389 	return MlkemEncapFileTest(ctx);
390 }
391 
392 static const struct test_parse encap_parse = {
393 	.states = encap_state_machine,
394 	.num_states = N_ENCAP_STATES,
395 
396 	.init = encap_init,
397 	.finish = encap_finish,
398 
399 	.run_test_case = encap_run_test_case,
400 };
401 
402 static int
403 mlkem_encap_tests(const char *fn, size_t size)
404 {
405 	struct MLKEM768_public_key public_key768;
406 	uint8_t ciphertext768[MLKEM768_CIPHERTEXT_BYTES];
407 	struct encap_ctx encap768 = {
408 		.public_key = &public_key768,
409 		.ciphertext = ciphertext768,
410 		.ciphertext_len = sizeof(ciphertext768),
411 
412 		.parse_public_key = mlkem768_parse_public_key,
413 		.encap_external_entropy = mlkem768_encap_external_entropy,
414 	};
415 	struct MLKEM1024_public_key public_key1024;
416 	uint8_t ciphertext1024[MLKEM1024_CIPHERTEXT_BYTES];
417 	struct encap_ctx encap1024 = {
418 		.public_key = &public_key1024,
419 		.ciphertext = ciphertext1024,
420 		.ciphertext_len = sizeof(ciphertext1024),
421 
422 		.parse_public_key = mlkem1024_parse_public_key,
423 		.encap_external_entropy = mlkem1024_encap_external_entropy,
424 	};
425 
426 	if (size == 768)
427 		return parse_test_file(fn, &encap_parse, &encap768);
428 	if (size == 1024)
429 		return parse_test_file(fn, &encap_parse, &encap1024);
430 
431 	errx(1, "unknown encap test: size %zu", size);
432 }
433 
434 struct keygen_ctx {
435 	struct parse *parse_ctx;
436 
437 	void *private_key;
438 	void *encoded_public_key;
439 	size_t encoded_public_key_len;
440 	size_t private_key_len;
441 	size_t public_key_len;
442 
443 	mlkem_generate_key_external_entropy_fn generate_key_external_entropy;
444 	mlkem_encode_private_key_fn encode_private_key;
445 };
446 
447 enum keygen_states {
448 	KEYGEN_SEED,
449 	KEYGEN_PUBLIC_KEY,
450 	KEYGEN_PRIVATE_KEY,
451 	N_KEYGEN_STATES,
452 };
453 
454 static const struct line_spec keygen_state_machine[] = {
455 	[KEYGEN_SEED] = {
456 		.state = KEYGEN_SEED,
457 		.type = LINE_HEX,
458 		.name = "seed",
459 		.label = "seed",
460 	},
461 	[KEYGEN_PUBLIC_KEY] = {
462 		.state = KEYGEN_PUBLIC_KEY,
463 		.type = LINE_HEX,
464 		.name = "public key",
465 		.label = "public_key",
466 	},
467 	[KEYGEN_PRIVATE_KEY] = {
468 		.state = KEYGEN_PRIVATE_KEY,
469 		.type = LINE_HEX,
470 		.name = "private key",
471 		.label = "private_key",
472 	},
473 };
474 
475 static int
476 keygen_init(void *ctx, void *parse_ctx)
477 {
478 	struct keygen_ctx *keygen = ctx;
479 
480 	keygen->parse_ctx = parse_ctx;
481 
482 	return 1;
483 }
484 
485 static void
486 keygen_finish(void *ctx)
487 {
488 	(void)ctx;
489 }
490 
491 static int
492 MlkemKeygenFileTest(struct keygen_ctx *keygen)
493 {
494 	struct parse *p = keygen->parse_ctx;
495 	CBS seed, public_key, private_key;
496 	uint8_t *encoded_private_key = NULL;
497 	size_t encoded_private_key_len = 0;
498 	int failed = 1;
499 
500 	parse_get_cbs(p, KEYGEN_SEED, &seed);
501 	parse_get_cbs(p, KEYGEN_PUBLIC_KEY, &public_key);
502 	parse_get_cbs(p, KEYGEN_PRIVATE_KEY, &private_key);
503 
504 	if (!parse_length_equal(p, "seed", MLKEM_SEED_BYTES, CBS_len(&seed)))
505 		goto err;
506 	if (!parse_length_equal(p, "public key",
507 	    keygen->public_key_len, CBS_len(&public_key)))
508 		goto err;
509 	if (!parse_length_equal(p, "private key",
510 	    keygen->private_key_len, CBS_len(&private_key)))
511 		goto err;
512 
513 	keygen->generate_key_external_entropy(keygen->encoded_public_key,
514 	    keygen->private_key, CBS_data(&seed));
515 	if (!keygen->encode_private_key(keygen->private_key,
516 	    &encoded_private_key, &encoded_private_key_len)) {
517 		parse_info(p, "encode private key");
518 		goto err;
519 	}
520 
521 	failed = !parse_data_equal(p, "private key", &private_key,
522 	    encoded_private_key, encoded_private_key_len);
523 	failed |= !parse_data_equal(p, "public key", &public_key,
524 	    keygen->encoded_public_key, keygen->encoded_public_key_len);
525 
526  err:
527 	freezero(encoded_private_key, encoded_private_key_len);
528 
529 	return failed;
530 }
531 
532 static int
533 keygen_run_test_case(void *ctx)
534 {
535 	return MlkemKeygenFileTest(ctx);
536 }
537 
538 static const struct test_parse keygen_parse = {
539 	.states = keygen_state_machine,
540 	.num_states = N_KEYGEN_STATES,
541 
542 	.init = keygen_init,
543 	.finish = keygen_finish,
544 
545 	.run_test_case = keygen_run_test_case,
546 };
547 
548 enum nist_keygen_states {
549 	NIST_KEYGEN_Z,
550 	NIST_KEYGEN_D,
551 	NIST_KEYGEN_EK,
552 	NIST_KEYGEN_DK,
553 	N_NIST_KEYGEN_STATES,
554 };
555 
556 static const struct line_spec nist_keygen_state_machine[] = {
557 	[NIST_KEYGEN_Z] = {
558 		.state = NIST_KEYGEN_Z,
559 		.type = LINE_HEX,
560 		.name = "seed (z)",
561 		.label = "z",
562 	},
563 	[NIST_KEYGEN_D] = {
564 		.state = NIST_KEYGEN_D,
565 		.type = LINE_HEX,
566 		.name = "seed (d)",
567 		.label = "d",
568 	},
569 	[NIST_KEYGEN_EK] = {
570 		.state = NIST_KEYGEN_EK,
571 		.type = LINE_HEX,
572 		.name = "public key (ek)",
573 		.label = "ek",
574 	},
575 	[NIST_KEYGEN_DK] = {
576 		.state = NIST_KEYGEN_DK,
577 		.type = LINE_HEX,
578 		.name = "private key (dk)",
579 		.label = "dk",
580 	},
581 };
582 
583 static int
584 MlkemNistKeygenFileTest(struct keygen_ctx *keygen)
585 {
586 	struct parse *p = keygen->parse_ctx;
587 	CBB seed_cbb;
588 	CBS z, d, ek, dk;
589 	uint8_t seed[MLKEM_SEED_BYTES];
590 	size_t seed_len;
591 	uint8_t *encoded_private_key = NULL;
592 	size_t encoded_private_key_len = 0;
593 	int failed = 1;
594 
595 	parse_get_cbs(p, NIST_KEYGEN_Z, &z);
596 	parse_get_cbs(p, NIST_KEYGEN_D, &d);
597 	parse_get_cbs(p, NIST_KEYGEN_EK, &ek);
598 	parse_get_cbs(p, NIST_KEYGEN_DK, &dk);
599 
600 	if (!CBB_init_fixed(&seed_cbb, seed, sizeof(seed)))
601 		parse_errx(p, "CBB_init_fixed");
602 	if (!CBB_add_bytes(&seed_cbb, CBS_data(&d), CBS_len(&d)))
603 		parse_errx(p, "CBB_add_bytes");
604 	if (!CBB_add_bytes(&seed_cbb, CBS_data(&z), CBS_len(&z)))
605 		parse_errx(p, "CBB_add_bytes");
606 	if (!CBB_finish(&seed_cbb, NULL, &seed_len))
607 		parse_errx(p, "CBB_finish");
608 
609 	if (!parse_length_equal(p, "bogus z or d", MLKEM_SEED_BYTES, seed_len))
610 		goto err;
611 
612 	keygen->generate_key_external_entropy(keygen->encoded_public_key,
613 	    keygen->private_key, seed);
614 	if (!keygen->encode_private_key(keygen->private_key,
615 	    &encoded_private_key, &encoded_private_key_len)) {
616 		parse_info(p, "encode private key");
617 		goto err;
618 	}
619 
620 	failed = !parse_data_equal(p, "public key", &ek,
621 	    keygen->encoded_public_key, keygen->encoded_public_key_len);
622 	failed |= !parse_data_equal(p, "private key", &dk,
623 	    encoded_private_key, encoded_private_key_len);
624 
625  err:
626 	freezero(encoded_private_key, encoded_private_key_len);
627 
628 	return failed;
629 }
630 
631 static int
632 nist_keygen_run_test_case(void *ctx)
633 {
634 	return MlkemNistKeygenFileTest(ctx);
635 }
636 
637 static const struct test_parse nist_keygen_parse = {
638 	.states = nist_keygen_state_machine,
639 	.num_states = N_NIST_KEYGEN_STATES,
640 
641 	.init = keygen_init,
642 	.finish = keygen_finish,
643 
644 	.run_test_case = nist_keygen_run_test_case,
645 };
646 
647 static int
648 mlkem_keygen_tests(const char *fn, size_t size, enum test_type test_type)
649 {
650 	struct MLKEM768_private_key private_key768;
651 	uint8_t encoded_public_key768[MLKEM768_PUBLIC_KEY_BYTES];
652 	struct keygen_ctx keygen768 = {
653 		.private_key = &private_key768,
654 		.encoded_public_key = encoded_public_key768,
655 		.encoded_public_key_len = sizeof(encoded_public_key768),
656 		.private_key_len = MLKEM768_PRIVATE_KEY_BYTES,
657 		.public_key_len = MLKEM768_PUBLIC_KEY_BYTES,
658 		.generate_key_external_entropy =
659 		    mlkem768_generate_key_external_entropy,
660 		.encode_private_key =
661 		    mlkem768_encode_private_key,
662 	};
663 	struct MLKEM1024_private_key private_key1024;
664 	uint8_t encoded_public_key1024[MLKEM1024_PUBLIC_KEY_BYTES];
665 	struct keygen_ctx keygen1024 = {
666 		.private_key = &private_key1024,
667 		.encoded_public_key = encoded_public_key1024,
668 		.encoded_public_key_len = sizeof(encoded_public_key1024),
669 		.private_key_len = MLKEM1024_PRIVATE_KEY_BYTES,
670 		.public_key_len = MLKEM1024_PUBLIC_KEY_BYTES,
671 
672 		.generate_key_external_entropy =
673 		    mlkem1024_generate_key_external_entropy,
674 		.encode_private_key =
675 		    mlkem1024_encode_private_key,
676 	};
677 
678 	if (size == 768 && test_type == TEST_TYPE_NORMAL)
679 		return parse_test_file(fn, &keygen_parse, &keygen768);
680 	if (size == 768 && test_type == TEST_TYPE_NIST)
681 		return parse_test_file(fn, &nist_keygen_parse, &keygen768);
682 	if (size == 1024 && test_type == TEST_TYPE_NORMAL)
683 		return parse_test_file(fn, &keygen_parse, &keygen1024);
684 	if (size == 1024 && test_type == TEST_TYPE_NIST)
685 		return parse_test_file(fn, &nist_keygen_parse, &keygen1024);
686 
687 	errx(1, "unknown keygen test: size %zu, type %d", size, test_type);
688 }
689 
690 static int
691 run_mlkem_test(const char *test, const char *fn)
692 {
693 	if (strcmp(test, "mlkem768_decap_tests") == 0)
694 		return mlkem_decap_tests(fn, 768, TEST_TYPE_NORMAL);
695 	if (strcmp(test, "mlkem768_nist_decap_tests") == 0)
696 		return mlkem_decap_tests(fn, 768, TEST_TYPE_NIST);
697 	if (strcmp(test, "mlkem1024_decap_tests") == 0)
698 		return mlkem_decap_tests(fn, 1024, TEST_TYPE_NORMAL);
699 	if (strcmp(test, "mlkem1024_nist_decap_tests") == 0)
700 		return mlkem_decap_tests(fn, 1024, TEST_TYPE_NIST);
701 
702 	if (strcmp(test, "mlkem768_encap_tests") == 0)
703 		return mlkem_encap_tests(fn, 768);
704 	if (strcmp(test, "mlkem1024_encap_tests") == 0)
705 		return mlkem_encap_tests(fn, 1024);
706 
707 	if (strcmp(test, "mlkem768_keygen_tests") == 0)
708 		return mlkem_keygen_tests(fn, 768, TEST_TYPE_NORMAL);
709 	if (strcmp(test, "mlkem768_nist_keygen_tests") == 0)
710 		return mlkem_keygen_tests(fn, 768, TEST_TYPE_NIST);
711 	if (strcmp(test, "mlkem1024_keygen_tests") == 0)
712 		return mlkem_keygen_tests(fn, 1024, TEST_TYPE_NORMAL);
713 	if (strcmp(test, "mlkem1024_nist_keygen_tests") == 0)
714 		return mlkem_keygen_tests(fn, 1024, TEST_TYPE_NIST);
715 
716 	errx(1, "unknown test %s (test file %s)", test, fn);
717 }
718 
719 int
720 main(int argc, const char *argv[])
721 {
722 	if (argc != 3) {
723 		fprintf(stderr, "usage: mlkem_test test testfile.txt\n");
724 		exit(1);
725 	}
726 
727 	return run_mlkem_test(argv[1], argv[2]);
728 }
729