summaryrefslogtreecommitdiff
path: root/src/regress/lib/libcrypto/mlkem/mlkem_unittest.c
diff options
context:
space:
mode:
authortb <>2024-12-26 00:04:24 +0000
committertb <>2024-12-26 00:04:24 +0000
commit31d1b04da9af806cdb66a2b49ed6490e67479eef (patch)
treef187d226245651988501e2fb8891081ff9eea9f2 /src/regress/lib/libcrypto/mlkem/mlkem_unittest.c
parentfe8b80dbfd7a71d866da84cfdab5d2ce23feac28 (diff)
downloadopenbsd-31d1b04da9af806cdb66a2b49ed6490e67479eef.tar.gz
openbsd-31d1b04da9af806cdb66a2b49ed6490e67479eef.tar.bz2
openbsd-31d1b04da9af806cdb66a2b49ed6490e67479eef.zip
Overhaul ML-KEM regress once more
Implement a file parser that drives a state machine to extract the test data from the .txt files and manages the parsed data. Comments and empty lines are ignored. The code currently assumes that instruction lines are at the start of the file (which isn't generally true) and only supports two line types for now. This is good enough for all the ML-KEM tests but should be easy enough to extend. Once all data for a test case is parsed in the expected order, a test handler is called which can retrieve the test data via a simple API and throw warnings and errors with information on the test case line number, etc. Merge the tests into three programs: one parsing the .txt files and running the corresponding test cases, a unit test and the iteration tests. Deduplicate the actual test code and let the caller pass in an object containing the API functions, private keys and arrays that need to be different between the 768 version and the 1024 version. This way we don't have two sets of half a dozen .c files differing only in 3 or 4 occurrences of 768 and 1024. All this will also make it a lot easier to hook these tests into portable.
Diffstat (limited to 'src/regress/lib/libcrypto/mlkem/mlkem_unittest.c')
-rw-r--r--src/regress/lib/libcrypto/mlkem/mlkem_unittest.c283
1 files changed, 101 insertions, 182 deletions
diff --git a/src/regress/lib/libcrypto/mlkem/mlkem_unittest.c b/src/regress/lib/libcrypto/mlkem/mlkem_unittest.c
index 18bf128bea..3f7e2886b9 100644
--- a/src/regress/lib/libcrypto/mlkem/mlkem_unittest.c
+++ b/src/regress/lib/libcrypto/mlkem/mlkem_unittest.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: mlkem_unittest.c,v 1.4 2024/12/20 00:07:12 tb Exp $ */ 1/* $OpenBSD: mlkem_unittest.c,v 1.5 2024/12/26 00:04:24 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>
@@ -27,13 +27,28 @@
27 27
28#include "mlkem_tests_util.h" 28#include "mlkem_tests_util.h"
29 29
30struct unittest_ctx {
31 void *priv;
32 void *pub;
33 void *priv2;
34 void *pub2;
35 uint8_t *encoded_public_key;
36 size_t encoded_public_key_len;
37 uint8_t *ciphertext;
38 size_t ciphertext_len;
39 mlkem_decap_fn decap;
40 mlkem_encap_fn encap;
41 mlkem_generate_key_fn generate_key;
42 mlkem_parse_private_key_fn parse_private_key;
43 mlkem_parse_public_key_fn parse_public_key;
44 mlkem_encode_private_key_fn encode_private_key;
45 mlkem_encode_public_key_fn encode_public_key;
46 mlkem_public_from_private_fn public_from_private;
47};
48
30static int 49static int
31MlKem768UnitTest(void) 50MlKemUnitTest(struct unittest_ctx *ctx)
32{ 51{
33 struct MLKEM768_private_key priv = { 0 }, priv2 = { 0 };
34 struct MLKEM768_public_key pub = { 0 }, pub2 = { 0 };
35 uint8_t encoded_public_key[MLKEM768_PUBLIC_KEY_BYTES];
36 uint8_t ciphertext[MLKEM768_CIPHERTEXT_BYTES];
37 uint8_t shared_secret1[MLKEM_SHARED_SECRET_BYTES]; 52 uint8_t shared_secret1[MLKEM_SHARED_SECRET_BYTES];
38 uint8_t shared_secret2[MLKEM_SHARED_SECRET_BYTES]; 53 uint8_t shared_secret2[MLKEM_SHARED_SECRET_BYTES];
39 uint8_t first_two_bytes[2]; 54 uint8_t first_two_bytes[2];
@@ -42,22 +57,22 @@ MlKem768UnitTest(void)
42 CBS cbs; 57 CBS cbs;
43 int failed = 0; 58 int failed = 0;
44 59
45 MLKEM768_generate_key(encoded_public_key, NULL, &priv); 60 ctx->generate_key(ctx->encoded_public_key, NULL, ctx->priv);
46 61
47 memcpy(first_two_bytes, encoded_public_key, sizeof(first_two_bytes)); 62 memcpy(first_two_bytes, ctx->encoded_public_key, sizeof(first_two_bytes));
48 memset(encoded_public_key, 0xff, sizeof(first_two_bytes)); 63 memset(ctx->encoded_public_key, 0xff, sizeof(first_two_bytes));
49 64
50 CBS_init(&cbs, encoded_public_key, sizeof(encoded_public_key)); 65 CBS_init(&cbs, ctx->encoded_public_key, ctx->encoded_public_key_len);
51 66
52 /* Parsing should fail because the first coefficient is >= kPrime. */ 67 /* Parsing should fail because the first coefficient is >= kPrime. */
53 if (MLKEM768_parse_public_key(&pub, &cbs)) { 68 if (ctx->parse_public_key(ctx->pub, &cbs)) {
54 warnx("MLKEM768_parse_public_key should have failed"); 69 warnx("parse_public_key should have failed");
55 failed |= 1; 70 failed |= 1;
56 } 71 }
57 72
58 memcpy(encoded_public_key, first_two_bytes, sizeof(first_two_bytes)); 73 memcpy(ctx->encoded_public_key, first_two_bytes, sizeof(first_two_bytes));
59 CBS_init(&cbs, encoded_public_key, sizeof(encoded_public_key)); 74 CBS_init(&cbs, ctx->encoded_public_key, ctx->encoded_public_key_len);
60 if (!MLKEM768_parse_public_key(&pub, &cbs)) { 75 if (!ctx->parse_public_key(ctx->pub, &cbs)) {
61 warnx("MLKEM768_parse_public_key"); 76 warnx("MLKEM768_parse_public_key");
62 failed |= 1; 77 failed |= 1;
63 } 78 }
@@ -67,16 +82,16 @@ MlKem768UnitTest(void)
67 failed |= 1; 82 failed |= 1;
68 } 83 }
69 84
70 if (!mlkem768_encode_public_key(&pub, &tmp_buf, &tmp_buf_len)) { 85 if (!ctx->encode_public_key(ctx->pub, &tmp_buf, &tmp_buf_len)) {
71 warnx("encode_public_key"); 86 warnx("encode_public_key");
72 failed |= 1; 87 failed |= 1;
73 } 88 }
74 if (sizeof(encoded_public_key) != tmp_buf_len) { 89 if (ctx->encoded_public_key_len != tmp_buf_len) {
75 warnx("mlkem768 encoded public key lengths differ"); 90 warnx("encoded public key lengths differ");
76 failed |= 1; 91 failed |= 1;
77 } 92 }
78 93
79 if (compare_data(encoded_public_key, tmp_buf, tmp_buf_len, 768, 94 if (compare_data(ctx->encoded_public_key, tmp_buf, tmp_buf_len,
80 "encoded public keys") != 0) { 95 "encoded public keys") != 0) {
81 warnx("compare_data"); 96 warnx("compare_data");
82 failed |= 1; 97 failed |= 1;
@@ -84,17 +99,17 @@ MlKem768UnitTest(void)
84 free(tmp_buf); 99 free(tmp_buf);
85 tmp_buf = NULL; 100 tmp_buf = NULL;
86 101
87 MLKEM768_public_from_private(&pub2, &priv); 102 ctx->public_from_private(ctx->pub2, ctx->priv);
88 if (!mlkem768_encode_public_key(&pub2, &tmp_buf, &tmp_buf_len)) { 103 if (!ctx->encode_public_key(ctx->pub2, &tmp_buf, &tmp_buf_len)) {
89 warnx("mlkem768_encode_public_key"); 104 warnx("encode_public_key");
90 failed |= 1; 105 failed |= 1;
91 } 106 }
92 if (sizeof(encoded_public_key) != tmp_buf_len) { 107 if (ctx->encoded_public_key_len != tmp_buf_len) {
93 warnx("mlkem768 encoded public key lengths differ"); 108 warnx("encoded public key lengths differ");
94 failed |= 1; 109 failed |= 1;
95 } 110 }
96 111
97 if (compare_data(encoded_public_key, tmp_buf, tmp_buf_len, 768, 112 if (compare_data(ctx->encoded_public_key, tmp_buf, tmp_buf_len,
98 "encoded public keys") != 0) { 113 "encoded public keys") != 0) {
99 warnx("compare_data"); 114 warnx("compare_data");
100 failed |= 1; 115 failed |= 1;
@@ -102,7 +117,7 @@ MlKem768UnitTest(void)
102 free(tmp_buf); 117 free(tmp_buf);
103 tmp_buf = NULL; 118 tmp_buf = NULL;
104 119
105 if (!mlkem768_encode_private_key(&priv, &encoded_private_key, 120 if (!ctx->encode_private_key(ctx->priv, &encoded_private_key,
106 &encoded_private_key_len)) { 121 &encoded_private_key_len)) {
107 warnx("mlkem768_encode_private_key"); 122 warnx("mlkem768_encode_private_key");
108 failed |= 1; 123 failed |= 1;
@@ -113,7 +128,7 @@ MlKem768UnitTest(void)
113 CBS_init(&cbs, encoded_private_key, encoded_private_key_len); 128 CBS_init(&cbs, encoded_private_key, encoded_private_key_len);
114 129
115 /* Parsing should fail because the first coefficient is >= kPrime. */ 130 /* Parsing should fail because the first coefficient is >= kPrime. */
116 if (MLKEM768_parse_private_key(&priv2, &cbs)) { 131 if (ctx->parse_private_key(ctx->priv2, &cbs)) {
117 warnx("MLKEM768_parse_private_key should have failed"); 132 warnx("MLKEM768_parse_private_key should have failed");
118 failed |= 1; 133 failed |= 1;
119 } 134 }
@@ -121,162 +136,22 @@ MlKem768UnitTest(void)
121 memcpy(encoded_private_key, first_two_bytes, sizeof(first_two_bytes)); 136 memcpy(encoded_private_key, first_two_bytes, sizeof(first_two_bytes));
122 CBS_init(&cbs, encoded_private_key, encoded_private_key_len); 137 CBS_init(&cbs, encoded_private_key, encoded_private_key_len);
123 138
124 if (!MLKEM768_parse_private_key(&priv2, &cbs)) { 139 if (!ctx->parse_private_key(ctx->priv2, &cbs)) {
125 warnx("MLKEM768_parse_private_key"); 140 warnx("MLKEM768_parse_private_key");
126 failed |= 1; 141 failed |= 1;
127 } 142 }
128 143
129 if (!mlkem768_encode_private_key(&priv2, &tmp_buf, &tmp_buf_len)) { 144 if (!ctx->encode_private_key(ctx->priv2, &tmp_buf, &tmp_buf_len)) {
130 warnx("mlkem768_encode_private_key"); 145 warnx("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
145 free(tmp_buf);
146 tmp_buf = NULL;
147
148 MLKEM768_encap(ciphertext, shared_secret1, &pub);
149 MLKEM768_decap(shared_secret2, ciphertext, MLKEM768_CIPHERTEXT_BYTES,
150 &priv);
151 if (compare_data(shared_secret1, shared_secret2, MLKEM_SHARED_SECRET_BYTES,
152 768, "shared secrets with priv") != 0) {
153 warnx("compare_data");
154 failed |= 1;
155 }
156
157 MLKEM768_decap(shared_secret2, ciphertext, MLKEM768_CIPHERTEXT_BYTES,
158 &priv2);
159 if (compare_data(shared_secret1, shared_secret2, MLKEM_SHARED_SECRET_BYTES,
160 768, "shared secrets with priv2") != 0) {
161 warnx("compare_data");
162 failed |= 1;
163 }
164
165 free(encoded_private_key);
166
167 return failed;
168}
169
170static int
171MlKem1024UnitTest(void)
172{
173 struct MLKEM1024_private_key priv = { 0 }, priv2 = { 0 };
174 struct MLKEM1024_public_key pub = { 0 }, pub2 = { 0 };
175 uint8_t encoded_public_key[MLKEM1024_PUBLIC_KEY_BYTES];
176 uint8_t ciphertext[MLKEM1024_CIPHERTEXT_BYTES];
177 uint8_t shared_secret1[MLKEM_SHARED_SECRET_BYTES];
178 uint8_t shared_secret2[MLKEM_SHARED_SECRET_BYTES];
179 uint8_t first_two_bytes[2];
180 uint8_t *encoded_private_key = NULL, *tmp_buf = NULL;
181 size_t encoded_private_key_len, tmp_buf_len;
182 CBS cbs;
183 int failed = 0;
184
185 MLKEM1024_generate_key(encoded_public_key, NULL, &priv);
186
187 memcpy(first_two_bytes, encoded_public_key, sizeof(first_two_bytes));
188 memset(encoded_public_key, 0xff, sizeof(first_two_bytes));
189
190 CBS_init(&cbs, encoded_public_key, sizeof(encoded_public_key));
191
192 /* Parsing should fail because the first coefficient is >= kPrime. */
193 if (MLKEM1024_parse_public_key(&pub, &cbs)) {
194 warnx("MLKEM1024_parse_public_key should have failed");
195 failed |= 1;
196 }
197
198 memcpy(encoded_public_key, first_two_bytes, sizeof(first_two_bytes));
199 CBS_init(&cbs, encoded_public_key, sizeof(encoded_public_key));
200 if (!MLKEM1024_parse_public_key(&pub, &cbs)) {
201 warnx("MLKEM1024_parse_public_key");
202 failed |= 1;
203 }
204
205 if (CBS_len(&cbs) != 0u) {
206 warnx("CBS_len must be 0");
207 failed |= 1;
208 }
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 }
224 free(tmp_buf);
225 tmp_buf = NULL;
226
227 MLKEM1024_public_from_private(&pub2, &priv);
228 if (!mlkem1024_encode_public_key(&pub2, &tmp_buf, &tmp_buf_len)) {
229 warnx("mlkem1024_encode_public_key");
230 failed |= 1;
231 }
232 if (sizeof(encoded_public_key) != tmp_buf_len) {
233 warnx("mlkem1024 encoded public key lengths differ");
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 }
242 free(tmp_buf);
243 tmp_buf = NULL;
244
245 if (!mlkem1024_encode_private_key(&priv, &encoded_private_key,
246 &encoded_private_key_len)) {
247 warnx("mlkem1024_encode_private_key");
248 failed |= 1;
249 }
250
251 memcpy(first_two_bytes, encoded_private_key, sizeof(first_two_bytes));
252 memset(encoded_private_key, 0xff, sizeof(first_two_bytes));
253 CBS_init(&cbs, encoded_private_key, encoded_private_key_len);
254
255 /* Parsing should fail because the first coefficient is >= kPrime. */
256 if (MLKEM1024_parse_private_key(&priv2, &cbs)) {
257 warnx("MLKEM1024_parse_private_key should have failed");
258 failed |= 1;
259 }
260
261 memcpy(encoded_private_key, first_two_bytes, sizeof(first_two_bytes));
262 CBS_init(&cbs, encoded_private_key, encoded_private_key_len);
263
264 if (!MLKEM1024_parse_private_key(&priv2, &cbs)) {
265 warnx("MLKEM1024_parse_private_key");
266 failed |= 1;
267 }
268
269 if (!mlkem1024_encode_private_key(&priv2, &tmp_buf, &tmp_buf_len)) {
270 warnx("mlkem1024_encode_private_key");
271 failed |= 1; 146 failed |= 1;
272 } 147 }
273 148
274 if (encoded_private_key_len != tmp_buf_len) { 149 if (encoded_private_key_len != tmp_buf_len) {
275 warnx("mlkem1024 encode private key lengths differ"); 150 warnx("encode private key lengths differ");
276 failed |= 1; 151 failed |= 1;
277 } 152 }
278 153
279 if (compare_data(encoded_private_key, tmp_buf, tmp_buf_len, 1024, 154 if (compare_data(encoded_private_key, tmp_buf, tmp_buf_len,
280 "encoded private key") != 0) { 155 "encoded private key") != 0) {
281 warnx("compare_data"); 156 warnx("compare_data");
282 failed |= 1; 157 failed |= 1;
@@ -285,19 +160,19 @@ MlKem1024UnitTest(void)
285 free(tmp_buf); 160 free(tmp_buf);
286 tmp_buf = NULL; 161 tmp_buf = NULL;
287 162
288 MLKEM1024_encap(ciphertext, shared_secret1, &pub); 163 ctx->encap(ctx->ciphertext, shared_secret1, ctx->pub);
289 MLKEM1024_decap(shared_secret2, ciphertext, MLKEM1024_CIPHERTEXT_BYTES, 164 ctx->decap(shared_secret2, ctx->ciphertext, ctx->ciphertext_len,
290 &priv); 165 ctx->priv);
291 if (compare_data(shared_secret1, shared_secret2, MLKEM_SHARED_SECRET_BYTES, 166 if (compare_data(shared_secret1, shared_secret2, MLKEM_SHARED_SECRET_BYTES,
292 1024, "shared secrets with priv") != 0) { 167 "shared secrets with priv") != 0) {
293 warnx("compare_data"); 168 warnx("compare_data");
294 failed |= 1; 169 failed |= 1;
295 } 170 }
296 171
297 MLKEM1024_decap(shared_secret2, ciphertext, MLKEM1024_CIPHERTEXT_BYTES, 172 ctx->decap(shared_secret2, ctx->ciphertext, ctx->ciphertext_len,
298 &priv2); 173 ctx->priv2);
299 if (compare_data(shared_secret1, shared_secret2, MLKEM_SHARED_SECRET_BYTES, 174 if (compare_data(shared_secret1, shared_secret2, MLKEM_SHARED_SECRET_BYTES,
300 1024, "shared secrets with priv2") != 0) { 175 "shared secrets with priv2") != 0) {
301 warnx("compare_data"); 176 warnx("compare_data");
302 failed |= 1; 177 failed |= 1;
303 } 178 }
@@ -308,12 +183,56 @@ MlKem1024UnitTest(void)
308} 183}
309 184
310int 185int
311main(int argc, char **argv) 186main(void)
312{ 187{
188 struct MLKEM768_private_key mlkem768_priv, mlkem768_priv2;
189 struct MLKEM768_public_key mlkem768_pub, mlkem768_pub2;
190 uint8_t mlkem768_encoded_public_key[MLKEM768_PUBLIC_KEY_BYTES];
191 uint8_t mlkem768_ciphertext[MLKEM768_CIPHERTEXT_BYTES];
192 struct unittest_ctx mlkem768_test = {
193 .priv = &mlkem768_priv,
194 .pub = &mlkem768_pub,
195 .priv2 = &mlkem768_priv2,
196 .pub2 = &mlkem768_pub2,
197 .encoded_public_key = mlkem768_encoded_public_key,
198 .encoded_public_key_len = sizeof(mlkem768_encoded_public_key),
199 .ciphertext = mlkem768_ciphertext,
200 .ciphertext_len = sizeof(mlkem768_ciphertext),
201 .decap = mlkem768_decap,
202 .encap = mlkem768_encap,
203 .generate_key = mlkem768_generate_key,
204 .parse_private_key = mlkem768_parse_private_key,
205 .parse_public_key = mlkem768_parse_public_key,
206 .encode_private_key = mlkem768_encode_private_key,
207 .encode_public_key = mlkem768_encode_public_key,
208 .public_from_private = mlkem768_public_from_private,
209 };
210 struct MLKEM1024_private_key mlkem1024_priv, mlkem1024_priv2;
211 struct MLKEM1024_public_key mlkem1024_pub, mlkem1024_pub2;
212 uint8_t mlkem1024_encoded_public_key[MLKEM1024_PUBLIC_KEY_BYTES];
213 uint8_t mlkem1024_ciphertext[MLKEM1024_CIPHERTEXT_BYTES];
214 struct unittest_ctx mlkem1024_test = {
215 .priv = &mlkem1024_priv,
216 .pub = &mlkem1024_pub,
217 .priv2 = &mlkem1024_priv2,
218 .pub2 = &mlkem1024_pub2,
219 .encoded_public_key = mlkem1024_encoded_public_key,
220 .encoded_public_key_len = sizeof(mlkem1024_encoded_public_key),
221 .ciphertext = mlkem1024_ciphertext,
222 .ciphertext_len = sizeof(mlkem1024_ciphertext),
223 .decap = mlkem1024_decap,
224 .encap = mlkem1024_encap,
225 .generate_key = mlkem1024_generate_key,
226 .parse_private_key = mlkem1024_parse_private_key,
227 .parse_public_key = mlkem1024_parse_public_key,
228 .encode_private_key = mlkem1024_encode_private_key,
229 .encode_public_key = mlkem1024_encode_public_key,
230 .public_from_private = mlkem1024_public_from_private,
231 };
313 int failed = 0; 232 int failed = 0;
314 233
315 failed |= MlKem768UnitTest(); 234 failed |= MlKemUnitTest(&mlkem768_test);
316 failed |= MlKem1024UnitTest(); 235 failed |= MlKemUnitTest(&mlkem1024_test);
317 236
318 return failed; 237 return failed;
319} 238}