summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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}