diff options
author | tb <> | 2024-12-26 00:04:24 +0000 |
---|---|---|
committer | tb <> | 2024-12-26 00:04:24 +0000 |
commit | 31d1b04da9af806cdb66a2b49ed6490e67479eef (patch) | |
tree | f187d226245651988501e2fb8891081ff9eea9f2 /src | |
parent | fe8b80dbfd7a71d866da84cfdab5d2ce23feac28 (diff) | |
download | openbsd-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')
20 files changed, 2110 insertions, 2571 deletions
diff --git a/src/regress/lib/libcrypto/mlkem/Makefile b/src/regress/lib/libcrypto/mlkem/Makefile index cb24605bd7..9c0c24f432 100644 --- a/src/regress/lib/libcrypto/mlkem/Makefile +++ b/src/regress/lib/libcrypto/mlkem/Makefile | |||
@@ -1,28 +1,31 @@ | |||
1 | # $OpenBSD: Makefile,v 1.7 2024/12/20 01:53:46 tb Exp $ | 1 | # $OpenBSD: Makefile,v 1.8 2024/12/26 00:04:24 tb Exp $ |
2 | 2 | ||
3 | PROGS += mlkem768_decap_tests | 3 | REGRESS_SLOW_TARGETS += run-regress-mlkem_iteration_tests |
4 | PROGS += mlkem768_encap_tests | 4 | |
5 | PROGS += mlkem768_iteration_test | 5 | PROGS += mlkem_tests |
6 | PROGS += mlkem768_keygen_tests | ||
7 | PROGS += mlkem768_nist_decap_tests | ||
8 | PROGS += mlkem768_nist_keygen_tests | ||
9 | PROGS += mlkem1024_decap_tests | ||
10 | PROGS += mlkem1024_encap_tests | ||
11 | PROGS += mlkem1024_iteration_test | ||
12 | PROGS += mlkem1024_keygen_tests | ||
13 | PROGS += mlkem1024_nist_decap_tests | ||
14 | PROGS += mlkem1024_nist_keygen_tests | ||
15 | PROGS += mlkem_unittest | 6 | PROGS += mlkem_unittest |
7 | PROGS += mlkem_iteration_tests | ||
16 | 8 | ||
17 | # Link test programs with mlkem_tests_util.c and use custom target | 9 | FILE_TEST += mlkem768_decap_tests |
18 | .for p in ${PROGS} | 10 | FILE_TEST += mlkem768_encap_tests |
19 | SRCS_$p += $p.c mlkem_tests_util.c | 11 | FILE_TEST += mlkem768_keygen_tests |
12 | FILE_TEST += mlkem768_nist_decap_tests | ||
13 | FILE_TEST += mlkem768_nist_keygen_tests | ||
14 | FILE_TEST += mlkem1024_decap_tests | ||
15 | FILE_TEST += mlkem1024_encap_tests | ||
16 | FILE_TEST += mlkem1024_keygen_tests | ||
17 | FILE_TEST += mlkem1024_nist_decap_tests | ||
18 | FILE_TEST += mlkem1024_nist_keygen_tests | ||
20 | 19 | ||
21 | REGRESS_TARGETS += run-$p | 20 | run-regress-mlkem_tests: mlkem_tests |
22 | run-$p: $p | 21 | .for f in ${FILE_TEST} |
23 | ./$p ${.CURDIR}/$p.txt | 22 | ./mlkem_tests $f ${.CURDIR}/$f.txt |
24 | .endfor | 23 | .endfor |
25 | 24 | ||
25 | SRCS_mlkem_tests = mlkem_tests.c mlkem_tests_util.c parse_test_file.c | ||
26 | SRCS_mlkem_iteration_tests = mlkem_iteration_tests.c mlkem_tests_util.c | ||
27 | SRCS_mlkem_unittest = mlkem_unittest.c mlkem_tests_util.c | ||
28 | |||
26 | LDADD = ${CRYPTO_INT} | 29 | LDADD = ${CRYPTO_INT} |
27 | DPADD = ${LIBCRYPTO} | 30 | DPADD = ${LIBCRYPTO} |
28 | 31 | ||
diff --git a/src/regress/lib/libcrypto/mlkem/mlkem1024_decap_tests.c b/src/regress/lib/libcrypto/mlkem/mlkem1024_decap_tests.c deleted file mode 100644 index 7d76a625b0..0000000000 --- a/src/regress/lib/libcrypto/mlkem/mlkem1024_decap_tests.c +++ /dev/null | |||
@@ -1,195 +0,0 @@ | |||
1 | /* $OpenBSD: mlkem1024_decap_tests.c,v 1.4 2024/12/20 00:32:15 tb Exp $ */ | ||
2 | /* | ||
3 | * Copyright (c) 2024 Google Inc. | ||
4 | * Copyright (c) 2024 Bob Beck <beck@obtuse.com> | ||
5 | * Copyright (c) 2024 Theo Buehler <tb@openbsd.org> | ||
6 | * | ||
7 | * Permission to use, copy, modify, and/or distribute this software for any | ||
8 | * purpose with or without fee is hereby granted, provided that the above | ||
9 | * copyright notice and this permission notice appear in all copies. | ||
10 | * | ||
11 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||
12 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | ||
13 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY | ||
14 | * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||
15 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION | ||
16 | * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN | ||
17 | * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
18 | */ | ||
19 | |||
20 | #include <assert.h> | ||
21 | #include <err.h> | ||
22 | #include <stdint.h> | ||
23 | #include <stdio.h> | ||
24 | #include <stdlib.h> | ||
25 | |||
26 | #include "bytestring.h" | ||
27 | #include "mlkem.h" | ||
28 | |||
29 | #include "mlkem_tests_util.h" | ||
30 | |||
31 | static int | ||
32 | MlkemDecapFileTest(CBB *ciphertext_cbb, CBB *shared_secret_cbb, | ||
33 | CBB *private_key_cbb, int should_fail, size_t line) | ||
34 | { | ||
35 | struct MLKEM1024_private_key priv; | ||
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; | ||
41 | |||
42 | if (!CBB_finish(ciphertext_cbb, &ciphertext, &ciphertext_len)) | ||
43 | goto err; | ||
44 | if (!CBB_finish(shared_secret_cbb, &shared_secret, &shared_secret_len)) | ||
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; | ||
61 | } | ||
62 | |||
63 | failed = compare_data(shared_secret, shared_secret_buf, | ||
64 | MLKEM_SHARED_SECRET_BYTES, line, "shared_secret"); | ||
65 | |||
66 | if (should_fail != failed) { | ||
67 | warnx("FAIL: #%zu: should_fail %d, failed %d", | ||
68 | line, should_fail, failed); | ||
69 | failed = 1; | ||
70 | } | ||
71 | |||
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; | ||
81 | } | ||
82 | |||
83 | #define S_START 0 | ||
84 | #define S_COMMENT 1 | ||
85 | #define S_PRIVATE_KEY 2 | ||
86 | #define S_CIPHERTEXT 3 | ||
87 | #define S_RESULT 4 | ||
88 | #define S_SHARED_SECRET 5 | ||
89 | |||
90 | #define S2S(x) case x: return #x | ||
91 | |||
92 | static const char * | ||
93 | state2str(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 | } | ||
106 | |||
107 | int | ||
108 | main(int argc, char **argv) | ||
109 | { | ||
110 | CBB ciphertext = { 0 }, shared_secret = { 0 }, private_key = { 0 }; | ||
111 | int should_fail = 0; | ||
112 | const char *test; | ||
113 | size_t line = 0; | ||
114 | char *buf = NULL; | ||
115 | size_t buflen = 0; | ||
116 | ssize_t len; | ||
117 | FILE *fp; | ||
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, "can't open test file"); | ||
128 | |||
129 | state = S_COMMENT; | ||
130 | line = 0; | ||
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 | |||
144 | switch (state) { | ||
145 | case S_START: | ||
146 | state = S_COMMENT; | ||
147 | break; | ||
148 | case S_COMMENT: | ||
149 | if (!CBS_get_u8(&cbs, &u8)) | ||
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); | ||
154 | state = S_PRIVATE_KEY; | ||
155 | break; | ||
156 | case S_PRIVATE_KEY: | ||
157 | if (!get_string_cbs(&cbs, "private_key: ", line, msg)) | ||
158 | errx(1, "#%zu %s: get_string_cbs", line, msg); | ||
159 | hex_decode_cbs(&cbs, &private_key, line, msg); | ||
160 | state = S_CIPHERTEXT; | ||
161 | break; | ||
162 | case S_CIPHERTEXT: | ||
163 | if (!get_string_cbs(&cbs, "ciphertext: ", line, msg)) | ||
164 | errx(1, "#%zu %s: get_string_cbs", line, msg); | ||
165 | hex_decode_cbs(&cbs, &ciphertext, line, msg); | ||
166 | state = S_RESULT; | ||
167 | break; | ||
168 | case S_RESULT: | ||
169 | if (!get_string_cbs(&cbs, "result: ", line, msg)) | ||
170 | errx(1, "#%zu %s: get_string_cbs", line, msg); | ||
171 | should_fail = get_string_cbs(&cbs, "fail", line, msg); | ||
172 | state = S_SHARED_SECRET; | ||
173 | break; | ||
174 | case S_SHARED_SECRET: | ||
175 | if (!get_string_cbs(&cbs, "shared_secret: ", line, msg)) | ||
176 | errx(1, "#%zu %s: get_string_cbs", line, msg); | ||
177 | hex_decode_cbs(&cbs, &shared_secret, line, msg); | ||
178 | |||
179 | failed |= MlkemDecapFileTest(&ciphertext, &shared_secret, | ||
180 | &private_key, should_fail, line); | ||
181 | |||
182 | state = S_START; | ||
183 | break; | ||
184 | } | ||
185 | if (CBS_len(&cbs) > 0) | ||
186 | errx(1, "#%zu %s: CBS_len", line, msg); | ||
187 | } | ||
188 | free(buf); | ||
189 | |||
190 | if (ferror(fp)) | ||
191 | err(1, NULL); | ||
192 | fclose(fp); | ||
193 | |||
194 | return failed; | ||
195 | } | ||
diff --git a/src/regress/lib/libcrypto/mlkem/mlkem1024_encap_tests.c b/src/regress/lib/libcrypto/mlkem/mlkem1024_encap_tests.c deleted file mode 100644 index 6459566ff0..0000000000 --- a/src/regress/lib/libcrypto/mlkem/mlkem1024_encap_tests.c +++ /dev/null | |||
@@ -1,210 +0,0 @@ | |||
1 | /* $OpenBSD: mlkem1024_encap_tests.c,v 1.4 2024/12/20 00:32:15 tb Exp $ */ | ||
2 | /* | ||
3 | * Copyright (c) 2024 Google Inc. | ||
4 | * Copyright (c) 2024 Bob Beck <beck@obtuse.com> | ||
5 | * Copyright (c) 2024 Theo Buehler <tb@openbsd.org> | ||
6 | * | ||
7 | * Permission to use, copy, modify, and/or distribute this software for any | ||
8 | * purpose with or without fee is hereby granted, provided that the above | ||
9 | * copyright notice and this permission notice appear in all copies. | ||
10 | * | ||
11 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||
12 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | ||
13 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY | ||
14 | * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||
15 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION | ||
16 | * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN | ||
17 | * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
18 | */ | ||
19 | |||
20 | #include <assert.h> | ||
21 | #include <err.h> | ||
22 | #include <stdint.h> | ||
23 | #include <stdio.h> | ||
24 | #include <stdlib.h> | ||
25 | |||
26 | #include "bytestring.h" | ||
27 | #include "mlkem.h" | ||
28 | |||
29 | #include "mlkem_internal.h" | ||
30 | #include "mlkem_tests_util.h" | ||
31 | |||
32 | static int | ||
33 | MlkemEncapFileTest(CBB *entropy_cbb, CBB *pubkey_cbb, CBB *ciphertext_cbb, | ||
34 | CBB *shared_secret_cbb, int should_fail, size_t line) | ||
35 | { | ||
36 | struct MLKEM1024_public_key pub; | ||
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; | ||
45 | |||
46 | if (!CBB_finish(entropy_cbb, &entropy, &entropy_len)) | ||
47 | goto err; | ||
48 | if (!CBB_finish(pubkey_cbb, &public_key, &public_key_len)) | ||
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; | ||
61 | } | ||
62 | MLKEM1024_encap_external_entropy(ciphertext_buf, shared_secret_buf, | ||
63 | &pub, entropy); | ||
64 | |||
65 | failed = compare_data(shared_secret, shared_secret_buf, | ||
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; | ||
87 | } | ||
88 | |||
89 | #define S_START 0 | ||
90 | #define S_COMMENT 1 | ||
91 | #define S_ENTROPY 2 | ||
92 | #define S_PUBLIC_KEY 3 | ||
93 | #define S_RESULT 4 | ||
94 | #define S_CIPHERTEXT 5 | ||
95 | #define S_SHARED_SECRET 6 | ||
96 | |||
97 | #define S2S(x) case x: return #x | ||
98 | |||
99 | static const char * | ||
100 | state2str(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 | } | ||
114 | |||
115 | int | ||
116 | main(int argc, char **argv) | ||
117 | { | ||
118 | CBB entropy = { 0 }, public_key = { 0 }, ciphertext = { 0 }, shared_secret = { 0 }; | ||
119 | int should_fail = 0; | ||
120 | const char *test; | ||
121 | size_t line; | ||
122 | char *buf = NULL; | ||
123 | size_t buflen = 0; | ||
124 | ssize_t len; | ||
125 | FILE *fp; | ||
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, "can't open test file"); | ||
137 | |||
138 | state = S_COMMENT; | ||
139 | line = 0; | ||
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 | |||
153 | switch (state) { | ||
154 | case S_START: | ||
155 | state = S_COMMENT; | ||
156 | break; | ||
157 | case S_COMMENT: | ||
158 | if (!CBS_get_u8(&cbs, &u8)) | ||
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); | ||
163 | state = S_ENTROPY; | ||
164 | break; | ||
165 | case S_ENTROPY: | ||
166 | if (!get_string_cbs(&cbs, "entropy: ", line, msg)) | ||
167 | errx(1, "#%zu %s: get_string_cbs", line, msg); | ||
168 | hex_decode_cbs(&cbs, &entropy, line, msg); | ||
169 | state = S_PUBLIC_KEY; | ||
170 | break; | ||
171 | case S_PUBLIC_KEY: | ||
172 | if (!get_string_cbs(&cbs, "public_key = ", line, msg)) | ||
173 | errx(1, "#%zu %s: get_string_cbs", line, msg); | ||
174 | hex_decode_cbs(&cbs, &public_key, line, msg); | ||
175 | state = S_RESULT; | ||
176 | break; | ||
177 | case S_RESULT: | ||
178 | if (!get_string_cbs(&cbs, "result: ", line, msg)) | ||
179 | errx(1, "#%zu %s: get_string_cbs", line, msg); | ||
180 | should_fail = get_string_cbs(&cbs, "fail", line, msg); | ||
181 | state = S_CIPHERTEXT; | ||
182 | break; | ||
183 | case S_CIPHERTEXT: | ||
184 | if (!get_string_cbs(&cbs, "ciphertext: ", line, msg)) | ||
185 | errx(1, "#%zu %s: get_string_cbs", line, msg); | ||
186 | hex_decode_cbs(&cbs, &ciphertext, line, msg); | ||
187 | state = S_SHARED_SECRET; | ||
188 | break; | ||
189 | case S_SHARED_SECRET: | ||
190 | if (!get_string_cbs(&cbs, "shared_secret: ", line, msg)) | ||
191 | errx(1, "#%zu %s: get_string_cbs", line, msg); | ||
192 | hex_decode_cbs(&cbs, &shared_secret, line, msg); | ||
193 | |||
194 | failed |= MlkemEncapFileTest(&entropy, &public_key, | ||
195 | &ciphertext, &shared_secret, should_fail, line); | ||
196 | |||
197 | state = S_START; | ||
198 | break; | ||
199 | } | ||
200 | if (CBS_len(&cbs) > 0) | ||
201 | errx(1, "#%zu %s: CBS_len", line, msg); | ||
202 | } | ||
203 | free(buf); | ||
204 | |||
205 | if (ferror(fp)) | ||
206 | err(1, NULL); | ||
207 | fclose(fp); | ||
208 | |||
209 | return failed; | ||
210 | } | ||
diff --git a/src/regress/lib/libcrypto/mlkem/mlkem1024_iteration_test.c b/src/regress/lib/libcrypto/mlkem/mlkem1024_iteration_test.c deleted file mode 100644 index e6a4d4f906..0000000000 --- a/src/regress/lib/libcrypto/mlkem/mlkem1024_iteration_test.c +++ /dev/null | |||
@@ -1,149 +0,0 @@ | |||
1 | /* $OpenBSD: mlkem1024_iteration_test.c,v 1.3 2024/12/20 00:07:12 tb Exp $ */ | ||
2 | /* | ||
3 | * Copyright (c) 2024 Google Inc. | ||
4 | * Copyright (c) 2024 Bob Beck <beck@obtuse.com> | ||
5 | * Copyright (c) 2024 Theo Buehler <tb@openbsd.org> | ||
6 | * | ||
7 | * Permission to use, copy, modify, and/or distribute this software for any | ||
8 | * purpose with or without fee is hereby granted, provided that the above | ||
9 | * copyright notice and this permission notice appear in all copies. | ||
10 | * | ||
11 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||
12 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | ||
13 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY | ||
14 | * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||
15 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION | ||
16 | * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN | ||
17 | * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
18 | */ | ||
19 | |||
20 | #include <err.h> | ||
21 | #include <stdint.h> | ||
22 | #include <stdio.h> | ||
23 | #include <stdlib.h> | ||
24 | |||
25 | #include "mlkem.h" | ||
26 | |||
27 | #include "mlkem_internal.h" | ||
28 | #include "mlkem_tests_util.h" | ||
29 | #include "sha3_internal.h" | ||
30 | |||
31 | /* | ||
32 | * The structure of this test is taken from | ||
33 | * https://github.com/C2SP/CCTV/blob/main/ML-KEM/README.md?ref=words.filippo.io#accumulated-pq-crystals-vectors | ||
34 | * but the final value has been updated to reflect the change from Kyber to | ||
35 | * ML-KEM. | ||
36 | * | ||
37 | * The deterministic RNG is a single SHAKE-128 instance with an empty input. | ||
38 | * (The RNG stream starts with 7f9c2ba4e88f827d616045507605853e.) | ||
39 | */ | ||
40 | |||
41 | static int | ||
42 | MlkemIterativeTest(void) | ||
43 | { | ||
44 | /* https://github.com/C2SP/CCTV/tree/main/ML-KEM */ | ||
45 | /* | ||
46 | * The deterministic RNG is a single SHAKE-128 instance with an empty input. | ||
47 | * (The RNG stream starts with 7f9c2ba4e88f827d616045507605853e.) | ||
48 | */ | ||
49 | const uint8_t kExpectedSeedStart[16] = { | ||
50 | 0x7f, 0x9c, 0x2b, 0xa4, 0xe8, 0x8f, 0x82, 0x7d, 0x61, 0x60, 0x45, | ||
51 | 0x50, 0x76, 0x05, 0x85, 0x3e | ||
52 | }; | ||
53 | |||
54 | /* | ||
55 | * Filippo says: | ||
56 | * ML-KEM-1024: 47ac888fe61544efc0518f46094b4f8a600965fc89822acb06dc7169d24f3543 | ||
57 | * but Boring believes this: | ||
58 | */ | ||
59 | const uint8_t kExpectedAdam[32] = { | ||
60 | 0xe3, 0xbf, 0x82, 0xb0, 0x13, 0x30, 0x7b, 0x2e, 0x9d, 0x47, 0xdd, | ||
61 | 0xe7, 0x91, 0xff, 0x6d, 0xfc, 0x82, 0xe6, 0x94, 0xe6, 0x38, 0x24, | ||
62 | 0x04, 0xab, 0xdb, 0x94, 0x8b, 0x90, 0x8b, 0x75, 0xba, 0xd5 | ||
63 | }; | ||
64 | uint8_t encoded_public_key[MLKEM1024_PUBLIC_KEY_BYTES]; | ||
65 | uint8_t invalid_ciphertext[MLKEM1024_CIPHERTEXT_BYTES]; | ||
66 | uint8_t shared_secret[MLKEM_SHARED_SECRET_BYTES]; | ||
67 | uint8_t ciphertext[MLKEM1024_CIPHERTEXT_BYTES]; | ||
68 | uint8_t encap_entropy[MLKEM_ENCAP_ENTROPY]; | ||
69 | uint8_t seed[MLKEM_SEED_BYTES] = {0}; | ||
70 | struct MLKEM1024_private_key priv; | ||
71 | struct MLKEM1024_public_key pub; | ||
72 | sha3_ctx drng, results; | ||
73 | uint8_t out[32]; | ||
74 | int i; | ||
75 | |||
76 | shake128_init(&drng); | ||
77 | shake128_init(&results); | ||
78 | |||
79 | shake_xof(&drng); | ||
80 | for (i = 0; i < 10000; i++) { | ||
81 | uint8_t *encoded_private_key = NULL; | ||
82 | size_t encoded_private_key_len; | ||
83 | |||
84 | /* | ||
85 | * This should draw both d and z from DRNG concatenating in | ||
86 | * seed. | ||
87 | */ | ||
88 | shake_out(&drng, seed, sizeof(seed)); | ||
89 | if (i == 0) { | ||
90 | if (compare_data(seed, kExpectedSeedStart, | ||
91 | sizeof(kExpectedSeedStart), 0, "seed start") != 0) | ||
92 | errx(1, "compare_data"); | ||
93 | } | ||
94 | |||
95 | /* generate ek as encoded_public_key */ | ||
96 | MLKEM1024_generate_key_external_entropy(encoded_public_key, | ||
97 | &priv, seed); | ||
98 | MLKEM1024_public_from_private(&pub, &priv); | ||
99 | |||
100 | /* hash in ek */ | ||
101 | shake_update(&results, encoded_public_key, | ||
102 | sizeof(encoded_public_key)); | ||
103 | |||
104 | /* marshal priv to dk as encoded_private_key */ | ||
105 | if (!mlkem1024_encode_private_key(&priv, &encoded_private_key, | ||
106 | &encoded_private_key_len)) | ||
107 | errx(1, "mlkem1024_encode_private_key"); | ||
108 | |||
109 | /* hash in dk */ | ||
110 | shake_update(&results, encoded_private_key, | ||
111 | encoded_private_key_len); | ||
112 | |||
113 | free(encoded_private_key); | ||
114 | |||
115 | /* draw m as encap entropy from DRNG */ | ||
116 | shake_out(&drng, encap_entropy, sizeof(encap_entropy)); | ||
117 | |||
118 | /* generate ct as ciphertext, k as shared_secret */ | ||
119 | MLKEM1024_encap_external_entropy(ciphertext, shared_secret, | ||
120 | &pub, encap_entropy); | ||
121 | |||
122 | /* hash in ct */ | ||
123 | shake_update(&results, ciphertext, sizeof(ciphertext)); | ||
124 | /* hash in k */ | ||
125 | shake_update(&results, shared_secret, sizeof(shared_secret)); | ||
126 | |||
127 | /* draw ct as invalid_ciphertxt from DRNG */ | ||
128 | shake_out(&drng, invalid_ciphertext, | ||
129 | sizeof(invalid_ciphertext)); | ||
130 | |||
131 | /* generte k as shared secret from invalid ciphertext */ | ||
132 | if (!MLKEM1024_decap(shared_secret, invalid_ciphertext, | ||
133 | sizeof(invalid_ciphertext), &priv)) | ||
134 | errx(1, "decap failed"); | ||
135 | |||
136 | /* hash in k */ | ||
137 | shake_update(&results, shared_secret, sizeof(shared_secret)); | ||
138 | } | ||
139 | shake_xof(&results); | ||
140 | shake_out(&results, out, sizeof(out)); | ||
141 | |||
142 | return compare_data(kExpectedAdam, out, sizeof(out), i, "final result hash"); | ||
143 | } | ||
144 | |||
145 | int | ||
146 | main(int argc, char **argv) | ||
147 | { | ||
148 | return MlkemIterativeTest(); | ||
149 | } | ||
diff --git a/src/regress/lib/libcrypto/mlkem/mlkem1024_keygen_tests.c b/src/regress/lib/libcrypto/mlkem/mlkem1024_keygen_tests.c deleted file mode 100644 index 442475bc82..0000000000 --- a/src/regress/lib/libcrypto/mlkem/mlkem1024_keygen_tests.c +++ /dev/null | |||
@@ -1,190 +0,0 @@ | |||
1 | /* $OpenBSD: mlkem1024_keygen_tests.c,v 1.6 2024/12/20 00:32:15 tb Exp $ */ | ||
2 | /* | ||
3 | * Copyright (c) 2024 Google Inc. | ||
4 | * Copyright (c) 2024 Bob Beck <beck@obtuse.com> | ||
5 | * Copyright (c) 2024 Theo Buehler <tb@openbsd.org> | ||
6 | * | ||
7 | * Permission to use, copy, modify, and/or distribute this software for any | ||
8 | * purpose with or without fee is hereby granted, provided that the above | ||
9 | * copyright notice and this permission notice appear in all copies. | ||
10 | * | ||
11 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||
12 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | ||
13 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY | ||
14 | * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||
15 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION | ||
16 | * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN | ||
17 | * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
18 | */ | ||
19 | |||
20 | #include <assert.h> | ||
21 | #include <err.h> | ||
22 | #include <stdint.h> | ||
23 | #include <stdio.h> | ||
24 | #include <stdlib.h> | ||
25 | |||
26 | #include "bytestring.h" | ||
27 | #include "mlkem.h" | ||
28 | |||
29 | #include "mlkem_internal.h" | ||
30 | #include "mlkem_tests_util.h" | ||
31 | |||
32 | static int | ||
33 | MlkemKeygenFileTest(CBB *seed_cbb, CBB *public_key_cbb, CBB *private_key_cbb, | ||
34 | size_t line) | ||
35 | { | ||
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; | ||
39 | uint8_t *encoded_private_key = NULL; | ||
40 | uint8_t encoded_public_key[MLKEM1024_PUBLIC_KEY_BYTES]; | ||
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; | ||
58 | |||
59 | MLKEM1024_generate_key_external_entropy(encoded_public_key, &priv, | ||
60 | seed); | ||
61 | if (!mlkem1024_encode_private_key(&priv, &encoded_private_key, &len)) { | ||
62 | warnx("#%zu: encoded_private_key", line); | ||
63 | goto err; | ||
64 | } | ||
65 | |||
66 | if (!compare_length(MLKEM1024_PRIVATE_KEY_BYTES, len, line, | ||
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); | ||
82 | free(encoded_private_key); | ||
83 | |||
84 | return failed; | ||
85 | } | ||
86 | |||
87 | #define S_START 0 | ||
88 | #define S_COMMENT 1 | ||
89 | #define S_SEED 2 | ||
90 | #define S_PUBLIC_KEY 3 | ||
91 | #define S_PRIVATE_KEY 4 | ||
92 | |||
93 | #define S2S(x) case x: return #x | ||
94 | |||
95 | static const char * | ||
96 | state2str(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 | } | ||
108 | |||
109 | int | ||
110 | main(int argc, char **argv) | ||
111 | { | ||
112 | CBB seed = { 0 }, public_key = { 0 }, private_key = { 0 }; | ||
113 | const char *test; | ||
114 | size_t line = 0; | ||
115 | char *buf = NULL; | ||
116 | size_t buflen = 0; | ||
117 | ssize_t len; | ||
118 | FILE *fp; | ||
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, "can'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'); | ||
144 | |||
145 | switch (state) { | ||
146 | case S_START: | ||
147 | state = S_COMMENT; | ||
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); | ||
155 | state = S_SEED; | ||
156 | break; | ||
157 | case S_SEED: | ||
158 | if (!get_string_cbs(&cbs, "seed: ", line, msg)) | ||
159 | errx(1, "#%zu %s: get_string_cbs", line, msg); | ||
160 | hex_decode_cbs(&cbs, &seed, line, msg); | ||
161 | state = S_PUBLIC_KEY; | ||
162 | break; | ||
163 | case S_PUBLIC_KEY: | ||
164 | if (!get_string_cbs(&cbs, "public_key: ", line, msg)) | ||
165 | errx(1, "#%zu %s: get_string_cbs", line, msg); | ||
166 | hex_decode_cbs(&cbs, &public_key, line, msg); | ||
167 | state = S_PRIVATE_KEY; | ||
168 | break; | ||
169 | case S_PRIVATE_KEY: | ||
170 | if (!get_string_cbs(&cbs, "private_key: ", line, msg)) | ||
171 | errx(1, "#%zu %s: get_string_cbs", line, msg); | ||
172 | hex_decode_cbs(&cbs, &private_key, line, msg); | ||
173 | |||
174 | failed |= MlkemKeygenFileTest(&seed, &public_key, | ||
175 | &private_key, line); | ||
176 | |||
177 | state = S_START; | ||
178 | break; | ||
179 | } | ||
180 | if (CBS_len(&cbs) > 0) | ||
181 | errx(1, "#%zu %s: CBS_len", line, msg); | ||
182 | } | ||
183 | free(buf); | ||
184 | |||
185 | if (ferror(fp)) | ||
186 | err(1, NULL); | ||
187 | fclose(fp); | ||
188 | |||
189 | return failed; | ||
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 deleted file mode 100644 index 929a4b21b1..0000000000 --- a/src/regress/lib/libcrypto/mlkem/mlkem1024_nist_decap_tests.c +++ /dev/null | |||
@@ -1,193 +0,0 @@ | |||
1 | /* $OpenBSD: mlkem1024_nist_decap_tests.c,v 1.4 2024/12/20 00:32:15 tb Exp $ */ | ||
2 | /* | ||
3 | * Copyright (c) 2024 Google Inc. | ||
4 | * Copyright (c) 2024 Bob Beck <beck@obtuse.com> | ||
5 | * Copyright (c) 2024 Theo Buehler <tb@openbsd.org> | ||
6 | * | ||
7 | * Permission to use, copy, modify, and/or distribute this software for any | ||
8 | * purpose with or without fee is hereby granted, provided that the above | ||
9 | * copyright notice and this permission notice appear in all copies. | ||
10 | * | ||
11 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||
12 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | ||
13 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY | ||
14 | * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||
15 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION | ||
16 | * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN | ||
17 | * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
18 | */ | ||
19 | |||
20 | #include <assert.h> | ||
21 | #include <err.h> | ||
22 | #include <stdint.h> | ||
23 | #include <stdio.h> | ||
24 | #include <stdlib.h> | ||
25 | |||
26 | #include "bytestring.h" | ||
27 | #include "mlkem.h" | ||
28 | |||
29 | #include "mlkem_internal.h" | ||
30 | #include "mlkem_tests_util.h" | ||
31 | |||
32 | static int | ||
33 | MlkemNistDecapFileTest(CBB *c_cbb, CBB *k_cbb, CBS *dk, size_t line) | ||
34 | { | ||
35 | uint8_t *c = NULL, *k = NULL; | ||
36 | size_t c_len = 0, k_len = 0; | ||
37 | uint8_t shared_secret[MLKEM_SHARED_SECRET_BYTES]; | ||
38 | struct MLKEM1024_private_key priv; | ||
39 | int failed = 1; | ||
40 | |||
41 | if (!CBB_finish(c_cbb, &c, &c_len)) | ||
42 | goto err; | ||
43 | if (!CBB_finish(k_cbb, &k, &k_len)) | ||
44 | goto err; | ||
45 | |||
46 | if (!compare_length(MLKEM1024_PRIVATE_KEY_BYTES, CBS_len(dk), line, | ||
47 | "private key len bogus")) | ||
48 | goto err; | ||
49 | if (!compare_length(MLKEM_SHARED_SECRET_BYTES, k_len, line, | ||
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; | ||
71 | } | ||
72 | |||
73 | #define S_START 0 | ||
74 | #define S_C 1 | ||
75 | #define S_K 2 | ||
76 | #define S_EMPTY 3 | ||
77 | |||
78 | #define S2S(x) case x: return #x | ||
79 | |||
80 | static const char * | ||
81 | state2str(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 | } | ||
92 | |||
93 | int | ||
94 | main(int argc, char **argv) | ||
95 | { | ||
96 | CBB dk_cbb = { 0 }, c = { 0 }, k = { 0 }; | ||
97 | CBS instr; | ||
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; | ||
106 | FILE *fp; | ||
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, "can'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'); | ||
156 | |||
157 | switch (state) { | ||
158 | case S_START: | ||
159 | state = S_C; | ||
160 | break; | ||
161 | case S_C: | ||
162 | if (!get_string_cbs(&cbs, "c: ", line, msg)) | ||
163 | errx(1, "#%zu %s: get_string_cbs", line, msg); | ||
164 | hex_decode_cbs(&cbs, &c, line, msg); | ||
165 | state = S_K; | ||
166 | break; | ||
167 | case S_K: | ||
168 | if (!get_string_cbs(&cbs, "k: ", line, msg)) | ||
169 | errx(1, "#%zu %s: get_string_cbs", line, msg); | ||
170 | hex_decode_cbs(&cbs, &k, line, msg); | ||
171 | state = S_EMPTY; | ||
172 | break; | ||
173 | case S_EMPTY: | ||
174 | CBS_init(&dk_cbs, dk, dk_len); | ||
175 | |||
176 | failed |= MlkemNistDecapFileTest(&c, &k, &dk_cbs, line); | ||
177 | |||
178 | state = S_C; | ||
179 | break; | ||
180 | } | ||
181 | if (CBS_len(&cbs) > 0) | ||
182 | errx(1, "#%zu %s: CBS_len", line, msg); | ||
183 | } | ||
184 | free(buf); | ||
185 | |||
186 | if (ferror(fp)) | ||
187 | err(1, NULL); | ||
188 | fclose(fp); | ||
189 | |||
190 | freezero(dk, dk_len); | ||
191 | |||
192 | return failed; | ||
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 deleted file mode 100644 index 5ef5ff0caa..0000000000 --- a/src/regress/lib/libcrypto/mlkem/mlkem1024_nist_keygen_tests.c +++ /dev/null | |||
@@ -1,197 +0,0 @@ | |||
1 | /* $OpenBSD: mlkem1024_nist_keygen_tests.c,v 1.5 2024/12/20 00:32:15 tb Exp $ */ | ||
2 | /* | ||
3 | * Copyright (c) 2024 Google Inc. | ||
4 | * Copyright (c) 2024 Bob Beck <beck@obtuse.com> | ||
5 | * Copyright (c) 2024 Theo Buehler <tb@openbsd.org> | ||
6 | * | ||
7 | * Permission to use, copy, modify, and/or distribute this software for any | ||
8 | * purpose with or without fee is hereby granted, provided that the above | ||
9 | * copyright notice and this permission notice appear in all copies. | ||
10 | * | ||
11 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||
12 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | ||
13 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY | ||
14 | * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||
15 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION | ||
16 | * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN | ||
17 | * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
18 | */ | ||
19 | |||
20 | #include <assert.h> | ||
21 | #include <err.h> | ||
22 | #include <stdint.h> | ||
23 | #include <stdio.h> | ||
24 | #include <stdlib.h> | ||
25 | |||
26 | #include "bytestring.h" | ||
27 | #include "mlkem.h" | ||
28 | |||
29 | #include "mlkem_internal.h" | ||
30 | #include "mlkem_tests_util.h" | ||
31 | |||
32 | static int | ||
33 | MlkemNistKeygenFileTest(CBB *z_cbb, CBB *d_cbb, CBB *ek_cbb, CBB *dk_cbb, | ||
34 | size_t line) | ||
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; | ||
39 | uint8_t seed[MLKEM_SEED_BYTES]; | ||
40 | struct MLKEM1024_private_key priv; | ||
41 | uint8_t *encoded_private_key = NULL; | ||
42 | uint8_t encoded_public_key[MLKEM1024_PUBLIC_KEY_BYTES]; | ||
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; | ||
67 | |||
68 | MLKEM1024_generate_key_external_entropy(encoded_public_key, &priv, seed); | ||
69 | |||
70 | if (!mlkem1024_encode_private_key(&priv, &encoded_private_key, &len)) { | ||
71 | warnx("#%zu mlkem1024_encode_private_key", line); | ||
72 | goto err; | ||
73 | } | ||
74 | |||
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); | ||
94 | free(encoded_private_key); | ||
95 | |||
96 | return failed; | ||
97 | } | ||
98 | |||
99 | #define S_START 0 | ||
100 | #define S_Z 1 | ||
101 | #define S_D 2 | ||
102 | #define S_EK 3 | ||
103 | #define S_DK 4 | ||
104 | |||
105 | #define S2S(x) case x: return #x | ||
106 | |||
107 | static const char * | ||
108 | state2str(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 | } | ||
120 | |||
121 | int | ||
122 | main(int argc, char **argv) | ||
123 | { | ||
124 | CBB z = { 0 }, d = { 0 }, ek = { 0 }, dk = { 0 }; | ||
125 | const char *test; | ||
126 | size_t line = 0; | ||
127 | char *buf = NULL; | ||
128 | size_t buflen = 0; | ||
129 | ssize_t len; | ||
130 | FILE *fp; | ||
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, "can't open test file"); | ||
141 | |||
142 | state = S_Z; | ||
143 | line = 0; | ||
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 | |||
157 | switch (state) { | ||
158 | case S_START: | ||
159 | state = S_Z; | ||
160 | break; | ||
161 | case S_Z: | ||
162 | if (!get_string_cbs(&cbs, "z: ", line, msg)) | ||
163 | errx(1, "#%zu %s: get_string_cbs", line, msg); | ||
164 | hex_decode_cbs(&cbs, &z, line, msg); | ||
165 | state = S_D; | ||
166 | break; | ||
167 | case S_D: | ||
168 | if (!get_string_cbs(&cbs, "d: ", line, msg)) | ||
169 | errx(1, "#%zu %s: get_string_cbs", line, msg); | ||
170 | hex_decode_cbs(&cbs, &d, line, msg); | ||
171 | state = S_EK; | ||
172 | break; | ||
173 | case S_EK: | ||
174 | if (!get_string_cbs(&cbs, "ek: ", line, msg)) | ||
175 | errx(1, "#%zu %s: get_string_cbs", line, msg); | ||
176 | hex_decode_cbs(&cbs, &ek, line, msg); | ||
177 | state = S_DK; | ||
178 | break; | ||
179 | case S_DK: | ||
180 | if (!get_string_cbs(&cbs, "dk: ", line, msg)) | ||
181 | errx(1, "#%zu %s: get_string_cbs", line, msg); | ||
182 | hex_decode_cbs(&cbs, &dk, line, msg); | ||
183 | |||
184 | failed |= MlkemNistKeygenFileTest(&z, &d, &ek, &dk, line); | ||
185 | |||
186 | state = S_START; | ||
187 | break; | ||
188 | } | ||
189 | } | ||
190 | free(buf); | ||
191 | |||
192 | if (ferror(fp)) | ||
193 | err(1, NULL); | ||
194 | fclose(fp); | ||
195 | |||
196 | return failed; | ||
197 | } | ||
diff --git a/src/regress/lib/libcrypto/mlkem/mlkem768_decap_tests.c b/src/regress/lib/libcrypto/mlkem/mlkem768_decap_tests.c deleted file mode 100644 index a58f005644..0000000000 --- a/src/regress/lib/libcrypto/mlkem/mlkem768_decap_tests.c +++ /dev/null | |||
@@ -1,195 +0,0 @@ | |||
1 | /* $OpenBSD: mlkem768_decap_tests.c,v 1.4 2024/12/20 00:32:15 tb Exp $ */ | ||
2 | /* | ||
3 | * Copyright (c) 2024 Google Inc. | ||
4 | * Copyright (c) 2024 Bob Beck <beck@obtuse.com> | ||
5 | * Copyright (c) 2024 Theo Buehler <tb@openbsd.org> | ||
6 | * | ||
7 | * Permission to use, copy, modify, and/or distribute this software for any | ||
8 | * purpose with or without fee is hereby granted, provided that the above | ||
9 | * copyright notice and this permission notice appear in all copies. | ||
10 | * | ||
11 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||
12 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | ||
13 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY | ||
14 | * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||
15 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION | ||
16 | * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN | ||
17 | * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
18 | */ | ||
19 | |||
20 | #include <assert.h> | ||
21 | #include <err.h> | ||
22 | #include <stdint.h> | ||
23 | #include <stdio.h> | ||
24 | #include <stdlib.h> | ||
25 | |||
26 | #include "bytestring.h" | ||
27 | #include "mlkem.h" | ||
28 | |||
29 | #include "mlkem_tests_util.h" | ||
30 | |||
31 | static int | ||
32 | MlkemDecapFileTest(CBB *ciphertext_cbb, CBB *shared_secret_cbb, | ||
33 | CBB *private_key_cbb, int should_fail, size_t line) | ||
34 | { | ||
35 | struct MLKEM768_private_key priv; | ||
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; | ||
41 | |||
42 | if (!CBB_finish(ciphertext_cbb, &ciphertext, &ciphertext_len)) | ||
43 | goto err; | ||
44 | if (!CBB_finish(shared_secret_cbb, &shared_secret, &shared_secret_len)) | ||
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; | ||
61 | } | ||
62 | |||
63 | failed = compare_data(shared_secret, shared_secret_buf, | ||
64 | MLKEM_SHARED_SECRET_BYTES, line, "shared_secret"); | ||
65 | |||
66 | if (should_fail != failed) { | ||
67 | warnx("FAIL: #%zu: should_fail %d, failed %d", | ||
68 | line, should_fail, failed); | ||
69 | failed = 1; | ||
70 | } | ||
71 | |||
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; | ||
81 | } | ||
82 | |||
83 | #define S_START 0 | ||
84 | #define S_COMMENT 1 | ||
85 | #define S_PRIVATE_KEY 2 | ||
86 | #define S_CIPHERTEXT 3 | ||
87 | #define S_RESULT 4 | ||
88 | #define S_SHARED_SECRET 5 | ||
89 | |||
90 | #define S2S(x) case x: return #x | ||
91 | |||
92 | static const char * | ||
93 | state2str(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 | } | ||
106 | |||
107 | int | ||
108 | main(int argc, char **argv) | ||
109 | { | ||
110 | CBB ciphertext = { 0 }, shared_secret = { 0 }, private_key = { 0 }; | ||
111 | int should_fail = 0; | ||
112 | const char *test; | ||
113 | size_t line = 0; | ||
114 | char *buf = NULL; | ||
115 | size_t buflen = 0; | ||
116 | ssize_t len; | ||
117 | FILE *fp; | ||
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, "can't open test file"); | ||
128 | |||
129 | state = S_COMMENT; | ||
130 | line = 0; | ||
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 | |||
144 | switch (state) { | ||
145 | case S_START: | ||
146 | state = S_COMMENT; | ||
147 | break; | ||
148 | case S_COMMENT: | ||
149 | if (!CBS_get_u8(&cbs, &u8)) | ||
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); | ||
154 | state = S_PRIVATE_KEY; | ||
155 | break; | ||
156 | case S_PRIVATE_KEY: | ||
157 | if (!get_string_cbs(&cbs, "private_key: ", line, msg)) | ||
158 | errx(1, "#%zu %s: get_string_cbs", line, msg); | ||
159 | hex_decode_cbs(&cbs, &private_key, line, msg); | ||
160 | state = S_CIPHERTEXT; | ||
161 | break; | ||
162 | case S_CIPHERTEXT: | ||
163 | if (!get_string_cbs(&cbs, "ciphertext: ", line, msg)) | ||
164 | errx(1, "#%zu %s: get_string_cbs", line, msg); | ||
165 | hex_decode_cbs(&cbs, &ciphertext, line, msg); | ||
166 | state = S_RESULT; | ||
167 | break; | ||
168 | case S_RESULT: | ||
169 | if (!get_string_cbs(&cbs, "result: ", line, msg)) | ||
170 | errx(1, "#%zu %s: get_string_cbs", line, msg); | ||
171 | should_fail = get_string_cbs(&cbs, "fail", line, msg); | ||
172 | state = S_SHARED_SECRET; | ||
173 | break; | ||
174 | case S_SHARED_SECRET: | ||
175 | if (!get_string_cbs(&cbs, "shared_secret: ", line, msg)) | ||
176 | errx(1, "#%zu %s: get_string_cbs", line, msg); | ||
177 | hex_decode_cbs(&cbs, &shared_secret, line, msg); | ||
178 | |||
179 | failed |= MlkemDecapFileTest(&ciphertext, &shared_secret, | ||
180 | &private_key, should_fail, line); | ||
181 | |||
182 | state = S_START; | ||
183 | break; | ||
184 | } | ||
185 | if (CBS_len(&cbs) > 0) | ||
186 | errx(1, "#%zu %s: CBS_len", line, msg); | ||
187 | } | ||
188 | free(buf); | ||
189 | |||
190 | if (ferror(fp)) | ||
191 | err(1, NULL); | ||
192 | fclose(fp); | ||
193 | |||
194 | return failed; | ||
195 | } | ||
diff --git a/src/regress/lib/libcrypto/mlkem/mlkem768_encap_tests.c b/src/regress/lib/libcrypto/mlkem/mlkem768_encap_tests.c deleted file mode 100644 index e2123f8de5..0000000000 --- a/src/regress/lib/libcrypto/mlkem/mlkem768_encap_tests.c +++ /dev/null | |||
@@ -1,210 +0,0 @@ | |||
1 | /* $OpenBSD: mlkem768_encap_tests.c,v 1.4 2024/12/20 00:32:15 tb Exp $ */ | ||
2 | /* | ||
3 | * Copyright (c) 2024 Google Inc. | ||
4 | * Copyright (c) 2024 Bob Beck <beck@obtuse.com> | ||
5 | * Copyright (c) 2024 Theo Buehler <tb@openbsd.org> | ||
6 | * | ||
7 | * Permission to use, copy, modify, and/or distribute this software for any | ||
8 | * purpose with or without fee is hereby granted, provided that the above | ||
9 | * copyright notice and this permission notice appear in all copies. | ||
10 | * | ||
11 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||
12 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | ||
13 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY | ||
14 | * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||
15 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION | ||
16 | * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN | ||
17 | * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
18 | */ | ||
19 | |||
20 | #include <assert.h> | ||
21 | #include <err.h> | ||
22 | #include <stdint.h> | ||
23 | #include <stdio.h> | ||
24 | #include <stdlib.h> | ||
25 | |||
26 | #include "bytestring.h" | ||
27 | #include "mlkem.h" | ||
28 | |||
29 | #include "mlkem_internal.h" | ||
30 | #include "mlkem_tests_util.h" | ||
31 | |||
32 | static int | ||
33 | MlkemEncapFileTest(CBB *entropy_cbb, CBB *pubkey_cbb, CBB *ciphertext_cbb, | ||
34 | CBB *shared_secret_cbb, int should_fail, size_t line) | ||
35 | { | ||
36 | struct MLKEM768_public_key pub; | ||
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; | ||
45 | |||
46 | if (!CBB_finish(entropy_cbb, &entropy, &entropy_len)) | ||
47 | goto err; | ||
48 | if (!CBB_finish(pubkey_cbb, &public_key, &public_key_len)) | ||
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; | ||
61 | } | ||
62 | MLKEM768_encap_external_entropy(ciphertext_buf, shared_secret_buf, | ||
63 | &pub, entropy); | ||
64 | |||
65 | failed = compare_data(shared_secret, shared_secret_buf, | ||
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; | ||
87 | } | ||
88 | |||
89 | #define S_START 0 | ||
90 | #define S_COMMENT 1 | ||
91 | #define S_ENTROPY 2 | ||
92 | #define S_PUBLIC_KEY 3 | ||
93 | #define S_RESULT 4 | ||
94 | #define S_CIPHERTEXT 5 | ||
95 | #define S_SHARED_SECRET 6 | ||
96 | |||
97 | #define S2S(x) case x: return #x | ||
98 | |||
99 | static const char * | ||
100 | state2str(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 | } | ||
114 | |||
115 | int | ||
116 | main(int argc, char **argv) | ||
117 | { | ||
118 | CBB entropy = { 0 }, public_key = { 0 }, ciphertext = { 0 }, shared_secret = { 0 }; | ||
119 | int should_fail = 0; | ||
120 | const char *test; | ||
121 | size_t line; | ||
122 | char *buf = NULL; | ||
123 | size_t buflen = 0; | ||
124 | ssize_t len; | ||
125 | FILE *fp; | ||
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, "can't open test file"); | ||
137 | |||
138 | state = S_COMMENT; | ||
139 | line = 0; | ||
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 | |||
153 | switch (state) { | ||
154 | case S_START: | ||
155 | state = S_COMMENT; | ||
156 | break; | ||
157 | case S_COMMENT: | ||
158 | if (!CBS_get_u8(&cbs, &u8)) | ||
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); | ||
163 | state = S_ENTROPY; | ||
164 | break; | ||
165 | case S_ENTROPY: | ||
166 | if (!get_string_cbs(&cbs, "entropy: ", line, msg)) | ||
167 | errx(1, "#%zu %s: get_string_cbs", line, msg); | ||
168 | hex_decode_cbs(&cbs, &entropy, line, msg); | ||
169 | state = S_PUBLIC_KEY; | ||
170 | break; | ||
171 | case S_PUBLIC_KEY: | ||
172 | if (!get_string_cbs(&cbs, "public_key = ", line, msg)) | ||
173 | errx(1, "#%zu %s: get_string_cbs", line, msg); | ||
174 | hex_decode_cbs(&cbs, &public_key, line, msg); | ||
175 | state = S_RESULT; | ||
176 | break; | ||
177 | case S_RESULT: | ||
178 | if (!get_string_cbs(&cbs, "result: ", line, msg)) | ||
179 | errx(1, "#%zu %s: get_string_cbs", line, msg); | ||
180 | should_fail = get_string_cbs(&cbs, "fail", line, msg); | ||
181 | state = S_CIPHERTEXT; | ||
182 | break; | ||
183 | case S_CIPHERTEXT: | ||
184 | if (!get_string_cbs(&cbs, "ciphertext: ", line, msg)) | ||
185 | errx(1, "#%zu %s: get_string_cbs", line, msg); | ||
186 | hex_decode_cbs(&cbs, &ciphertext, line, msg); | ||
187 | state = S_SHARED_SECRET; | ||
188 | break; | ||
189 | case S_SHARED_SECRET: | ||
190 | if (!get_string_cbs(&cbs, "shared_secret: ", line, msg)) | ||
191 | errx(1, "#%zu %s: get_string_cbs", line, msg); | ||
192 | hex_decode_cbs(&cbs, &shared_secret, line, msg); | ||
193 | |||
194 | failed |= MlkemEncapFileTest(&entropy, &public_key, | ||
195 | &ciphertext, &shared_secret, should_fail, line); | ||
196 | |||
197 | state = S_START; | ||
198 | break; | ||
199 | } | ||
200 | if (CBS_len(&cbs) > 0) | ||
201 | errx(1, "#%zu %s: CBS_len", line, msg); | ||
202 | } | ||
203 | free(buf); | ||
204 | |||
205 | if (ferror(fp)) | ||
206 | err(1, NULL); | ||
207 | fclose(fp); | ||
208 | |||
209 | return failed; | ||
210 | } | ||
diff --git a/src/regress/lib/libcrypto/mlkem/mlkem768_iteration_test.c b/src/regress/lib/libcrypto/mlkem/mlkem768_iteration_test.c deleted file mode 100644 index 9517980d7b..0000000000 --- a/src/regress/lib/libcrypto/mlkem/mlkem768_iteration_test.c +++ /dev/null | |||
@@ -1,149 +0,0 @@ | |||
1 | /* $OpenBSD: mlkem768_iteration_test.c,v 1.3 2024/12/20 00:07:12 tb Exp $ */ | ||
2 | /* | ||
3 | * Copyright (c) 2024 Google Inc. | ||
4 | * Copyright (c) 2024 Bob Beck <beck@obtuse.com> | ||
5 | * Copyright (c) 2024 Theo Buehler <tb@openbsd.org> | ||
6 | * | ||
7 | * Permission to use, copy, modify, and/or distribute this software for any | ||
8 | * purpose with or without fee is hereby granted, provided that the above | ||
9 | * copyright notice and this permission notice appear in all copies. | ||
10 | * | ||
11 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||
12 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | ||
13 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY | ||
14 | * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||
15 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION | ||
16 | * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN | ||
17 | * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
18 | */ | ||
19 | |||
20 | #include <err.h> | ||
21 | #include <stdint.h> | ||
22 | #include <stdio.h> | ||
23 | #include <stdlib.h> | ||
24 | |||
25 | #include "mlkem.h" | ||
26 | |||
27 | #include "mlkem_internal.h" | ||
28 | #include "mlkem_tests_util.h" | ||
29 | #include "sha3_internal.h" | ||
30 | |||
31 | /* | ||
32 | * The structure of this test is taken from | ||
33 | * https://github.com/C2SP/CCTV/blob/main/ML-KEM/README.md?ref=words.filippo.io#accumulated-pq-crystals-vectors | ||
34 | * but the final value has been updated to reflect the change from Kyber to | ||
35 | * ML-KEM. | ||
36 | * | ||
37 | * The deterministic RNG is a single SHAKE-128 instance with an empty input. | ||
38 | * (The RNG stream starts with 7f9c2ba4e88f827d616045507605853e.) | ||
39 | */ | ||
40 | |||
41 | static int | ||
42 | MlkemIterativeTest(void) | ||
43 | { | ||
44 | /* https://github.com/C2SP/CCTV/tree/main/ML-KEM */ | ||
45 | /* | ||
46 | * The deterministic RNG is a single SHAKE-128 instance with an empty input. | ||
47 | * (The RNG stream starts with 7f9c2ba4e88f827d616045507605853e.) | ||
48 | */ | ||
49 | const uint8_t kExpectedSeedStart[16] = { | ||
50 | 0x7f, 0x9c, 0x2b, 0xa4, 0xe8, 0x8f, 0x82, 0x7d, 0x61, 0x60, 0x45, | ||
51 | 0x50, 0x76, 0x05, 0x85, 0x3e | ||
52 | }; | ||
53 | |||
54 | /* | ||
55 | * Filippo says: | ||
56 | * ML-KEM-768: f7db260e1137a742e05fe0db9525012812b004d29040a5b606aad3d134b548d3 | ||
57 | * but Boring believes this: | ||
58 | */ | ||
59 | const uint8_t kExpectedAdam[32] = { | ||
60 | 0xf9, 0x59, 0xd1, 0x8d, 0x3d, 0x11, 0x80, 0x12, 0x14, 0x33, 0xbf, | ||
61 | 0x0e, 0x05, 0xf1, 0x1e, 0x79, 0x08, 0xcf, 0x9d, 0x03, 0xed, 0xc1, | ||
62 | 0x50, 0xb2, 0xb0, 0x7c, 0xb9, 0x0b, 0xef, 0x5b, 0xc1, 0xc1 | ||
63 | }; | ||
64 | uint8_t encoded_public_key[MLKEM768_PUBLIC_KEY_BYTES]; | ||
65 | uint8_t invalid_ciphertext[MLKEM768_CIPHERTEXT_BYTES]; | ||
66 | uint8_t shared_secret[MLKEM_SHARED_SECRET_BYTES]; | ||
67 | uint8_t ciphertext[MLKEM768_CIPHERTEXT_BYTES]; | ||
68 | uint8_t encap_entropy[MLKEM_ENCAP_ENTROPY]; | ||
69 | uint8_t seed[MLKEM_SEED_BYTES] = {0}; | ||
70 | struct MLKEM768_private_key priv; | ||
71 | struct MLKEM768_public_key pub; | ||
72 | sha3_ctx drng, results; | ||
73 | uint8_t out[32]; | ||
74 | int i; | ||
75 | |||
76 | shake128_init(&drng); | ||
77 | shake128_init(&results); | ||
78 | |||
79 | shake_xof(&drng); | ||
80 | for (i = 0; i < 10000; i++) { | ||
81 | uint8_t *encoded_private_key = NULL; | ||
82 | size_t encoded_private_key_len; | ||
83 | |||
84 | /* | ||
85 | * This should draw both d and z from DRNG concatenating in | ||
86 | * seed. | ||
87 | */ | ||
88 | shake_out(&drng, seed, sizeof(seed)); | ||
89 | if (i == 0) { | ||
90 | if (compare_data(seed, kExpectedSeedStart, | ||
91 | sizeof(kExpectedSeedStart), 0, "seed start") != 0) | ||
92 | errx(1, "compare_data"); | ||
93 | } | ||
94 | |||
95 | /* generate ek as encoded_public_key */ | ||
96 | MLKEM768_generate_key_external_entropy(encoded_public_key, | ||
97 | &priv, seed); | ||
98 | MLKEM768_public_from_private(&pub, &priv); | ||
99 | |||
100 | /* hash in ek */ | ||
101 | shake_update(&results, encoded_public_key, | ||
102 | sizeof(encoded_public_key)); | ||
103 | |||
104 | /* marshal priv to dk as encoded_private_key */ | ||
105 | if (!mlkem768_encode_private_key(&priv, &encoded_private_key, | ||
106 | &encoded_private_key_len)) | ||
107 | errx(1, "mlkem768_encode_private_key"); | ||
108 | |||
109 | /* hash in dk */ | ||
110 | shake_update(&results, encoded_private_key, | ||
111 | encoded_private_key_len); | ||
112 | |||
113 | free(encoded_private_key); | ||
114 | |||
115 | /* draw m as encap entropy from DRNG */ | ||
116 | shake_out(&drng, encap_entropy, sizeof(encap_entropy)); | ||
117 | |||
118 | /* generate ct as ciphertext, k as shared_secret */ | ||
119 | MLKEM768_encap_external_entropy(ciphertext, shared_secret, | ||
120 | &pub, encap_entropy); | ||
121 | |||
122 | /* hash in ct */ | ||
123 | shake_update(&results, ciphertext, sizeof(ciphertext)); | ||
124 | /* hash in k */ | ||
125 | shake_update(&results, shared_secret, sizeof(shared_secret)); | ||
126 | |||
127 | /* draw ct as invalid_ciphertxt from DRNG */ | ||
128 | shake_out(&drng, invalid_ciphertext, | ||
129 | sizeof(invalid_ciphertext)); | ||
130 | |||
131 | /* generte k as shared secret from invalid ciphertext */ | ||
132 | if (!MLKEM768_decap(shared_secret, invalid_ciphertext, | ||
133 | sizeof(invalid_ciphertext), &priv)) | ||
134 | errx(1, "decap failed"); | ||
135 | |||
136 | /* hash in k */ | ||
137 | shake_update(&results, shared_secret, sizeof(shared_secret)); | ||
138 | } | ||
139 | shake_xof(&results); | ||
140 | shake_out(&results, out, sizeof(out)); | ||
141 | |||
142 | return compare_data(kExpectedAdam, out, sizeof(out), i, "final result hash"); | ||
143 | } | ||
144 | |||
145 | int | ||
146 | main(int argc, char **argv) | ||
147 | { | ||
148 | return MlkemIterativeTest(); | ||
149 | } | ||
diff --git a/src/regress/lib/libcrypto/mlkem/mlkem768_keygen_tests.c b/src/regress/lib/libcrypto/mlkem/mlkem768_keygen_tests.c deleted file mode 100644 index 3f8012c4e6..0000000000 --- a/src/regress/lib/libcrypto/mlkem/mlkem768_keygen_tests.c +++ /dev/null | |||
@@ -1,190 +0,0 @@ | |||
1 | /* $OpenBSD: mlkem768_keygen_tests.c,v 1.6 2024/12/20 00:32:15 tb Exp $ */ | ||
2 | /* | ||
3 | * Copyright (c) 2024 Google Inc. | ||
4 | * Copyright (c) 2024 Bob Beck <beck@obtuse.com> | ||
5 | * Copyright (c) 2024 Theo Buehler <tb@openbsd.org> | ||
6 | * | ||
7 | * Permission to use, copy, modify, and/or distribute this software for any | ||
8 | * purpose with or without fee is hereby granted, provided that the above | ||
9 | * copyright notice and this permission notice appear in all copies. | ||
10 | * | ||
11 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||
12 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | ||
13 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY | ||
14 | * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||
15 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION | ||
16 | * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN | ||
17 | * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
18 | */ | ||
19 | |||
20 | #include <assert.h> | ||
21 | #include <err.h> | ||
22 | #include <stdint.h> | ||
23 | #include <stdio.h> | ||
24 | #include <stdlib.h> | ||
25 | |||
26 | #include "bytestring.h" | ||
27 | #include "mlkem.h" | ||
28 | |||
29 | #include "mlkem_internal.h" | ||
30 | #include "mlkem_tests_util.h" | ||
31 | |||
32 | static int | ||
33 | MlkemKeygenFileTest(CBB *seed_cbb, CBB *public_key_cbb, CBB *private_key_cbb, | ||
34 | size_t line) | ||
35 | { | ||
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; | ||
39 | uint8_t *encoded_private_key = NULL; | ||
40 | uint8_t encoded_public_key[MLKEM768_PUBLIC_KEY_BYTES]; | ||
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; | ||
58 | |||
59 | MLKEM768_generate_key_external_entropy(encoded_public_key, &priv, | ||
60 | seed); | ||
61 | if (!mlkem768_encode_private_key(&priv, &encoded_private_key, &len)) { | ||
62 | warnx("#%zu: encoded_private_key", line); | ||
63 | goto err; | ||
64 | } | ||
65 | |||
66 | if (!compare_length(MLKEM768_PRIVATE_KEY_BYTES, len, line, | ||
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); | ||
82 | free(encoded_private_key); | ||
83 | |||
84 | return failed; | ||
85 | } | ||
86 | |||
87 | #define S_START 0 | ||
88 | #define S_COMMENT 1 | ||
89 | #define S_SEED 2 | ||
90 | #define S_PUBLIC_KEY 3 | ||
91 | #define S_PRIVATE_KEY 4 | ||
92 | |||
93 | #define S2S(x) case x: return #x | ||
94 | |||
95 | static const char * | ||
96 | state2str(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 | } | ||
108 | |||
109 | int | ||
110 | main(int argc, char **argv) | ||
111 | { | ||
112 | CBB seed = { 0 }, public_key = { 0 }, private_key = { 0 }; | ||
113 | const char *test; | ||
114 | size_t line = 0; | ||
115 | char *buf = NULL; | ||
116 | size_t buflen = 0; | ||
117 | ssize_t len; | ||
118 | FILE *fp; | ||
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, "can'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'); | ||
144 | |||
145 | switch (state) { | ||
146 | case S_START: | ||
147 | state = S_COMMENT; | ||
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); | ||
155 | state = S_SEED; | ||
156 | break; | ||
157 | case S_SEED: | ||
158 | if (!get_string_cbs(&cbs, "seed: ", line, msg)) | ||
159 | errx(1, "#%zu %s: get_string_cbs", line, msg); | ||
160 | hex_decode_cbs(&cbs, &seed, line, msg); | ||
161 | state = S_PUBLIC_KEY; | ||
162 | break; | ||
163 | case S_PUBLIC_KEY: | ||
164 | if (!get_string_cbs(&cbs, "public_key: ", line, msg)) | ||
165 | errx(1, "#%zu %s: get_string_cbs", line, msg); | ||
166 | hex_decode_cbs(&cbs, &public_key, line, msg); | ||
167 | state = S_PRIVATE_KEY; | ||
168 | break; | ||
169 | case S_PRIVATE_KEY: | ||
170 | if (!get_string_cbs(&cbs, "private_key: ", line, msg)) | ||
171 | errx(1, "#%zu %s: get_string_cbs", line, msg); | ||
172 | hex_decode_cbs(&cbs, &private_key, line, msg); | ||
173 | |||
174 | failed |= MlkemKeygenFileTest(&seed, &public_key, | ||
175 | &private_key, line); | ||
176 | |||
177 | state = S_START; | ||
178 | break; | ||
179 | } | ||
180 | if (CBS_len(&cbs) > 0) | ||
181 | errx(1, "#%zu %s: CBS_len", line, msg); | ||
182 | } | ||
183 | free(buf); | ||
184 | |||
185 | if (ferror(fp)) | ||
186 | err(1, NULL); | ||
187 | fclose(fp); | ||
188 | |||
189 | return failed; | ||
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 deleted file mode 100644 index 9de8958c39..0000000000 --- a/src/regress/lib/libcrypto/mlkem/mlkem768_nist_decap_tests.c +++ /dev/null | |||
@@ -1,193 +0,0 @@ | |||
1 | /* $OpenBSD: mlkem768_nist_decap_tests.c,v 1.4 2024/12/20 00:32:15 tb Exp $ */ | ||
2 | /* | ||
3 | * Copyright (c) 2024 Google Inc. | ||
4 | * Copyright (c) 2024 Bob Beck <beck@obtuse.com> | ||
5 | * Copyright (c) 2024 Theo Buehler <tb@openbsd.org> | ||
6 | * | ||
7 | * Permission to use, copy, modify, and/or distribute this software for any | ||
8 | * purpose with or without fee is hereby granted, provided that the above | ||
9 | * copyright notice and this permission notice appear in all copies. | ||
10 | * | ||
11 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||
12 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | ||
13 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY | ||
14 | * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||
15 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION | ||
16 | * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN | ||
17 | * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
18 | */ | ||
19 | |||
20 | #include <assert.h> | ||
21 | #include <err.h> | ||
22 | #include <stdint.h> | ||
23 | #include <stdio.h> | ||
24 | #include <stdlib.h> | ||
25 | |||
26 | #include "bytestring.h" | ||
27 | #include "mlkem.h" | ||
28 | |||
29 | #include "mlkem_internal.h" | ||
30 | #include "mlkem_tests_util.h" | ||
31 | |||
32 | static int | ||
33 | MlkemNistDecapFileTest(CBB *c_cbb, CBB *k_cbb, CBS *dk, size_t line) | ||
34 | { | ||
35 | uint8_t *c = NULL, *k = NULL; | ||
36 | size_t c_len = 0, k_len = 0; | ||
37 | uint8_t shared_secret[MLKEM_SHARED_SECRET_BYTES]; | ||
38 | struct MLKEM768_private_key priv; | ||
39 | int failed = 1; | ||
40 | |||
41 | if (!CBB_finish(c_cbb, &c, &c_len)) | ||
42 | goto err; | ||
43 | if (!CBB_finish(k_cbb, &k, &k_len)) | ||
44 | goto err; | ||
45 | |||
46 | if (!compare_length(MLKEM768_PRIVATE_KEY_BYTES, CBS_len(dk), line, | ||
47 | "private key len bogus")) | ||
48 | goto err; | ||
49 | if (!compare_length(MLKEM_SHARED_SECRET_BYTES, k_len, line, | ||
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; | ||
71 | } | ||
72 | |||
73 | #define S_START 0 | ||
74 | #define S_C 1 | ||
75 | #define S_K 2 | ||
76 | #define S_EMPTY 3 | ||
77 | |||
78 | #define S2S(x) case x: return #x | ||
79 | |||
80 | static const char * | ||
81 | state2str(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 | } | ||
92 | |||
93 | int | ||
94 | main(int argc, char **argv) | ||
95 | { | ||
96 | CBB dk_cbb = { 0 }, c = { 0 }, k = { 0 }; | ||
97 | CBS instr; | ||
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; | ||
106 | FILE *fp; | ||
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, "can'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'); | ||
156 | |||
157 | switch (state) { | ||
158 | case S_START: | ||
159 | state = S_C; | ||
160 | break; | ||
161 | case S_C: | ||
162 | if (!get_string_cbs(&cbs, "c: ", line, msg)) | ||
163 | errx(1, "#%zu %s: get_string_cbs", line, msg); | ||
164 | hex_decode_cbs(&cbs, &c, line, msg); | ||
165 | state = S_K; | ||
166 | break; | ||
167 | case S_K: | ||
168 | if (!get_string_cbs(&cbs, "k: ", line, msg)) | ||
169 | errx(1, "#%zu %s: get_string_cbs", line, msg); | ||
170 | hex_decode_cbs(&cbs, &k, line, msg); | ||
171 | state = S_EMPTY; | ||
172 | break; | ||
173 | case S_EMPTY: | ||
174 | CBS_init(&dk_cbs, dk, dk_len); | ||
175 | |||
176 | failed |= MlkemNistDecapFileTest(&c, &k, &dk_cbs, line); | ||
177 | |||
178 | state = S_C; | ||
179 | break; | ||
180 | } | ||
181 | if (CBS_len(&cbs) > 0) | ||
182 | errx(1, "#%zu %s: CBS_len", line, msg); | ||
183 | } | ||
184 | free(buf); | ||
185 | |||
186 | if (ferror(fp)) | ||
187 | err(1, NULL); | ||
188 | fclose(fp); | ||
189 | |||
190 | freezero(dk, dk_len); | ||
191 | |||
192 | return failed; | ||
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 deleted file mode 100644 index ae0e018e69..0000000000 --- a/src/regress/lib/libcrypto/mlkem/mlkem768_nist_keygen_tests.c +++ /dev/null | |||
@@ -1,197 +0,0 @@ | |||
1 | /* $OpenBSD: mlkem768_nist_keygen_tests.c,v 1.5 2024/12/20 00:32:15 tb Exp $ */ | ||
2 | /* | ||
3 | * Copyright (c) 2024 Google Inc. | ||
4 | * Copyright (c) 2024 Bob Beck <beck@obtuse.com> | ||
5 | * Copyright (c) 2024 Theo Buehler <tb@openbsd.org> | ||
6 | * | ||
7 | * Permission to use, copy, modify, and/or distribute this software for any | ||
8 | * purpose with or without fee is hereby granted, provided that the above | ||
9 | * copyright notice and this permission notice appear in all copies. | ||
10 | * | ||
11 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||
12 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | ||
13 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY | ||
14 | * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||
15 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION | ||
16 | * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN | ||
17 | * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
18 | */ | ||
19 | |||
20 | #include <assert.h> | ||
21 | #include <err.h> | ||
22 | #include <stdint.h> | ||
23 | #include <stdio.h> | ||
24 | #include <stdlib.h> | ||
25 | |||
26 | #include "bytestring.h" | ||
27 | #include "mlkem.h" | ||
28 | |||
29 | #include "mlkem_internal.h" | ||
30 | #include "mlkem_tests_util.h" | ||
31 | |||
32 | static int | ||
33 | MlkemNistKeygenFileTest(CBB *z_cbb, CBB *d_cbb, CBB *ek_cbb, CBB *dk_cbb, | ||
34 | size_t line) | ||
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; | ||
39 | uint8_t seed[MLKEM_SEED_BYTES]; | ||
40 | struct MLKEM768_private_key priv; | ||
41 | uint8_t *encoded_private_key = NULL; | ||
42 | uint8_t encoded_public_key[MLKEM768_PUBLIC_KEY_BYTES]; | ||
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; | ||
67 | |||
68 | MLKEM768_generate_key_external_entropy(encoded_public_key, &priv, seed); | ||
69 | |||
70 | if (!mlkem768_encode_private_key(&priv, &encoded_private_key, &len)) { | ||
71 | warnx("#%zu mlkem768_encode_private_key", line); | ||
72 | goto err; | ||
73 | } | ||
74 | |||
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); | ||
94 | free(encoded_private_key); | ||
95 | |||
96 | return failed; | ||
97 | } | ||
98 | |||
99 | #define S_START 0 | ||
100 | #define S_Z 1 | ||
101 | #define S_D 2 | ||
102 | #define S_EK 3 | ||
103 | #define S_DK 4 | ||
104 | |||
105 | #define S2S(x) case x: return #x | ||
106 | |||
107 | static const char * | ||
108 | state2str(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 | } | ||
120 | |||
121 | int | ||
122 | main(int argc, char **argv) | ||
123 | { | ||
124 | CBB z = { 0 }, d = { 0 }, ek = { 0 }, dk = { 0 }; | ||
125 | const char *test; | ||
126 | size_t line = 0; | ||
127 | char *buf = NULL; | ||
128 | size_t buflen = 0; | ||
129 | ssize_t len; | ||
130 | FILE *fp; | ||
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, "can't open test file"); | ||
141 | |||
142 | state = S_Z; | ||
143 | line = 0; | ||
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 | |||
157 | switch (state) { | ||
158 | case S_START: | ||
159 | state = S_Z; | ||
160 | break; | ||
161 | case S_Z: | ||
162 | if (!get_string_cbs(&cbs, "z: ", line, msg)) | ||
163 | errx(1, "#%zu %s: get_string_cbs", line, msg); | ||
164 | hex_decode_cbs(&cbs, &z, line, msg); | ||
165 | state = S_D; | ||
166 | break; | ||
167 | case S_D: | ||
168 | if (!get_string_cbs(&cbs, "d: ", line, msg)) | ||
169 | errx(1, "#%zu %s: get_string_cbs", line, msg); | ||
170 | hex_decode_cbs(&cbs, &d, line, msg); | ||
171 | state = S_EK; | ||
172 | break; | ||
173 | case S_EK: | ||
174 | if (!get_string_cbs(&cbs, "ek: ", line, msg)) | ||
175 | errx(1, "#%zu %s: get_string_cbs", line, msg); | ||
176 | hex_decode_cbs(&cbs, &ek, line, msg); | ||
177 | state = S_DK; | ||
178 | break; | ||
179 | case S_DK: | ||
180 | if (!get_string_cbs(&cbs, "dk: ", line, msg)) | ||
181 | errx(1, "#%zu %s: get_string_cbs", line, msg); | ||
182 | hex_decode_cbs(&cbs, &dk, line, msg); | ||
183 | |||
184 | failed |= MlkemNistKeygenFileTest(&z, &d, &ek, &dk, line); | ||
185 | |||
186 | state = S_START; | ||
187 | break; | ||
188 | } | ||
189 | } | ||
190 | free(buf); | ||
191 | |||
192 | if (ferror(fp)) | ||
193 | err(1, NULL); | ||
194 | fclose(fp); | ||
195 | |||
196 | return failed; | ||
197 | } | ||
diff --git a/src/regress/lib/libcrypto/mlkem/mlkem_iteration_tests.c b/src/regress/lib/libcrypto/mlkem/mlkem_iteration_tests.c new file mode 100644 index 0000000000..1ecda95bb9 --- /dev/null +++ b/src/regress/lib/libcrypto/mlkem/mlkem_iteration_tests.c | |||
@@ -0,0 +1,230 @@ | |||
1 | /* $OpenBSD: mlkem_iteration_tests.c,v 1.1 2024/12/26 00:04:24 tb Exp $ */ | ||
2 | /* | ||
3 | * Copyright (c) 2024 Google Inc. | ||
4 | * Copyright (c) 2024 Bob Beck <beck@obtuse.com> | ||
5 | * Copyright (c) 2024 Theo Buehler <tb@openbsd.org> | ||
6 | * | ||
7 | * Permission to use, copy, modify, and/or distribute this software for any | ||
8 | * purpose with or without fee is hereby granted, provided that the above | ||
9 | * copyright notice and this permission notice appear in all copies. | ||
10 | * | ||
11 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||
12 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | ||
13 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY | ||
14 | * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||
15 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION | ||
16 | * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN | ||
17 | * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
18 | */ | ||
19 | |||
20 | #include <err.h> | ||
21 | #include <stdint.h> | ||
22 | #include <stdio.h> | ||
23 | #include <stdlib.h> | ||
24 | |||
25 | #include "mlkem.h" | ||
26 | |||
27 | #include "mlkem_internal.h" | ||
28 | #include "mlkem_tests_util.h" | ||
29 | #include "sha3_internal.h" | ||
30 | |||
31 | /* | ||
32 | * Based on https://c2sp.org/CCTV/ML-KEM | ||
33 | * | ||
34 | * The final value has been updated to reflect the change from Kyber to ML-KEM. | ||
35 | * | ||
36 | * The deterministic RNG is a single SHAKE-128 instance with an empty input. | ||
37 | * (The RNG stream starts with 7f9c2ba4e88f827d616045507605853e.) | ||
38 | */ | ||
39 | const uint8_t kExpectedSeedStart[16] = { | ||
40 | 0x7f, 0x9c, 0x2b, 0xa4, 0xe8, 0x8f, 0x82, 0x7d, 0x61, 0x60, 0x45, | ||
41 | 0x50, 0x76, 0x05, 0x85, 0x3e | ||
42 | }; | ||
43 | |||
44 | /* | ||
45 | * Filippo says: | ||
46 | * ML-KEM-768: f7db260e1137a742e05fe0db9525012812b004d29040a5b606aad3d134b548d3 | ||
47 | * but Boring believes this: | ||
48 | */ | ||
49 | const uint8_t kExpectedAdam768[32] = { | ||
50 | 0xf9, 0x59, 0xd1, 0x8d, 0x3d, 0x11, 0x80, 0x12, 0x14, 0x33, 0xbf, | ||
51 | 0x0e, 0x05, 0xf1, 0x1e, 0x79, 0x08, 0xcf, 0x9d, 0x03, 0xed, 0xc1, | ||
52 | 0x50, 0xb2, 0xb0, 0x7c, 0xb9, 0x0b, 0xef, 0x5b, 0xc1, 0xc1 | ||
53 | }; | ||
54 | |||
55 | /* | ||
56 | * Filippo says: | ||
57 | * ML-KEM-1024: 47ac888fe61544efc0518f46094b4f8a600965fc89822acb06dc7169d24f3543 | ||
58 | * but Boring believes this: | ||
59 | */ | ||
60 | const uint8_t kExpectedAdam1024[32] = { | ||
61 | 0xe3, 0xbf, 0x82, 0xb0, 0x13, 0x30, 0x7b, 0x2e, 0x9d, 0x47, 0xdd, | ||
62 | 0xe7, 0x91, 0xff, 0x6d, 0xfc, 0x82, 0xe6, 0x94, 0xe6, 0x38, 0x24, | ||
63 | 0x04, 0xab, 0xdb, 0x94, 0x8b, 0x90, 0x8b, 0x75, 0xba, 0xd5 | ||
64 | }; | ||
65 | |||
66 | typedef void (*mlkem_public_from_private_fn)(void *out_public_key, | ||
67 | const void *private_key); | ||
68 | |||
69 | struct iteration_ctx { | ||
70 | uint8_t *encoded_public_key; | ||
71 | size_t encoded_public_key_len; | ||
72 | uint8_t *ciphertext; | ||
73 | size_t ciphertext_len; | ||
74 | uint8_t *invalid_ciphertext; | ||
75 | size_t invalid_ciphertext_len; | ||
76 | void *priv; | ||
77 | void *pub; | ||
78 | |||
79 | mlkem_encode_private_key_fn encode_private_key; | ||
80 | mlkem_encap_external_entropy_fn encap_external_entropy; | ||
81 | mlkem_generate_key_external_entropy_fn generate_key_external_entropy; | ||
82 | mlkem_public_from_private_fn public_from_private; | ||
83 | mlkem_decap_fn decap; | ||
84 | |||
85 | const uint8_t *start; | ||
86 | size_t start_len; | ||
87 | |||
88 | const uint8_t *expected; | ||
89 | size_t expected_len; | ||
90 | }; | ||
91 | |||
92 | static int | ||
93 | MlkemIterativeTest(struct iteration_ctx *ctx) | ||
94 | { | ||
95 | uint8_t shared_secret[MLKEM_SHARED_SECRET_BYTES]; | ||
96 | uint8_t encap_entropy[MLKEM_ENCAP_ENTROPY]; | ||
97 | uint8_t seed[MLKEM_SEED_BYTES] = {0}; | ||
98 | sha3_ctx drng, results; | ||
99 | uint8_t out[32]; | ||
100 | int i; | ||
101 | |||
102 | shake128_init(&drng); | ||
103 | shake128_init(&results); | ||
104 | |||
105 | shake_xof(&drng); | ||
106 | for (i = 0; i < 10000; i++) { | ||
107 | uint8_t *encoded_private_key = NULL; | ||
108 | size_t encoded_private_key_len; | ||
109 | |||
110 | /* | ||
111 | * This should draw both d and z from DRNG concatenating in | ||
112 | * seed. | ||
113 | */ | ||
114 | shake_out(&drng, seed, sizeof(seed)); | ||
115 | if (i == 0) { | ||
116 | if (compare_data(seed, ctx->start, ctx->start_len, | ||
117 | "seed start") != 0) | ||
118 | errx(1, "compare_data"); | ||
119 | } | ||
120 | |||
121 | /* generate ek as encoded_public_key */ | ||
122 | ctx->generate_key_external_entropy(ctx->encoded_public_key, | ||
123 | ctx->priv, seed); | ||
124 | ctx->public_from_private(ctx->pub, ctx->priv); | ||
125 | |||
126 | /* hash in ek */ | ||
127 | shake_update(&results, ctx->encoded_public_key, | ||
128 | ctx->encoded_public_key_len); | ||
129 | |||
130 | /* marshal priv to dk as encoded_private_key */ | ||
131 | if (!ctx->encode_private_key(ctx->priv, &encoded_private_key, | ||
132 | &encoded_private_key_len)) | ||
133 | errx(1, "encode private key"); | ||
134 | |||
135 | /* hash in dk */ | ||
136 | shake_update(&results, encoded_private_key, | ||
137 | encoded_private_key_len); | ||
138 | |||
139 | free(encoded_private_key); | ||
140 | |||
141 | /* draw m as encap entropy from DRNG */ | ||
142 | shake_out(&drng, encap_entropy, sizeof(encap_entropy)); | ||
143 | |||
144 | /* generate ct as ciphertext, k as shared_secret */ | ||
145 | ctx->encap_external_entropy(ctx->ciphertext, shared_secret, | ||
146 | ctx->pub, encap_entropy); | ||
147 | |||
148 | /* hash in ct */ | ||
149 | shake_update(&results, ctx->ciphertext, ctx->ciphertext_len); | ||
150 | /* hash in k */ | ||
151 | shake_update(&results, shared_secret, sizeof(shared_secret)); | ||
152 | |||
153 | /* draw ct as invalid_ciphertxt from DRNG */ | ||
154 | shake_out(&drng, ctx->invalid_ciphertext, | ||
155 | ctx->invalid_ciphertext_len); | ||
156 | |||
157 | /* generate k as shared secret from invalid ciphertext */ | ||
158 | if (!ctx->decap(shared_secret, ctx->invalid_ciphertext, | ||
159 | ctx->invalid_ciphertext_len, ctx->priv)) | ||
160 | errx(1, "decap failed"); | ||
161 | |||
162 | /* hash in k */ | ||
163 | shake_update(&results, shared_secret, sizeof(shared_secret)); | ||
164 | } | ||
165 | shake_xof(&results); | ||
166 | shake_out(&results, out, sizeof(out)); | ||
167 | |||
168 | return compare_data(ctx->expected, out, sizeof(out), "final result hash"); | ||
169 | } | ||
170 | |||
171 | int | ||
172 | main(void) | ||
173 | { | ||
174 | uint8_t encoded_public_key768[MLKEM768_PUBLIC_KEY_BYTES]; | ||
175 | uint8_t ciphertext768[MLKEM768_CIPHERTEXT_BYTES]; | ||
176 | uint8_t invalid_ciphertext768[MLKEM768_CIPHERTEXT_BYTES]; | ||
177 | struct MLKEM768_private_key priv768; | ||
178 | struct MLKEM768_public_key pub768; | ||
179 | struct iteration_ctx iteration768 = { | ||
180 | .encoded_public_key = encoded_public_key768, | ||
181 | .encoded_public_key_len = sizeof(encoded_public_key768), | ||
182 | .ciphertext = ciphertext768, | ||
183 | .ciphertext_len = sizeof(ciphertext768), | ||
184 | .invalid_ciphertext = invalid_ciphertext768, | ||
185 | .invalid_ciphertext_len = sizeof(invalid_ciphertext768), | ||
186 | .priv = &priv768, | ||
187 | .pub = &pub768, | ||
188 | .encap_external_entropy = mlkem768_encap_external_entropy, | ||
189 | .encode_private_key = mlkem768_encode_private_key, | ||
190 | .generate_key_external_entropy = | ||
191 | mlkem768_generate_key_external_entropy, | ||
192 | .public_from_private = mlkem768_public_from_private, | ||
193 | .decap = mlkem768_decap, | ||
194 | .start = kExpectedSeedStart, | ||
195 | .start_len = sizeof(kExpectedSeedStart), | ||
196 | .expected = kExpectedAdam768, | ||
197 | .expected_len = sizeof(kExpectedAdam768), | ||
198 | }; | ||
199 | uint8_t encoded_public_key1024[MLKEM1024_PUBLIC_KEY_BYTES]; | ||
200 | uint8_t ciphertext1024[MLKEM1024_CIPHERTEXT_BYTES]; | ||
201 | uint8_t invalid_ciphertext1024[MLKEM1024_CIPHERTEXT_BYTES]; | ||
202 | struct MLKEM1024_private_key priv1024; | ||
203 | struct MLKEM1024_public_key pub1024; | ||
204 | struct iteration_ctx iteration1024 = { | ||
205 | .encoded_public_key = encoded_public_key1024, | ||
206 | .encoded_public_key_len = sizeof(encoded_public_key1024), | ||
207 | .ciphertext = ciphertext1024, | ||
208 | .ciphertext_len = sizeof(ciphertext1024), | ||
209 | .invalid_ciphertext = invalid_ciphertext1024, | ||
210 | .invalid_ciphertext_len = sizeof(invalid_ciphertext1024), | ||
211 | .priv = &priv1024, | ||
212 | .pub = &pub1024, | ||
213 | .encap_external_entropy = mlkem1024_encap_external_entropy, | ||
214 | .encode_private_key = mlkem1024_encode_private_key, | ||
215 | .generate_key_external_entropy = | ||
216 | mlkem1024_generate_key_external_entropy, | ||
217 | .public_from_private = mlkem1024_public_from_private, | ||
218 | .decap = mlkem1024_decap, | ||
219 | .start = kExpectedSeedStart, | ||
220 | .start_len = sizeof(kExpectedSeedStart), | ||
221 | .expected = kExpectedAdam1024, | ||
222 | .expected_len = sizeof(kExpectedAdam1024), | ||
223 | }; | ||
224 | int failed = 0; | ||
225 | |||
226 | failed |= MlkemIterativeTest(&iteration768); | ||
227 | failed |= MlkemIterativeTest(&iteration1024); | ||
228 | |||
229 | return failed; | ||
230 | } | ||
diff --git a/src/regress/lib/libcrypto/mlkem/mlkem_tests.c b/src/regress/lib/libcrypto/mlkem/mlkem_tests.c new file mode 100644 index 0000000000..716f38d144 --- /dev/null +++ b/src/regress/lib/libcrypto/mlkem/mlkem_tests.c | |||
@@ -0,0 +1,728 @@ | |||
1 | /* $OpenBSD: mlkem_tests.c,v 1.1 2024/12/26 00:04:24 tb Exp $ */ | ||
2 | /* | ||
3 | * Copyright (c) 2024 Google Inc. | ||
4 | * Copyright (c) 2024 Theo Buehler <tb@openbsd.org> | ||
5 | * Copyright (c) 2024 Bob Beck <beck@obtuse.com> | ||
6 | * | ||
7 | * Permission to use, copy, modify, and/or distribute this software for any | ||
8 | * purpose with or without fee is hereby granted, provided that the above | ||
9 | * copyright notice and this permission notice appear in all copies. | ||
10 | * | ||
11 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||
12 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | ||
13 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY | ||
14 | * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||
15 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION | ||
16 | * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN | ||
17 | * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
18 | */ | ||
19 | |||
20 | #include <err.h> | ||
21 | #include <stdint.h> | ||
22 | #include <stdio.h> | ||
23 | #include <stdlib.h> | ||
24 | #include <string.h> | ||
25 | |||
26 | #include "bytestring.h" | ||
27 | #include "mlkem.h" | ||
28 | |||
29 | #include "mlkem_internal.h" | ||
30 | |||
31 | #include "mlkem_tests_util.h" | ||
32 | #include "parse_test_file.h" | ||
33 | |||
34 | enum test_type { | ||
35 | TEST_TYPE_NORMAL, | ||
36 | TEST_TYPE_NIST, | ||
37 | }; | ||
38 | |||
39 | struct decap_ctx { | ||
40 | struct parse *parse_ctx; | ||
41 | |||
42 | void *private_key; | ||
43 | size_t private_key_len; | ||
44 | |||
45 | mlkem_parse_private_key_fn parse_private_key; | ||
46 | mlkem_decap_fn decap; | ||
47 | }; | ||
48 | |||
49 | enum decap_states { | ||
50 | DECAP_PRIVATE_KEY, | ||
51 | DECAP_CIPHERTEXT, | ||
52 | DECAP_RESULT, | ||
53 | DECAP_SHARED_SECRET, | ||
54 | N_DECAP_STATES, | ||
55 | }; | ||
56 | |||
57 | static const struct line_spec decap_state_machine[] = { | ||
58 | [DECAP_PRIVATE_KEY] = { | ||
59 | .state = DECAP_PRIVATE_KEY, | ||
60 | .type = LINE_HEX, | ||
61 | .name = "private key", | ||
62 | .label = "private_key", | ||
63 | }, | ||
64 | [DECAP_CIPHERTEXT] = { | ||
65 | .state = DECAP_CIPHERTEXT, | ||
66 | .type = LINE_HEX, | ||
67 | .name = "cipher text", | ||
68 | .label = "ciphertext", | ||
69 | }, | ||
70 | [DECAP_RESULT] = { | ||
71 | .state = DECAP_RESULT, | ||
72 | .type = LINE_STRING_MATCH, | ||
73 | .name = "result", | ||
74 | .label = "result", | ||
75 | .match = "fail", | ||
76 | }, | ||
77 | [DECAP_SHARED_SECRET] = { | ||
78 | .state = DECAP_SHARED_SECRET, | ||
79 | .type = LINE_HEX, | ||
80 | .name = "shared secret", | ||
81 | .label = "shared_secret", | ||
82 | }, | ||
83 | }; | ||
84 | |||
85 | static int | ||
86 | decap_init(void *ctx, void *parse_ctx) | ||
87 | { | ||
88 | struct decap_ctx *decap = ctx; | ||
89 | |||
90 | decap->parse_ctx = parse_ctx; | ||
91 | |||
92 | return 1; | ||
93 | } | ||
94 | |||
95 | static void | ||
96 | decap_finish(void *ctx) | ||
97 | { | ||
98 | (void)ctx; | ||
99 | } | ||
100 | |||
101 | static int | ||
102 | MlkemDecapFileTest(struct decap_ctx *decap) | ||
103 | { | ||
104 | struct parse *p = decap->parse_ctx; | ||
105 | uint8_t shared_secret_buf[MLKEM_SHARED_SECRET_BYTES]; | ||
106 | CBS ciphertext, shared_secret, private_key; | ||
107 | int should_fail; | ||
108 | int failed = 1; | ||
109 | |||
110 | parse_get_cbs(p, DECAP_CIPHERTEXT, &ciphertext); | ||
111 | parse_get_cbs(p, DECAP_SHARED_SECRET, &shared_secret); | ||
112 | parse_get_cbs(p, DECAP_PRIVATE_KEY, &private_key); | ||
113 | parse_get_int(p, DECAP_RESULT, &should_fail); | ||
114 | |||
115 | if (!decap->parse_private_key(decap->private_key, &private_key)) { | ||
116 | if ((failed = !should_fail)) | ||
117 | parse_info(p, "parse private key"); | ||
118 | goto err; | ||
119 | } | ||
120 | if (!decap->decap(shared_secret_buf, | ||
121 | CBS_data(&ciphertext), CBS_len(&ciphertext), decap->private_key)) { | ||
122 | if ((failed = !should_fail)) | ||
123 | parse_info(p, decap"); | ||
124 | goto err; | ||
125 | } | ||
126 | |||
127 | failed = !parse_data_equal(p, "shared_secret", &shared_secret, | ||
128 | shared_secret_buf, sizeof(shared_secret_buf)); | ||
129 | |||
130 | if (should_fail != failed) { | ||
131 | parse_info(p, "FAIL: should_fail %d, failed %d", | ||
132 | should_fail, failed); | ||
133 | failed = 1; | ||
134 | } | ||
135 | |||
136 | err: | ||
137 | return failed; | ||
138 | } | ||
139 | |||
140 | static int | ||
141 | decap_run_test_case(void *ctx) | ||
142 | { | ||
143 | return MlkemDecapFileTest(ctx); | ||
144 | } | ||
145 | |||
146 | static const struct test_parse decap_parse = { | ||
147 | .states = decap_state_machine, | ||
148 | .num_states = N_DECAP_STATES, | ||
149 | |||
150 | .init = decap_init, | ||
151 | .finish = decap_finish, | ||
152 | |||
153 | .run_test_case = decap_run_test_case, | ||
154 | }; | ||
155 | |||
156 | enum nist_decap_instructions { | ||
157 | NIST_DECAP_DK, | ||
158 | N_NIST_DECAP_INSTRUCTIONS, | ||
159 | }; | ||
160 | |||
161 | static const struct line_spec nist_decap_instruction_state_machine[] = { | ||
162 | [NIST_DECAP_DK] = { | ||
163 | .state = NIST_DECAP_DK, | ||
164 | .type = LINE_HEX, | ||
165 | .name = "private key (instruction [dk])", | ||
166 | .label = "dk", | ||
167 | }, | ||
168 | }; | ||
169 | |||
170 | enum nist_decap_states { | ||
171 | NIST_DECAP_C, | ||
172 | NIST_DECAP_K, | ||
173 | N_NIST_DECAP_STATES, | ||
174 | }; | ||
175 | |||
176 | static const struct line_spec nist_decap_state_machine[] = { | ||
177 | [NIST_DECAP_C] = { | ||
178 | .state = NIST_DECAP_C, | ||
179 | .type = LINE_HEX, | ||
180 | .name = "ciphertext (c)", | ||
181 | .label = "c", | ||
182 | }, | ||
183 | [NIST_DECAP_K] = { | ||
184 | .state = NIST_DECAP_K, | ||
185 | .type = LINE_HEX, | ||
186 | .name = "shared secret (k)", | ||
187 | .label = "k", | ||
188 | }, | ||
189 | }; | ||
190 | |||
191 | static int | ||
192 | MlkemNistDecapFileTest(struct decap_ctx *decap) | ||
193 | { | ||
194 | struct parse *p = decap->parse_ctx; | ||
195 | uint8_t shared_secret[MLKEM_SHARED_SECRET_BYTES]; | ||
196 | CBS dk, c, k; | ||
197 | int failed = 1; | ||
198 | |||
199 | parse_instruction_get_cbs(p, NIST_DECAP_DK, &dk); | ||
200 | parse_get_cbs(p, NIST_DECAP_C, &c); | ||
201 | parse_get_cbs(p, NIST_DECAP_K, &k); | ||
202 | |||
203 | if (!parse_length_equal(p, "private key", | ||
204 | decap->private_key_len, CBS_len(&dk))) | ||
205 | goto err; | ||
206 | if (!parse_length_equal(p, "shared secret", | ||
207 | MLKEM_SHARED_SECRET_BYTES, CBS_len(&k))) | ||
208 | goto err; | ||
209 | |||
210 | if (!decap->parse_private_key(decap->private_key, &dk)) { | ||
211 | parse_info(p, "parse private key"); | ||
212 | goto err; | ||
213 | } | ||
214 | if (!decap->decap(shared_secret, CBS_data(&c), CBS_len(&c), | ||
215 | decap->private_key)) { | ||
216 | parse_info(p, "decap"); | ||
217 | goto err; | ||
218 | } | ||
219 | |||
220 | failed = !parse_data_equal(p, "shared secret", &k, | ||
221 | shared_secret, MLKEM_SHARED_SECRET_BYTES); | ||
222 | |||
223 | err: | ||
224 | return failed; | ||
225 | } | ||
226 | |||
227 | static int | ||
228 | nist_decap_run_test_case(void *ctx) | ||
229 | { | ||
230 | return MlkemNistDecapFileTest(ctx); | ||
231 | } | ||
232 | |||
233 | static const struct test_parse nist_decap_parse = { | ||
234 | .instructions = nist_decap_instruction_state_machine, | ||
235 | .num_instructions = N_NIST_DECAP_INSTRUCTIONS, | ||
236 | |||
237 | .states = nist_decap_state_machine, | ||
238 | .num_states = N_NIST_DECAP_STATES, | ||
239 | |||
240 | .init = decap_init, | ||
241 | .finish = decap_finish, | ||
242 | |||
243 | .run_test_case = nist_decap_run_test_case, | ||
244 | }; | ||
245 | |||
246 | static int | ||
247 | mlkem_decap_tests(const char *fn, size_t size, enum test_type test_type) | ||
248 | { | ||
249 | struct MLKEM768_private_key private_key768; | ||
250 | struct decap_ctx decap768 = { | ||
251 | .private_key = &private_key768, | ||
252 | .private_key_len = MLKEM768_PRIVATE_KEY_BYTES, | ||
253 | |||
254 | .parse_private_key = mlkem768_parse_private_key, | ||
255 | .decap = mlkem768_decap, | ||
256 | }; | ||
257 | struct MLKEM1024_private_key private_key1024; | ||
258 | struct decap_ctx decap1024 = { | ||
259 | .private_key = &private_key1024, | ||
260 | .private_key_len = MLKEM1024_PRIVATE_KEY_BYTES, | ||
261 | |||
262 | .parse_private_key = mlkem1024_parse_private_key, | ||
263 | .decap = mlkem1024_decap, | ||
264 | }; | ||
265 | |||
266 | if (size == 768 && test_type == TEST_TYPE_NORMAL) | ||
267 | return parse_test_file(fn, &decap_parse, &decap768); | ||
268 | if (size == 768 && test_type == TEST_TYPE_NIST) | ||
269 | return parse_test_file(fn, &nist_decap_parse, &decap768); | ||
270 | if (size == 1024 && test_type == TEST_TYPE_NORMAL) | ||
271 | return parse_test_file(fn, &decap_parse, &decap1024); | ||
272 | if (size == 1024 && test_type == TEST_TYPE_NIST) | ||
273 | return parse_test_file(fn, &nist_decap_parse, &decap1024); | ||
274 | |||
275 | errx(1, "unknown decap test: size %zu, type %d", size, test_type); | ||
276 | } | ||
277 | |||
278 | struct encap_ctx { | ||
279 | struct parse *parse_ctx; | ||
280 | |||
281 | void *public_key; | ||
282 | uint8_t *ciphertext; | ||
283 | size_t ciphertext_len; | ||
284 | |||
285 | mlkem_parse_public_key_fn parse_public_key; | ||
286 | mlkem_encap_external_entropy_fn encap_external_entropy; | ||
287 | }; | ||
288 | |||
289 | enum encap_states { | ||
290 | ENCAP_ENTROPY, | ||
291 | ENCAP_PUBLIC_KEY, | ||
292 | ENCAP_RESULT, | ||
293 | ENCAP_CIPHERTEXT, | ||
294 | ENCAP_SHARED_SECRET, | ||
295 | N_ENCAP_STATES, | ||
296 | }; | ||
297 | |||
298 | static const struct line_spec encap_state_machine[] = { | ||
299 | [ENCAP_ENTROPY] = { | ||
300 | .state = ENCAP_ENTROPY, | ||
301 | .type = LINE_HEX, | ||
302 | .name = "entropy", | ||
303 | .label = "entropy", | ||
304 | }, | ||
305 | [ENCAP_PUBLIC_KEY] = { | ||
306 | .state = ENCAP_PUBLIC_KEY, | ||
307 | .type = LINE_HEX, | ||
308 | .name = "public key", | ||
309 | .label = "public_key", | ||
310 | }, | ||
311 | [ENCAP_RESULT] = { | ||
312 | .state = ENCAP_RESULT, | ||
313 | .type = LINE_STRING_MATCH, | ||
314 | .name = "result", | ||
315 | .label = "result", | ||
316 | .match = "fail", | ||
317 | }, | ||
318 | [ENCAP_CIPHERTEXT] = { | ||
319 | .state = ENCAP_CIPHERTEXT, | ||
320 | .type = LINE_HEX, | ||
321 | .name = "ciphertext", | ||
322 | .label = "ciphertext", | ||
323 | }, | ||
324 | [ENCAP_SHARED_SECRET] = { | ||
325 | .state = ENCAP_SHARED_SECRET, | ||
326 | .type = LINE_HEX, | ||
327 | .name = "shared secret", | ||
328 | .label = "shared_secret", | ||
329 | }, | ||
330 | }; | ||
331 | |||
332 | static int | ||
333 | encap_init(void *ctx, void *parse_ctx) | ||
334 | { | ||
335 | struct encap_ctx *encap = ctx; | ||
336 | |||
337 | encap->parse_ctx = parse_ctx; | ||
338 | |||
339 | return 1; | ||
340 | } | ||
341 | |||
342 | static void | ||
343 | encap_finish(void *ctx) | ||
344 | { | ||
345 | (void)ctx; | ||
346 | } | ||
347 | |||
348 | static int | ||
349 | MlkemEncapFileTest(struct encap_ctx *encap) | ||
350 | { | ||
351 | struct parse *p = encap->parse_ctx; | ||
352 | uint8_t shared_secret_buf[MLKEM_SHARED_SECRET_BYTES]; | ||
353 | CBS entropy, public_key, ciphertext, shared_secret; | ||
354 | int should_fail; | ||
355 | int failed = 1; | ||
356 | |||
357 | parse_get_cbs(p, ENCAP_ENTROPY, &entropy); | ||
358 | parse_get_cbs(p, ENCAP_PUBLIC_KEY, &public_key); | ||
359 | parse_get_cbs(p, ENCAP_CIPHERTEXT, &ciphertext); | ||
360 | parse_get_cbs(p, ENCAP_SHARED_SECRET, &shared_secret); | ||
361 | parse_get_int(p, ENCAP_RESULT, &should_fail); | ||
362 | |||
363 | if (!encap->parse_public_key(encap->public_key, &public_key)) { | ||
364 | if ((failed = !should_fail)) | ||
365 | parse_info(p, "parse public key"); | ||
366 | goto err; | ||
367 | } | ||
368 | encap->encap_external_entropy(encap->ciphertext, shared_secret_buf, | ||
369 | encap->public_key, CBS_data(&entropy)); | ||
370 | |||
371 | failed = !parse_data_equal(p, "shared_secret", &shared_secret, | ||
372 | shared_secret_buf, sizeof(shared_secret_buf)); | ||
373 | failed |= !parse_data_equal(p, "ciphertext", &ciphertext, | ||
374 | encap->ciphertext, encap->ciphertext_len); | ||
375 | |||
376 | if (should_fail != failed) { | ||
377 | parse_info(p, "FAIL: should_fail %d, failed %d", | ||
378 | should_fail, failed); | ||
379 | failed = 1; | ||
380 | } | ||
381 | |||
382 | err: | ||
383 | return failed; | ||
384 | } | ||
385 | |||
386 | static int | ||
387 | encap_run_test_case(void *ctx) | ||
388 | { | ||
389 | return MlkemEncapFileTest(ctx); | ||
390 | } | ||
391 | |||
392 | static const struct test_parse encap_parse = { | ||
393 | .states = encap_state_machine, | ||
394 | .num_states = N_ENCAP_STATES, | ||
395 | |||
396 | .init = encap_init, | ||
397 | .finish = encap_finish, | ||
398 | |||
399 | .run_test_case = encap_run_test_case, | ||
400 | }; | ||
401 | |||
402 | static int | ||
403 | mlkem_encap_tests(const char *fn, size_t size) | ||
404 | { | ||
405 | struct MLKEM768_public_key public_key768; | ||
406 | uint8_t ciphertext768[MLKEM768_CIPHERTEXT_BYTES]; | ||
407 | struct encap_ctx encap768 = { | ||
408 | .public_key = &public_key768, | ||
409 | .ciphertext = ciphertext768, | ||
410 | .ciphertext_len = sizeof(ciphertext768), | ||
411 | |||
412 | .parse_public_key = mlkem768_parse_public_key, | ||
413 | .encap_external_entropy = mlkem768_encap_external_entropy, | ||
414 | }; | ||
415 | struct MLKEM1024_public_key public_key1024; | ||
416 | uint8_t ciphertext1024[MLKEM1024_CIPHERTEXT_BYTES]; | ||
417 | struct encap_ctx encap1024 = { | ||
418 | .public_key = &public_key1024, | ||
419 | .ciphertext = ciphertext1024, | ||
420 | .ciphertext_len = sizeof(ciphertext1024), | ||
421 | |||
422 | .parse_public_key = mlkem1024_parse_public_key, | ||
423 | .encap_external_entropy = mlkem1024_encap_external_entropy, | ||
424 | }; | ||
425 | |||
426 | if (size == 768) | ||
427 | return parse_test_file(fn, &encap_parse, &encap768); | ||
428 | if (size == 1024) | ||
429 | return parse_test_file(fn, &encap_parse, &encap1024); | ||
430 | |||
431 | errx(1, "unknown encap test: size %zu", size); | ||
432 | } | ||
433 | |||
434 | struct keygen_ctx { | ||
435 | struct parse *parse_ctx; | ||
436 | |||
437 | void *private_key; | ||
438 | void *encoded_public_key; | ||
439 | size_t encoded_public_key_len; | ||
440 | size_t private_key_len; | ||
441 | size_t public_key_len; | ||
442 | |||
443 | mlkem_generate_key_external_entropy_fn generate_key_external_entropy; | ||
444 | mlkem_encode_private_key_fn encode_private_key; | ||
445 | }; | ||
446 | |||
447 | enum keygen_states { | ||
448 | KEYGEN_SEED, | ||
449 | KEYGEN_PUBLIC_KEY, | ||
450 | KEYGEN_PRIVATE_KEY, | ||
451 | N_KEYGEN_STATES, | ||
452 | }; | ||
453 | |||
454 | static const struct line_spec keygen_state_machine[] = { | ||
455 | [KEYGEN_SEED] = { | ||
456 | .state = KEYGEN_SEED, | ||
457 | .type = LINE_HEX, | ||
458 | .name = "seed", | ||
459 | .label = "seed", | ||
460 | }, | ||
461 | [KEYGEN_PUBLIC_KEY] = { | ||
462 | .state = KEYGEN_PUBLIC_KEY, | ||
463 | .type = LINE_HEX, | ||
464 | .name = "public key", | ||
465 | .label = "public_key", | ||
466 | }, | ||
467 | [KEYGEN_PRIVATE_KEY] = { | ||
468 | .state = KEYGEN_PRIVATE_KEY, | ||
469 | .type = LINE_HEX, | ||
470 | .name = "private key", | ||
471 | .label = "private_key", | ||
472 | }, | ||
473 | }; | ||
474 | |||
475 | static int | ||
476 | keygen_init(void *ctx, void *parse_ctx) | ||
477 | { | ||
478 | struct keygen_ctx *keygen = ctx; | ||
479 | |||
480 | keygen->parse_ctx = parse_ctx; | ||
481 | |||
482 | return 1; | ||
483 | } | ||
484 | |||
485 | static void | ||
486 | keygen_finish(void *ctx) | ||
487 | { | ||
488 | (void)ctx; | ||
489 | } | ||
490 | |||
491 | static int | ||
492 | MlkemKeygenFileTest(struct keygen_ctx *keygen) | ||
493 | { | ||
494 | struct parse *p = keygen->parse_ctx; | ||
495 | CBS seed, public_key, private_key; | ||
496 | uint8_t *encoded_private_key = NULL; | ||
497 | size_t encoded_private_key_len = 0; | ||
498 | int failed = 1; | ||
499 | |||
500 | parse_get_cbs(p, KEYGEN_SEED, &seed); | ||
501 | parse_get_cbs(p, KEYGEN_PUBLIC_KEY, &public_key); | ||
502 | parse_get_cbs(p, KEYGEN_PRIVATE_KEY, &private_key); | ||
503 | |||
504 | if (!parse_length_equal(p, "seed", MLKEM_SEED_BYTES, CBS_len(&seed))) | ||
505 | goto err; | ||
506 | if (!parse_length_equal(p, "public key", | ||
507 | keygen->public_key_len, CBS_len(&public_key))) | ||
508 | goto err; | ||
509 | if (!parse_length_equal(p, "private key", | ||
510 | keygen->private_key_len, CBS_len(&private_key))) | ||
511 | goto err; | ||
512 | |||
513 | keygen->generate_key_external_entropy(keygen->encoded_public_key, | ||
514 | keygen->private_key, CBS_data(&seed)); | ||
515 | if (!keygen->encode_private_key(keygen->private_key, | ||
516 | &encoded_private_key, &encoded_private_key_len)) { | ||
517 | parse_info(p, "encode private key"); | ||
518 | goto err; | ||
519 | } | ||
520 | |||
521 | failed = !parse_data_equal(p, "private key", &private_key, | ||
522 | encoded_private_key, encoded_private_key_len); | ||
523 | failed |= !parse_data_equal(p, "public key", &public_key, | ||
524 | keygen->encoded_public_key, keygen->encoded_public_key_len); | ||
525 | |||
526 | err: | ||
527 | freezero(encoded_private_key, encoded_private_key_len); | ||
528 | |||
529 | return failed; | ||
530 | } | ||
531 | |||
532 | static int | ||
533 | keygen_run_test_case(void *ctx) | ||
534 | { | ||
535 | return MlkemKeygenFileTest(ctx); | ||
536 | } | ||
537 | |||
538 | static const struct test_parse keygen_parse = { | ||
539 | .states = keygen_state_machine, | ||
540 | .num_states = N_KEYGEN_STATES, | ||
541 | |||
542 | .init = keygen_init, | ||
543 | .finish = keygen_finish, | ||
544 | |||
545 | .run_test_case = keygen_run_test_case, | ||
546 | }; | ||
547 | |||
548 | enum nist_keygen_states { | ||
549 | NIST_KEYGEN_Z, | ||
550 | NIST_KEYGEN_D, | ||
551 | NIST_KEYGEN_EK, | ||
552 | NIST_KEYGEN_DK, | ||
553 | N_NIST_KEYGEN_STATES, | ||
554 | }; | ||
555 | |||
556 | static const struct line_spec nist_keygen_state_machine[] = { | ||
557 | [NIST_KEYGEN_Z] = { | ||
558 | .state = NIST_KEYGEN_Z, | ||
559 | .type = LINE_HEX, | ||
560 | .name = "seed (z)", | ||
561 | .label = "z", | ||
562 | }, | ||
563 | [NIST_KEYGEN_D] = { | ||
564 | .state = NIST_KEYGEN_D, | ||
565 | .type = LINE_HEX, | ||
566 | .name = "seed (d)", | ||
567 | .label = "d", | ||
568 | }, | ||
569 | [NIST_KEYGEN_EK] = { | ||
570 | .state = NIST_KEYGEN_EK, | ||
571 | .type = LINE_HEX, | ||
572 | .name = "public key (ek)", | ||
573 | .label = "ek", | ||
574 | }, | ||
575 | [NIST_KEYGEN_DK] = { | ||
576 | .state = NIST_KEYGEN_DK, | ||
577 | .type = LINE_HEX, | ||
578 | .name = "private key (dk)", | ||
579 | .label = "dk", | ||
580 | }, | ||
581 | }; | ||
582 | |||
583 | static int | ||
584 | MlkemNistKeygenFileTest(struct keygen_ctx *keygen) | ||
585 | { | ||
586 | struct parse *p = keygen->parse_ctx; | ||
587 | CBB seed_cbb; | ||
588 | CBS z, d, ek, dk; | ||
589 | uint8_t seed[MLKEM_SEED_BYTES]; | ||
590 | size_t seed_len; | ||
591 | uint8_t *encoded_private_key = NULL; | ||
592 | size_t encoded_private_key_len = 0; | ||
593 | int failed = 1; | ||
594 | |||
595 | parse_get_cbs(p, NIST_KEYGEN_Z, &z); | ||
596 | parse_get_cbs(p, NIST_KEYGEN_D, &d); | ||
597 | parse_get_cbs(p, NIST_KEYGEN_EK, &ek); | ||
598 | parse_get_cbs(p, NIST_KEYGEN_DK, &dk); | ||
599 | |||
600 | if (!CBB_init_fixed(&seed_cbb, seed, sizeof(seed))) | ||
601 | parse_errx(p, "CBB_init_fixed"); | ||
602 | if (!CBB_add_bytes(&seed_cbb, CBS_data(&d), CBS_len(&d))) | ||
603 | parse_errx(p, "CBB_add_bytes"); | ||
604 | if (!CBB_add_bytes(&seed_cbb, CBS_data(&z), CBS_len(&z))) | ||
605 | parse_errx(p, "CBB_add_bytes"); | ||
606 | if (!CBB_finish(&seed_cbb, NULL, &seed_len)) | ||
607 | parse_errx(p, "CBB_finish"); | ||
608 | |||
609 | if (!parse_length_equal(p, "bogus z or d", MLKEM_SEED_BYTES, seed_len)) | ||
610 | goto err; | ||
611 | |||
612 | keygen->generate_key_external_entropy(keygen->encoded_public_key, | ||
613 | keygen->private_key, seed); | ||
614 | if (!keygen->encode_private_key(keygen->private_key, | ||
615 | &encoded_private_key, &encoded_private_key_len)) { | ||
616 | parse_info(p, "encode private key"); | ||
617 | goto err; | ||
618 | } | ||
619 | |||
620 | failed = !parse_data_equal(p, "public key", &ek, | ||
621 | keygen->encoded_public_key, keygen->encoded_public_key_len); | ||
622 | failed |= !parse_data_equal(p, "private key", &dk, | ||
623 | encoded_private_key, encoded_private_key_len); | ||
624 | |||
625 | err: | ||
626 | freezero(encoded_private_key, encoded_private_key_len); | ||
627 | |||
628 | return failed; | ||
629 | } | ||
630 | |||
631 | static int | ||
632 | nist_keygen_run_test_case(void *ctx) | ||
633 | { | ||
634 | return MlkemNistKeygenFileTest(ctx); | ||
635 | } | ||
636 | |||
637 | static const struct test_parse nist_keygen_parse = { | ||
638 | .states = nist_keygen_state_machine, | ||
639 | .num_states = N_NIST_KEYGEN_STATES, | ||
640 | |||
641 | .init = keygen_init, | ||
642 | .finish = keygen_finish, | ||
643 | |||
644 | .run_test_case = nist_keygen_run_test_case, | ||
645 | }; | ||
646 | |||
647 | static int | ||
648 | mlkem_keygen_tests(const char *fn, size_t size, enum test_type test_type) | ||
649 | { | ||
650 | struct MLKEM768_private_key private_key768; | ||
651 | uint8_t encoded_public_key768[MLKEM768_PUBLIC_KEY_BYTES]; | ||
652 | struct keygen_ctx keygen768 = { | ||
653 | .private_key = &private_key768, | ||
654 | .encoded_public_key = encoded_public_key768, | ||
655 | .encoded_public_key_len = sizeof(encoded_public_key768), | ||
656 | .private_key_len = MLKEM768_PRIVATE_KEY_BYTES, | ||
657 | .public_key_len = MLKEM768_PUBLIC_KEY_BYTES, | ||
658 | .generate_key_external_entropy = | ||
659 | mlkem768_generate_key_external_entropy, | ||
660 | .encode_private_key = | ||
661 | mlkem768_encode_private_key, | ||
662 | }; | ||
663 | struct MLKEM1024_private_key private_key1024; | ||
664 | uint8_t encoded_public_key1024[MLKEM1024_PUBLIC_KEY_BYTES]; | ||
665 | struct keygen_ctx keygen1024 = { | ||
666 | .private_key = &private_key1024, | ||
667 | .encoded_public_key = encoded_public_key1024, | ||
668 | .encoded_public_key_len = sizeof(encoded_public_key1024), | ||
669 | .private_key_len = MLKEM1024_PRIVATE_KEY_BYTES, | ||
670 | .public_key_len = MLKEM1024_PUBLIC_KEY_BYTES, | ||
671 | |||
672 | .generate_key_external_entropy = | ||
673 | mlkem1024_generate_key_external_entropy, | ||
674 | .encode_private_key = | ||
675 | mlkem1024_encode_private_key, | ||
676 | }; | ||
677 | |||
678 | if (size == 768 && test_type == TEST_TYPE_NORMAL) | ||
679 | return parse_test_file(fn, &keygen_parse, &keygen768); | ||
680 | if (size == 768 && test_type == TEST_TYPE_NIST) | ||
681 | return parse_test_file(fn, &nist_keygen_parse, &keygen768); | ||
682 | if (size == 1024 && test_type == TEST_TYPE_NORMAL) | ||
683 | return parse_test_file(fn, &keygen_parse, &keygen1024); | ||
684 | if (size == 1024 && test_type == TEST_TYPE_NIST) | ||
685 | return parse_test_file(fn, &nist_keygen_parse, &keygen1024); | ||
686 | |||
687 | errx(1, "unknown keygen test: size %zu, type %d", size, test_type); | ||
688 | } | ||
689 | |||
690 | static int | ||
691 | run_mlkem_test(const char *test, const char *fn) | ||
692 | { | ||
693 | if (strcmp(test, "mlkem768_decap_tests") == 0) | ||
694 | return mlkem_decap_tests(fn, 768, TEST_TYPE_NORMAL); | ||
695 | if (strcmp(test, "mlkem768_nist_decap_tests") == 0) | ||
696 | return mlkem_decap_tests(fn, 768, TEST_TYPE_NIST); | ||
697 | if (strcmp(test, "mlkem1024_decap_tests") == 0) | ||
698 | return mlkem_decap_tests(fn, 1024, TEST_TYPE_NORMAL); | ||
699 | if (strcmp(test, "mlkem1024_nist_decap_tests") == 0) | ||
700 | return mlkem_decap_tests(fn, 1024, TEST_TYPE_NIST); | ||
701 | |||
702 | if (strcmp(test, "mlkem768_encap_tests") == 0) | ||
703 | return mlkem_encap_tests(fn, 768); | ||
704 | if (strcmp(test, "mlkem1024_encap_tests") == 0) | ||
705 | return mlkem_encap_tests(fn, 1024); | ||
706 | |||
707 | if (strcmp(test, "mlkem768_keygen_tests") == 0) | ||
708 | return mlkem_keygen_tests(fn, 768, TEST_TYPE_NORMAL); | ||
709 | if (strcmp(test, "mlkem768_nist_keygen_tests") == 0) | ||
710 | return mlkem_keygen_tests(fn, 768, TEST_TYPE_NIST); | ||
711 | if (strcmp(test, "mlkem1024_keygen_tests") == 0) | ||
712 | return mlkem_keygen_tests(fn, 1024, TEST_TYPE_NORMAL); | ||
713 | if (strcmp(test, "mlkem1024_nist_keygen_tests") == 0) | ||
714 | return mlkem_keygen_tests(fn, 1024, TEST_TYPE_NIST); | ||
715 | |||
716 | errx(1, "unknown test %s (test file %s)", test, fn); | ||
717 | } | ||
718 | |||
719 | int | ||
720 | main(int argc, const char *argv[]) | ||
721 | { | ||
722 | if (argc != 3) { | ||
723 | fprintf(stderr, "usage: mlkem_test test testfile.txt\n"); | ||
724 | exit(1); | ||
725 | } | ||
726 | |||
727 | return run_mlkem_test(argv[1], argv[2]); | ||
728 | } | ||
diff --git a/src/regress/lib/libcrypto/mlkem/mlkem_tests_util.c b/src/regress/lib/libcrypto/mlkem/mlkem_tests_util.c index 6287849e3b..1bb2ed3a8b 100644 --- a/src/regress/lib/libcrypto/mlkem/mlkem_tests_util.c +++ b/src/regress/lib/libcrypto/mlkem/mlkem_tests_util.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: mlkem_tests_util.c,v 1.4 2024/12/20 15:47:26 tb Exp $ */ | 1 | /* $OpenBSD: mlkem_tests_util.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> |
@@ -45,13 +45,12 @@ hexdump(const uint8_t *buf, size_t len, const uint8_t *compare) | |||
45 | } | 45 | } |
46 | 46 | ||
47 | int | 47 | int |
48 | compare_data(const uint8_t *want, const uint8_t *got, size_t len, size_t line, | 48 | compare_data(const uint8_t *want, const uint8_t *got, size_t len, const char *msg) |
49 | const char *msg) | ||
50 | { | 49 | { |
51 | if (memcmp(want, got, len) == 0) | 50 | if (memcmp(want, got, len) == 0) |
52 | return 0; | 51 | return 0; |
53 | 52 | ||
54 | warnx("FAIL: #%zu - %s differs", line, msg); | 53 | warnx("FAIL: %s differs", msg); |
55 | fprintf(stderr, "want:\n"); | 54 | fprintf(stderr, "want:\n"); |
56 | hexdump(want, len, got); | 55 | hexdump(want, len, got); |
57 | fprintf(stderr, "got:\n"); | 56 | fprintf(stderr, "got:\n"); |
@@ -62,80 +61,15 @@ compare_data(const uint8_t *want, const uint8_t *got, size_t len, size_t line, | |||
62 | } | 61 | } |
63 | 62 | ||
64 | int | 63 | int |
65 | compare_length(size_t want, size_t got, size_t line, const char *msg) | 64 | mlkem768_encode_private_key(const void *private_key, uint8_t **out_buf, |
66 | { | 65 | size_t *out_len) |
67 | if (want == got) | ||
68 | return 1; | ||
69 | |||
70 | warnx("#%zu: %s: want %zu, got %zu", line, msg, want, got); | ||
71 | return 0; | ||
72 | } | ||
73 | |||
74 | static int | ||
75 | hex_get_nibble_cbs(CBS *cbs, uint8_t *out_nibble) | ||
76 | { | ||
77 | uint8_t c; | ||
78 | |||
79 | if (!CBS_get_u8(cbs, &c)) | ||
80 | return 0; | ||
81 | |||
82 | if (c >= '0' && c <= '9') { | ||
83 | *out_nibble = c - '0'; | ||
84 | return 1; | ||
85 | } | ||
86 | if (c >= 'a' && c <= 'f') { | ||
87 | *out_nibble = c - 'a' + 10; | ||
88 | return 1; | ||
89 | } | ||
90 | if (c >= 'A' && c <= 'F') { | ||
91 | *out_nibble = c - 'A' + 10; | ||
92 | return 1; | ||
93 | } | ||
94 | |||
95 | return 0; | ||
96 | } | ||
97 | |||
98 | void | ||
99 | hex_decode_cbs(CBS *cbs, CBB *cbb, size_t line, const char *msg) | ||
100 | { | ||
101 | if (!CBB_init(cbb, 0)) | ||
102 | errx(1, "#%zu %s: %s CBB_init", line, msg, __func__); | ||
103 | |||
104 | while (CBS_len(cbs) > 0) { | ||
105 | uint8_t hi, lo; | ||
106 | |||
107 | if (!hex_get_nibble_cbs(cbs, &hi)) | ||
108 | errx(1, "#%zu %s: %s nibble", line, msg, __func__); | ||
109 | if (!hex_get_nibble_cbs(cbs, &lo)) | ||
110 | errx(1, "#%zu %s: %s nibble", line, msg, __func__); | ||
111 | |||
112 | if (!CBB_add_u8(cbb, hi << 4 | lo)) | ||
113 | errx(1, "#%zu %s: %s CBB_add_u8", line, msg, __func__); | ||
114 | } | ||
115 | } | ||
116 | |||
117 | int | ||
118 | get_string_cbs(CBS *cbs_in, const char *str, size_t line, const char *msg) | ||
119 | { | ||
120 | CBS cbs; | ||
121 | size_t len = strlen(str); | ||
122 | |||
123 | if (!CBS_get_bytes(cbs_in, &cbs, len)) | ||
124 | errx(1, "#%zu %s: %s CBB_get_bytes", line, msg, __func__); | ||
125 | |||
126 | return CBS_mem_equal(&cbs, str, len); | ||
127 | } | ||
128 | |||
129 | int | ||
130 | mlkem768_encode_private_key(const struct MLKEM768_private_key *priv, | ||
131 | uint8_t **out_buf, size_t *out_len) | ||
132 | { | 66 | { |
133 | CBB cbb; | 67 | CBB cbb; |
134 | int ret = 0; | 68 | int ret = 0; |
135 | 69 | ||
136 | if (!CBB_init(&cbb, MLKEM768_PUBLIC_KEY_BYTES)) | 70 | if (!CBB_init(&cbb, MLKEM768_PUBLIC_KEY_BYTES)) |
137 | goto err; | 71 | goto err; |
138 | if (!MLKEM768_marshal_private_key(&cbb, priv)) | 72 | if (!MLKEM768_marshal_private_key(&cbb, private_key)) |
139 | goto err; | 73 | goto err; |
140 | if (!CBB_finish(&cbb, out_buf, out_len)) | 74 | if (!CBB_finish(&cbb, out_buf, out_len)) |
141 | goto err; | 75 | goto err; |
@@ -149,15 +83,15 @@ mlkem768_encode_private_key(const struct MLKEM768_private_key *priv, | |||
149 | } | 83 | } |
150 | 84 | ||
151 | int | 85 | int |
152 | mlkem768_encode_public_key(const struct MLKEM768_public_key *pub, | 86 | mlkem768_encode_public_key(const void *public_key, uint8_t **out_buf, |
153 | uint8_t **out_buf, size_t *out_len) | 87 | size_t *out_len) |
154 | { | 88 | { |
155 | CBB cbb; | 89 | CBB cbb; |
156 | int ret = 0; | 90 | int ret = 0; |
157 | 91 | ||
158 | if (!CBB_init(&cbb, MLKEM768_PUBLIC_KEY_BYTES)) | 92 | if (!CBB_init(&cbb, MLKEM768_PUBLIC_KEY_BYTES)) |
159 | goto err; | 93 | goto err; |
160 | if (!MLKEM768_marshal_public_key(&cbb, pub)) | 94 | if (!MLKEM768_marshal_public_key(&cbb, public_key)) |
161 | goto err; | 95 | goto err; |
162 | if (!CBB_finish(&cbb, out_buf, out_len)) | 96 | if (!CBB_finish(&cbb, out_buf, out_len)) |
163 | goto err; | 97 | goto err; |
@@ -171,15 +105,15 @@ mlkem768_encode_public_key(const struct MLKEM768_public_key *pub, | |||
171 | } | 105 | } |
172 | 106 | ||
173 | int | 107 | int |
174 | mlkem1024_encode_private_key(const struct MLKEM1024_private_key *priv, | 108 | mlkem1024_encode_private_key(const void *private_key, uint8_t **out_buf, |
175 | uint8_t **out_buf, size_t *out_len) | 109 | size_t *out_len) |
176 | { | 110 | { |
177 | CBB cbb; | 111 | CBB cbb; |
178 | int ret = 0; | 112 | int ret = 0; |
179 | 113 | ||
180 | if (!CBB_init(&cbb, MLKEM1024_PUBLIC_KEY_BYTES)) | 114 | if (!CBB_init(&cbb, MLKEM1024_PUBLIC_KEY_BYTES)) |
181 | goto err; | 115 | goto err; |
182 | if (!MLKEM1024_marshal_private_key(&cbb, priv)) | 116 | if (!MLKEM1024_marshal_private_key(&cbb, private_key)) |
183 | goto err; | 117 | goto err; |
184 | if (!CBB_finish(&cbb, out_buf, out_len)) | 118 | if (!CBB_finish(&cbb, out_buf, out_len)) |
185 | goto err; | 119 | goto err; |
@@ -193,15 +127,15 @@ mlkem1024_encode_private_key(const struct MLKEM1024_private_key *priv, | |||
193 | } | 127 | } |
194 | 128 | ||
195 | int | 129 | int |
196 | mlkem1024_encode_public_key(const struct MLKEM1024_public_key *pub, | 130 | mlkem1024_encode_public_key(const void *public_key, uint8_t **out_buf, |
197 | uint8_t **out_buf, size_t *out_len) | 131 | size_t *out_len) |
198 | { | 132 | { |
199 | CBB cbb; | 133 | CBB cbb; |
200 | int ret = 0; | 134 | int ret = 0; |
201 | 135 | ||
202 | if (!CBB_init(&cbb, MLKEM1024_PUBLIC_KEY_BYTES)) | 136 | if (!CBB_init(&cbb, MLKEM1024_PUBLIC_KEY_BYTES)) |
203 | goto err; | 137 | goto err; |
204 | if (!MLKEM1024_marshal_public_key(&cbb, pub)) | 138 | if (!MLKEM1024_marshal_public_key(&cbb, public_key)) |
205 | goto err; | 139 | goto err; |
206 | if (!CBB_finish(&cbb, out_buf, out_len)) | 140 | if (!CBB_finish(&cbb, out_buf, out_len)) |
207 | goto err; | 141 | goto err; |
@@ -213,3 +147,121 @@ mlkem1024_encode_public_key(const struct MLKEM1024_public_key *pub, | |||
213 | 147 | ||
214 | return ret; | 148 | return ret; |
215 | } | 149 | } |
150 | |||
151 | int | ||
152 | mlkem768_decap(uint8_t out_shared_secret[MLKEM_SHARED_SECRET_BYTES], | ||
153 | const uint8_t *ciphertext, size_t ciphertext_len, const void *private_key) | ||
154 | { | ||
155 | return MLKEM768_decap(out_shared_secret, ciphertext, ciphertext_len, | ||
156 | private_key); | ||
157 | } | ||
158 | |||
159 | void | ||
160 | mlkem768_encap(uint8_t *out_ciphertext, | ||
161 | uint8_t out_shared_secret[MLKEM_SHARED_SECRET_BYTES], | ||
162 | const void *public_key) | ||
163 | { | ||
164 | MLKEM768_encap(out_ciphertext, out_shared_secret, public_key); | ||
165 | } | ||
166 | |||
167 | void | ||
168 | mlkem768_encap_external_entropy(uint8_t *out_ciphertext, | ||
169 | uint8_t out_shared_secret[MLKEM_SHARED_SECRET_BYTES], | ||
170 | const void *public_key, const uint8_t entropy[MLKEM_ENCAP_ENTROPY]) | ||
171 | { | ||
172 | MLKEM768_encap_external_entropy(out_ciphertext, out_shared_secret, | ||
173 | public_key, entropy); | ||
174 | } | ||
175 | |||
176 | void | ||
177 | mlkem768_generate_key(uint8_t *out_encoded_public_key, | ||
178 | uint8_t optional_out_seed[MLKEM_SEED_BYTES], void *out_private_key) | ||
179 | { | ||
180 | MLKEM768_generate_key(out_encoded_public_key, optional_out_seed, | ||
181 | out_private_key); | ||
182 | } | ||
183 | |||
184 | void | ||
185 | mlkem768_generate_key_external_entropy(uint8_t *out_encoded_public_key, | ||
186 | void *out_private_key, const uint8_t entropy[MLKEM_SEED_BYTES]) | ||
187 | { | ||
188 | MLKEM768_generate_key_external_entropy(out_encoded_public_key, | ||
189 | out_private_key, entropy); | ||
190 | } | ||
191 | |||
192 | int | ||
193 | mlkem768_parse_private_key(void *out_private_key, CBS *private_key_cbs) | ||
194 | { | ||
195 | return MLKEM768_parse_private_key(out_private_key, private_key_cbs); | ||
196 | } | ||
197 | |||
198 | int | ||
199 | mlkem768_parse_public_key(void *out_public_key, CBS *public_key_cbs) | ||
200 | { | ||
201 | return MLKEM768_parse_public_key(out_public_key, public_key_cbs); | ||
202 | } | ||
203 | |||
204 | void | ||
205 | mlkem768_public_from_private(void *out_public_key, const void *private_key) | ||
206 | { | ||
207 | MLKEM768_public_from_private(out_public_key, private_key); | ||
208 | } | ||
209 | |||
210 | int | ||
211 | mlkem1024_decap(uint8_t out_shared_secret[MLKEM_SHARED_SECRET_BYTES], | ||
212 | const uint8_t *ciphertext, size_t ciphertext_len, const void *private_key) | ||
213 | { | ||
214 | return MLKEM1024_decap(out_shared_secret, ciphertext, ciphertext_len, | ||
215 | private_key); | ||
216 | } | ||
217 | |||
218 | void | ||
219 | mlkem1024_encap(uint8_t *out_ciphertext, | ||
220 | uint8_t out_shared_secret[MLKEM_SHARED_SECRET_BYTES], | ||
221 | const void *public_key) | ||
222 | { | ||
223 | MLKEM1024_encap(out_ciphertext, out_shared_secret, public_key); | ||
224 | } | ||
225 | |||
226 | void | ||
227 | mlkem1024_encap_external_entropy(uint8_t *out_ciphertext, | ||
228 | uint8_t out_shared_secret[MLKEM_SHARED_SECRET_BYTES], | ||
229 | const void *public_key, const uint8_t entropy[MLKEM_ENCAP_ENTROPY]) | ||
230 | { | ||
231 | MLKEM1024_encap_external_entropy(out_ciphertext, out_shared_secret, | ||
232 | public_key, entropy); | ||
233 | } | ||
234 | |||
235 | void | ||
236 | mlkem1024_generate_key(uint8_t *out_encoded_public_key, | ||
237 | uint8_t optional_out_seed[MLKEM_SEED_BYTES], void *out_private_key) | ||
238 | { | ||
239 | MLKEM1024_generate_key(out_encoded_public_key, optional_out_seed, | ||
240 | out_private_key); | ||
241 | } | ||
242 | |||
243 | void | ||
244 | mlkem1024_generate_key_external_entropy(uint8_t *out_encoded_public_key, | ||
245 | void *out_private_key, const uint8_t entropy[MLKEM_SEED_BYTES]) | ||
246 | { | ||
247 | MLKEM1024_generate_key_external_entropy(out_encoded_public_key, | ||
248 | out_private_key, entropy); | ||
249 | } | ||
250 | |||
251 | int | ||
252 | mlkem1024_parse_private_key(void *out_private_key, CBS *private_key_cbs) | ||
253 | { | ||
254 | return MLKEM1024_parse_private_key(out_private_key, private_key_cbs); | ||
255 | } | ||
256 | |||
257 | void | ||
258 | mlkem1024_public_from_private(void *out_public_key, const void *private_key) | ||
259 | { | ||
260 | MLKEM1024_public_from_private(out_public_key, private_key); | ||
261 | } | ||
262 | |||
263 | int | ||
264 | mlkem1024_parse_public_key(void *out_public_key, CBS *public_key_cbs) | ||
265 | { | ||
266 | return MLKEM1024_parse_public_key(out_public_key, public_key_cbs); | ||
267 | } | ||
diff --git a/src/regress/lib/libcrypto/mlkem/mlkem_tests_util.h b/src/regress/lib/libcrypto/mlkem/mlkem_tests_util.h index cbb0f83f8c..7fbe6f76a9 100644 --- a/src/regress/lib/libcrypto/mlkem/mlkem_tests_util.h +++ b/src/regress/lib/libcrypto/mlkem/mlkem_tests_util.h | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: mlkem_tests_util.h,v 1.3 2024/12/20 00:07:12 tb Exp $ */ | 1 | /* $OpenBSD: mlkem_tests_util.h,v 1.4 2024/12/26 00:04:24 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 | * Copyright (c) 2024 Theo Buehler <tb@openbsd.org> |
@@ -24,26 +24,66 @@ | |||
24 | 24 | ||
25 | #include "bytestring.h" | 25 | #include "bytestring.h" |
26 | 26 | ||
27 | struct MLKEM1024_private_key; | 27 | #include "mlkem.h" |
28 | struct MLKEM1024_public_key; | 28 | #include "mlkem_internal.h" |
29 | struct MLKEM768_private_key; | ||
30 | struct MLKEM768_public_key; | ||
31 | 29 | ||
32 | /* XXX - return values of the two compare functions are inconsistent */ | ||
33 | int compare_data(const uint8_t *want, const uint8_t *got, size_t len, | 30 | int compare_data(const uint8_t *want, const uint8_t *got, size_t len, |
34 | size_t line, const char *msg); | 31 | const char *msg); |
35 | int compare_length(size_t want, size_t got, size_t line, const char *msg); | 32 | |
36 | 33 | int mlkem768_encode_private_key(const void *priv, uint8_t **out_buf, | |
37 | void hex_decode_cbs(CBS *cbs, CBB *cbb, size_t line, const char *msg); | 34 | size_t *out_len); |
38 | int get_string_cbs(CBS *cbs, const char *str, size_t line, const char *msg); | 35 | int mlkem768_encode_public_key(const void *pub, uint8_t **out_buf, |
39 | 36 | size_t *out_len); | |
40 | int mlkem768_encode_private_key(const struct MLKEM768_private_key *priv, | 37 | int mlkem1024_encode_private_key(const void *priv, uint8_t **out_buf, |
41 | uint8_t **out_buf, size_t *out_len); | 38 | size_t *out_len); |
42 | int mlkem768_encode_public_key(const struct MLKEM768_public_key *pub, | 39 | int mlkem1024_encode_public_key(const void *pub, uint8_t **out_buf, |
43 | uint8_t **out_buf, size_t *out_len); | 40 | size_t *out_len); |
44 | int mlkem1024_encode_private_key(const struct MLKEM1024_private_key *priv, | 41 | |
45 | uint8_t **out_buf, size_t *out_len); | 42 | int mlkem768_decap(uint8_t out_shared_secret[MLKEM_SHARED_SECRET_BYTES], |
46 | int mlkem1024_encode_public_key(const struct MLKEM1024_public_key *pub, | 43 | const uint8_t *ciphertext, size_t ciphertext_len, const void *priv); |
47 | uint8_t **out_buf, size_t *out_len); | 44 | void mlkem768_encap(uint8_t *out_ciphertext, |
45 | uint8_t out_shared_secret[MLKEM_SHARED_SECRET_BYTES], const void *pub); | ||
46 | void mlkem768_encap_external_entropy(uint8_t *out_ciphertext, | ||
47 | uint8_t out_shared_secret[MLKEM_SHARED_SECRET_BYTES], const void *pub, | ||
48 | const uint8_t entropy[MLKEM_ENCAP_ENTROPY]); | ||
49 | void mlkem768_generate_key(uint8_t *out_encoded_public_key, | ||
50 | uint8_t optional_out_seed[MLKEM_SEED_BYTES], void *out_private_key); | ||
51 | void mlkem768_generate_key_external_entropy(uint8_t *out_encoded_public_key, | ||
52 | void *out_private_key, const uint8_t entropy[MLKEM_SEED_BYTES]); | ||
53 | int mlkem768_parse_private_key(void *priv, CBS *private_key_cbs); | ||
54 | int mlkem768_parse_public_key(void *pub, CBS *in); | ||
55 | void mlkem768_public_from_private(void *out_public_key, const void *private_key); | ||
56 | |||
57 | int mlkem1024_decap(uint8_t out_shared_secret[MLKEM_SHARED_SECRET_BYTES], | ||
58 | const uint8_t *ciphertext, size_t ciphertext_len, const void *priv); | ||
59 | void mlkem1024_encap(uint8_t *out_ciphertext, | ||
60 | uint8_t out_shared_secret[MLKEM_SHARED_SECRET_BYTES], const void *pub); | ||
61 | void mlkem1024_encap_external_entropy(uint8_t *out_ciphertext, | ||
62 | uint8_t out_shared_secret[MLKEM_SHARED_SECRET_BYTES], const void *pub, | ||
63 | const uint8_t entropy[MLKEM_ENCAP_ENTROPY]); | ||
64 | void mlkem1024_generate_key(uint8_t *out_encoded_public_key, | ||
65 | uint8_t optional_out_seed[MLKEM_SEED_BYTES], void *out_private_key); | ||
66 | void mlkem1024_generate_key_external_entropy(uint8_t *out_encoded_public_key, | ||
67 | void *out_private_key, const uint8_t entropy[MLKEM_SEED_BYTES]); | ||
68 | int mlkem1024_parse_private_key(void *priv, CBS *private_key_cbs); | ||
69 | int mlkem1024_parse_public_key(void *pub, CBS *in); | ||
70 | void mlkem1024_public_from_private(void *out_public_key, const void *private_key); | ||
71 | |||
72 | typedef int (*mlkem_encode_private_key_fn)(const void *, uint8_t **, size_t *); | ||
73 | typedef int (*mlkem_encode_public_key_fn)(const void *, uint8_t **, size_t *); | ||
74 | typedef int (*mlkem_decap_fn)(uint8_t [MLKEM_SHARED_SECRET_BYTES], | ||
75 | const uint8_t *, size_t, const void *); | ||
76 | typedef void (*mlkem_encap_fn)(uint8_t *, uint8_t [MLKEM_SHARED_SECRET_BYTES], | ||
77 | const void *); | ||
78 | typedef void (*mlkem_encap_external_entropy_fn)(uint8_t *, | ||
79 | uint8_t [MLKEM_SHARED_SECRET_BYTES], const void *, | ||
80 | const uint8_t [MLKEM_ENCAP_ENTROPY]); | ||
81 | typedef void (*mlkem_generate_key_fn)(uint8_t *, uint8_t *, void *); | ||
82 | typedef void (*mlkem_generate_key_external_entropy_fn)(uint8_t *, void *, | ||
83 | const uint8_t [MLKEM_SEED_BYTES]); | ||
84 | typedef int (*mlkem_parse_private_key_fn)(void *, CBS *); | ||
85 | typedef int (*mlkem_parse_public_key_fn)(void *, CBS *); | ||
86 | typedef void (*mlkem_public_from_private_fn)(void *out_public_key, | ||
87 | const void *private_key); | ||
48 | 88 | ||
49 | #endif /* MLKEM_TEST_UTIL_H */ | 89 | #endif /* MLKEM_TEST_UTIL_H */ |
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 | ||
30 | struct 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 | |||
30 | static int | 49 | static int |
31 | MlKem768UnitTest(void) | 50 | MlKemUnitTest(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 | |||
170 | static int | ||
171 | MlKem1024UnitTest(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 | ||
310 | int | 185 | int |
311 | main(int argc, char **argv) | 186 | main(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 | } |
diff --git a/src/regress/lib/libcrypto/mlkem/parse_test_file.c b/src/regress/lib/libcrypto/mlkem/parse_test_file.c new file mode 100644 index 0000000000..d79fa3dfd5 --- /dev/null +++ b/src/regress/lib/libcrypto/mlkem/parse_test_file.c | |||
@@ -0,0 +1,752 @@ | |||
1 | /* $OpenBSD: parse_test_file.c,v 1.1 2024/12/26 00:04:24 tb Exp $ */ | ||
2 | |||
3 | /* | ||
4 | * Copyright (c) 2024 Theo Buehler <tb@openbsd.org> | ||
5 | * | ||
6 | * Permission to use, copy, modify, and distribute this software for any | ||
7 | * purpose with or without fee is hereby granted, provided that the above | ||
8 | * copyright notice and this permission notice appear in all copies. | ||
9 | * | ||
10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||
11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | ||
12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | ||
13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||
14 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | ||
15 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | ||
16 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
17 | */ | ||
18 | |||
19 | #include <sys/types.h> | ||
20 | |||
21 | #include <assert.h> | ||
22 | #include <err.h> | ||
23 | #include <stdarg.h> | ||
24 | #include <stdint.h> | ||
25 | #include <stdio.h> | ||
26 | #include <stdlib.h> | ||
27 | #include <string.h> | ||
28 | |||
29 | #include "bytestring.h" | ||
30 | |||
31 | #include "parse_test_file.h" | ||
32 | |||
33 | struct line_data { | ||
34 | uint8_t *data; | ||
35 | size_t data_len; | ||
36 | CBS cbs; | ||
37 | int val; | ||
38 | }; | ||
39 | |||
40 | static struct line_data * | ||
41 | line_data_new(void) | ||
42 | { | ||
43 | return calloc(1, sizeof(struct line_data)); | ||
44 | } | ||
45 | |||
46 | static void | ||
47 | line_data_clear(struct line_data *ld) | ||
48 | { | ||
49 | freezero(ld->data, ld->data_len); | ||
50 | explicit_bzero(ld, sizeof(*ld)); | ||
51 | } | ||
52 | |||
53 | static void | ||
54 | line_data_free(struct line_data *ld) | ||
55 | { | ||
56 | if (ld == NULL) | ||
57 | return; | ||
58 | line_data_clear(ld); | ||
59 | free(ld); | ||
60 | } | ||
61 | |||
62 | static void | ||
63 | line_data_get_int(struct line_data *ld, int *out) | ||
64 | { | ||
65 | *out = ld->val; | ||
66 | } | ||
67 | |||
68 | static void | ||
69 | line_data_get_cbs(struct line_data *ld, CBS *out) | ||
70 | { | ||
71 | CBS_dup(&ld->cbs, out); | ||
72 | } | ||
73 | |||
74 | static void | ||
75 | line_data_set_int(struct line_data *ld, int val) | ||
76 | { | ||
77 | ld->val = val; | ||
78 | } | ||
79 | |||
80 | static int | ||
81 | line_data_set_from_cbb(struct line_data *ld, CBB *cbb) | ||
82 | { | ||
83 | if (!CBB_finish(cbb, &ld->data, &ld->data_len)) | ||
84 | return 0; | ||
85 | |||
86 | CBS_init(&ld->cbs, ld->data, ld->data_len); | ||
87 | |||
88 | return 1; | ||
89 | } | ||
90 | |||
91 | struct parse_state { | ||
92 | size_t line; | ||
93 | size_t test; | ||
94 | |||
95 | size_t max; | ||
96 | size_t cur; | ||
97 | struct line_data **data; | ||
98 | |||
99 | size_t instruction_max; | ||
100 | size_t instruction_cur; | ||
101 | struct line_data **instruction_data; | ||
102 | |||
103 | int running_test_case; | ||
104 | }; | ||
105 | |||
106 | static void | ||
107 | parse_state_init(struct parse_state *ps, size_t max, size_t instruction_max) | ||
108 | { | ||
109 | size_t i; | ||
110 | |||
111 | assert(max > 0); | ||
112 | |||
113 | memset(ps, 0, sizeof(*ps)); | ||
114 | ps->test = 1; | ||
115 | |||
116 | ps->max = max; | ||
117 | if ((ps->data = calloc(max, sizeof(*ps->data))) == NULL) | ||
118 | err(1, NULL); | ||
119 | for (i = 0; i < max; i++) { | ||
120 | if ((ps->data[i] = line_data_new()) == NULL) | ||
121 | err(1, NULL); | ||
122 | } | ||
123 | |||
124 | if ((ps->instruction_max = instruction_max) > 0) { | ||
125 | if ((ps->instruction_data = calloc(instruction_max, | ||
126 | sizeof(*ps->instruction_data))) == NULL) | ||
127 | err(1, NULL); | ||
128 | for (i = 0; i < instruction_max; i++) | ||
129 | if ((ps->instruction_data[i] = line_data_new()) == NULL) | ||
130 | err(1, NULL); | ||
131 | } | ||
132 | } | ||
133 | |||
134 | static void | ||
135 | parse_state_finish(struct parse_state *ps) | ||
136 | { | ||
137 | size_t i; | ||
138 | |||
139 | for (i = 0; i < ps->max; i++) | ||
140 | line_data_free(ps->data[i]); | ||
141 | free(ps->data); | ||
142 | |||
143 | for (i = 0; i < ps->instruction_max; i++) | ||
144 | line_data_free(ps->instruction_data[i]); | ||
145 | free(ps->instruction_data); | ||
146 | } | ||
147 | |||
148 | static void | ||
149 | parse_state_new_line(struct parse_state *ps) | ||
150 | { | ||
151 | ps->line++; | ||
152 | } | ||
153 | |||
154 | static void | ||
155 | parse_instruction_advance(struct parse_state *ps) | ||
156 | { | ||
157 | assert(ps->instruction_cur < ps->instruction_max); | ||
158 | ps->instruction_cur++; | ||
159 | } | ||
160 | |||
161 | static void | ||
162 | parse_state_advance(struct parse_state *ps) | ||
163 | { | ||
164 | assert(ps->cur < ps->max); | ||
165 | |||
166 | ps->cur++; | ||
167 | if ((ps->cur %= ps->max) == 0) | ||
168 | ps->test++; | ||
169 | } | ||
170 | |||
171 | struct parse { | ||
172 | struct parse_state state; | ||
173 | CBS cbs; | ||
174 | char *buf; | ||
175 | size_t buf_max; | ||
176 | const struct test_parse *tctx; | ||
177 | void *ctx; | ||
178 | |||
179 | const char *fn; | ||
180 | FILE *fp; | ||
181 | }; | ||
182 | |||
183 | static int | ||
184 | parse_instructions_parsed(struct parse *p) | ||
185 | { | ||
186 | return p->state.instruction_max == p->state.instruction_cur; | ||
187 | } | ||
188 | |||
189 | static void | ||
190 | parse_advance(struct parse *p) | ||
191 | { | ||
192 | if (!parse_instructions_parsed(p)) { | ||
193 | parse_instruction_advance(&p->state); | ||
194 | return; | ||
195 | } | ||
196 | parse_state_advance(&p->state); | ||
197 | } | ||
198 | |||
199 | static size_t | ||
200 | parse_max(struct parse *p) | ||
201 | { | ||
202 | return p->state.max; | ||
203 | } | ||
204 | |||
205 | static size_t | ||
206 | parse_instruction_max(struct parse *p) | ||
207 | { | ||
208 | return p->state.instruction_max; | ||
209 | } | ||
210 | |||
211 | static size_t | ||
212 | parse_cur(struct parse *p) | ||
213 | { | ||
214 | if (!parse_instructions_parsed(p)) { | ||
215 | assert(p->state.instruction_cur < p->state.instruction_max); | ||
216 | return p->state.instruction_cur; | ||
217 | } | ||
218 | |||
219 | assert(p->state.cur < parse_max(p)); | ||
220 | return p->state.cur; | ||
221 | } | ||
222 | |||
223 | static size_t | ||
224 | parse_must_run_test_case(struct parse *p) | ||
225 | { | ||
226 | return parse_instructions_parsed(p) && parse_max(p) - parse_cur(p) == 1; | ||
227 | } | ||
228 | |||
229 | static const struct line_spec * | ||
230 | parse_states(struct parse *p) | ||
231 | { | ||
232 | if (!parse_instructions_parsed(p)) | ||
233 | return p->tctx->instructions; | ||
234 | return p->tctx->states; | ||
235 | } | ||
236 | |||
237 | static const struct line_spec * | ||
238 | parse_instruction_states(struct parse *p) | ||
239 | { | ||
240 | return p->tctx->instructions; | ||
241 | } | ||
242 | |||
243 | static const struct line_spec * | ||
244 | parse_state(struct parse *p) | ||
245 | { | ||
246 | return &parse_states(p)[parse_cur(p)]; | ||
247 | } | ||
248 | |||
249 | static size_t | ||
250 | line(struct parse *p) | ||
251 | { | ||
252 | return p->state.line; | ||
253 | } | ||
254 | |||
255 | static size_t | ||
256 | test(struct parse *p) | ||
257 | { | ||
258 | return p->state.test; | ||
259 | } | ||
260 | |||
261 | static const char * | ||
262 | name(struct parse *p) | ||
263 | { | ||
264 | if (p->state.running_test_case) | ||
265 | return "running test case"; | ||
266 | return parse_state(p)->name; | ||
267 | } | ||
268 | |||
269 | static const char * | ||
270 | label(struct parse *p) | ||
271 | { | ||
272 | return parse_state(p)->label; | ||
273 | } | ||
274 | |||
275 | static const char * | ||
276 | match(struct parse *p) | ||
277 | { | ||
278 | return parse_state(p)->match; | ||
279 | } | ||
280 | |||
281 | static enum line | ||
282 | parse_line_type(struct parse *p) | ||
283 | { | ||
284 | return parse_state(p)->type; | ||
285 | } | ||
286 | |||
287 | static void | ||
288 | parse_vinfo(struct parse *p, const char *fmt, va_list ap) | ||
289 | { | ||
290 | fprintf(stderr, "%s:%zu test #%zu (%s): ", | ||
291 | p->fn, line(p), test(p), name(p)); | ||
292 | vfprintf(stderr, fmt, ap); | ||
293 | fprintf(stderr, "\n"); | ||
294 | } | ||
295 | |||
296 | void | ||
297 | parse_info(struct parse *p, const char *fmt, ...) | ||
298 | { | ||
299 | va_list ap; | ||
300 | |||
301 | va_start(ap, fmt); | ||
302 | parse_vinfo(p, fmt, ap); | ||
303 | va_end(ap); | ||
304 | } | ||
305 | |||
306 | void | ||
307 | parse_errx(struct parse *p, const char *fmt, ...) | ||
308 | { | ||
309 | va_list ap; | ||
310 | |||
311 | va_start(ap, fmt); | ||
312 | parse_vinfo(p, fmt, ap); | ||
313 | va_end(ap); | ||
314 | |||
315 | exit(1); | ||
316 | } | ||
317 | |||
318 | int | ||
319 | parse_length_equal(struct parse *p, const char *descr, size_t want, size_t got) | ||
320 | { | ||
321 | if (want == got) | ||
322 | return 1; | ||
323 | |||
324 | parse_info(p, "%s length: want %zu, got %zu", descr, want, got); | ||
325 | return 0; | ||
326 | } | ||
327 | |||
328 | static void | ||
329 | hexdump(const uint8_t *buf, size_t len, const uint8_t *compare) | ||
330 | { | ||
331 | const char *mark = "", *newline; | ||
332 | size_t i; | ||
333 | |||
334 | for (i = 1; i <= len; i++) { | ||
335 | if (compare != NULL) | ||
336 | mark = (buf[i - 1] != compare[i - 1]) ? "*" : " "; | ||
337 | newline = i % 8 ? "" : "\n"; | ||
338 | fprintf(stderr, " %s0x%02x,%s", mark, buf[i - 1], newline); | ||
339 | } | ||
340 | if ((len % 8) != 0) | ||
341 | fprintf(stderr, "\n"); | ||
342 | } | ||
343 | |||
344 | int | ||
345 | parse_data_equal(struct parse *p, const char *descr, CBS *want, | ||
346 | const uint8_t *got, size_t got_len) | ||
347 | { | ||
348 | if (!parse_length_equal(p, descr, CBS_len(want), got_len)) | ||
349 | return 0; | ||
350 | if (CBS_mem_equal(want, got, got_len)) | ||
351 | return 1; | ||
352 | |||
353 | parse_info(p, "%s differs", descr); | ||
354 | fprintf(stderr, "want:\n"); | ||
355 | hexdump(CBS_data(want), CBS_len(want), got); | ||
356 | fprintf(stderr, "got:\n"); | ||
357 | hexdump(got, got_len, CBS_data(want)); | ||
358 | fprintf(stderr, "\n"); | ||
359 | |||
360 | return 0; | ||
361 | } | ||
362 | |||
363 | static void | ||
364 | parse_line_data_clear(struct parse *p) | ||
365 | { | ||
366 | size_t i; | ||
367 | |||
368 | for (i = 0; i < parse_max(p); i++) | ||
369 | line_data_clear(p->state.data[i]); | ||
370 | } | ||
371 | |||
372 | static struct line_data ** | ||
373 | parse_state_data(struct parse *p) | ||
374 | { | ||
375 | if (!parse_instructions_parsed(p)) | ||
376 | return p->state.instruction_data; | ||
377 | return p->state.data; | ||
378 | } | ||
379 | |||
380 | static void | ||
381 | parse_state_set_int(struct parse *p, int val) | ||
382 | { | ||
383 | if (parse_line_type(p) != LINE_STRING_MATCH) | ||
384 | parse_errx(p, "%s: want %d, got %d", __func__, | ||
385 | LINE_STRING_MATCH, parse_line_type(p)); | ||
386 | line_data_set_int(parse_state_data(p)[parse_cur(p)], val); | ||
387 | } | ||
388 | |||
389 | static void | ||
390 | parse_state_set_from_cbb(struct parse *p, CBB *cbb) | ||
391 | { | ||
392 | if (parse_line_type(p) != LINE_HEX) | ||
393 | parse_errx(p, "%s: want %d, got %d", __func__, | ||
394 | LINE_STRING_MATCH, parse_line_type(p)); | ||
395 | if (!line_data_set_from_cbb(parse_state_data(p)[parse_cur(p)], cbb)) | ||
396 | parse_errx(p, "line_data_set_from_cbb"); | ||
397 | } | ||
398 | |||
399 | int | ||
400 | parse_get_int(struct parse *p, size_t idx, int *out) | ||
401 | { | ||
402 | assert(parse_must_run_test_case(p)); | ||
403 | assert(idx < parse_max(p)); | ||
404 | assert(parse_states(p)[idx].type == LINE_STRING_MATCH); | ||
405 | |||
406 | line_data_get_int(p->state.data[idx], out); | ||
407 | |||
408 | return 1; | ||
409 | } | ||
410 | |||
411 | int | ||
412 | parse_get_cbs(struct parse *p, size_t idx, CBS *out) | ||
413 | { | ||
414 | assert(parse_must_run_test_case(p)); | ||
415 | assert(idx < parse_max(p)); | ||
416 | assert(parse_states(p)[idx].type == LINE_HEX); | ||
417 | |||
418 | line_data_get_cbs(p->state.data[idx], out); | ||
419 | |||
420 | return 1; | ||
421 | } | ||
422 | |||
423 | int | ||
424 | parse_instruction_get_int(struct parse *p, size_t idx, int *out) | ||
425 | { | ||
426 | assert(parse_must_run_test_case(p)); | ||
427 | assert(idx < parse_instruction_max(p)); | ||
428 | assert(parse_instruction_states(p)[idx].type == LINE_STRING_MATCH); | ||
429 | |||
430 | line_data_get_int(p->state.instruction_data[idx], out); | ||
431 | |||
432 | return 1; | ||
433 | } | ||
434 | |||
435 | int | ||
436 | parse_instruction_get_cbs(struct parse *p, size_t idx, CBS *out) | ||
437 | { | ||
438 | assert(parse_must_run_test_case(p)); | ||
439 | assert(idx < parse_instruction_max(p)); | ||
440 | assert(parse_instruction_states(p)[idx].type == LINE_HEX); | ||
441 | |||
442 | line_data_get_cbs(p->state.instruction_data[idx], out); | ||
443 | |||
444 | return 1; | ||
445 | } | ||
446 | |||
447 | static int | ||
448 | CBS_peek_bytes(CBS *cbs, CBS *out, size_t len) | ||
449 | { | ||
450 | CBS dup; | ||
451 | |||
452 | CBS_dup(cbs, &dup); | ||
453 | return CBS_get_bytes(&dup, out, len); | ||
454 | } | ||
455 | |||
456 | static int | ||
457 | parse_peek_string_cbs(struct parse *p, const char *str) | ||
458 | { | ||
459 | CBS cbs; | ||
460 | size_t len = strlen(str); | ||
461 | |||
462 | if (!CBS_peek_bytes(&p->cbs, &cbs, len)) | ||
463 | parse_errx(p, "CBS_peek_data"); | ||
464 | |||
465 | return CBS_mem_equal(&cbs, (const uint8_t *)str, len); | ||
466 | } | ||
467 | |||
468 | static int | ||
469 | parse_get_string_cbs(struct parse *p, const char *str) | ||
470 | { | ||
471 | CBS cbs; | ||
472 | size_t len = strlen(str); | ||
473 | |||
474 | if (!CBS_get_bytes(&p->cbs, &cbs, len)) | ||
475 | parse_errx(p, "CBS_get_bytes"); | ||
476 | |||
477 | return CBS_mem_equal(&cbs, (const uint8_t *)str, len); | ||
478 | } | ||
479 | |||
480 | static int | ||
481 | parse_get_string_end_cbs(struct parse *p, const char *str) | ||
482 | { | ||
483 | CBS cbs; | ||
484 | int equal = 1; | ||
485 | |||
486 | CBS_init(&cbs, (const uint8_t *)str, strlen(str)); | ||
487 | |||
488 | if (CBS_len(&p->cbs) < CBS_len(&cbs)) | ||
489 | parse_errx(p, "line too short to match %s", str); | ||
490 | |||
491 | while (CBS_len(&cbs) > 0) { | ||
492 | uint8_t want, got; | ||
493 | |||
494 | if (!CBS_get_last_u8(&cbs, &want)) | ||
495 | parse_errx(p, "CBS_get_last_u8"); | ||
496 | if (!CBS_get_last_u8(&p->cbs, &got)) | ||
497 | parse_errx(p, "CBS_get_last_u8"); | ||
498 | if (want != got) | ||
499 | equal = 0; | ||
500 | } | ||
501 | |||
502 | return equal; | ||
503 | } | ||
504 | |||
505 | static void | ||
506 | parse_check_label_matches(struct parse *p) | ||
507 | { | ||
508 | const char *sep = ": "; | ||
509 | |||
510 | if (!parse_get_string_cbs(p, label(p))) | ||
511 | parse_errx(p, "label mismatch %s", label(p)); | ||
512 | |||
513 | /* Now we expect either ": " or " = ". */ | ||
514 | if (!parse_peek_string_cbs(p, sep)) | ||
515 | sep = " = "; | ||
516 | if (!parse_get_string_cbs(p, sep)) | ||
517 | parse_errx(p, "error getting \"%s\"", sep); | ||
518 | } | ||
519 | |||
520 | static int | ||
521 | parse_empty_or_comment_line(struct parse *p) | ||
522 | { | ||
523 | if (CBS_len(&p->cbs) == 0) { | ||
524 | return 1; | ||
525 | } | ||
526 | if (parse_peek_string_cbs(p, "#")) { | ||
527 | if (!CBS_skip(&p->cbs, CBS_len(&p->cbs))) | ||
528 | parse_errx(p, "CBS_skip"); | ||
529 | return 1; | ||
530 | } | ||
531 | return 0; | ||
532 | } | ||
533 | |||
534 | static void | ||
535 | parse_string_match_line(struct parse *p) | ||
536 | { | ||
537 | int string_matches; | ||
538 | |||
539 | parse_check_label_matches(p); | ||
540 | |||
541 | string_matches = parse_get_string_cbs(p, match(p)); | ||
542 | parse_state_set_int(p, string_matches); | ||
543 | |||
544 | if (!string_matches) { | ||
545 | if (!CBS_skip(&p->cbs, CBS_len(&p->cbs))) | ||
546 | parse_errx(p, "CBS_skip"); | ||
547 | } | ||
548 | } | ||
549 | |||
550 | static int | ||
551 | parse_get_hex_nibble_cbs(CBS *cbs, uint8_t *out_nibble) | ||
552 | { | ||
553 | uint8_t c; | ||
554 | |||
555 | if (!CBS_get_u8(cbs, &c)) | ||
556 | return 0; | ||
557 | |||
558 | if (c >= '0' && c <= '9') { | ||
559 | *out_nibble = c - '0'; | ||
560 | return 1; | ||
561 | } | ||
562 | if (c >= 'a' && c <= 'f') { | ||
563 | *out_nibble = c - 'a' + 10; | ||
564 | return 1; | ||
565 | } | ||
566 | if (c >= 'A' && c <= 'F') { | ||
567 | *out_nibble = c - 'A' + 10; | ||
568 | return 1; | ||
569 | } | ||
570 | |||
571 | return 0; | ||
572 | } | ||
573 | |||
574 | static void | ||
575 | parse_hex_line(struct parse *p) | ||
576 | { | ||
577 | CBB cbb; | ||
578 | |||
579 | parse_check_label_matches(p); | ||
580 | |||
581 | if (!CBB_init(&cbb, 0)) | ||
582 | parse_errx(p, "CBB_init"); | ||
583 | |||
584 | while (CBS_len(&p->cbs) > 0) { | ||
585 | uint8_t hi, lo; | ||
586 | |||
587 | if (!parse_get_hex_nibble_cbs(&p->cbs, &hi)) | ||
588 | parse_errx(p, "parse_get_hex_nibble_cbs"); | ||
589 | if (!parse_get_hex_nibble_cbs(&p->cbs, &lo)) | ||
590 | parse_errx(p, "parse_get_hex_nibble_cbs"); | ||
591 | |||
592 | if (!CBB_add_u8(&cbb, hi << 4 | lo)) | ||
593 | parse_errx(p, "CBB_add_u8"); | ||
594 | } | ||
595 | |||
596 | parse_state_set_from_cbb(p, &cbb); | ||
597 | } | ||
598 | |||
599 | static void | ||
600 | parse_maybe_prepare_instruction_line(struct parse *p) | ||
601 | { | ||
602 | if (parse_instructions_parsed(p)) | ||
603 | return; | ||
604 | |||
605 | /* Should not happen due to parse_empty_or_comment_line(). */ | ||
606 | if (CBS_len(&p->cbs) == 0) | ||
607 | parse_errx(p, "empty instruction line"); | ||
608 | |||
609 | if (!parse_peek_string_cbs(p, "[")) | ||
610 | parse_errx(p, "expected instruction line"); | ||
611 | if (!parse_get_string_cbs(p, "[")) | ||
612 | parse_errx(p, "expected start of instruction line"); | ||
613 | if (!parse_get_string_end_cbs(p, "]")) | ||
614 | parse_errx(p, "expected end of instruction line"); | ||
615 | } | ||
616 | |||
617 | static void | ||
618 | parse_check_line_consumed(struct parse *p) | ||
619 | { | ||
620 | if (CBS_len(&p->cbs) > 0) | ||
621 | parse_errx(p, "%zu unprocessed bytes", CBS_len(&p->cbs)); | ||
622 | } | ||
623 | |||
624 | static int | ||
625 | parse_run_test_case(struct parse *p) | ||
626 | { | ||
627 | const struct test_parse *tctx = p->tctx; | ||
628 | |||
629 | p->state.running_test_case = 1; | ||
630 | return tctx->run_test_case(p->ctx); | ||
631 | } | ||
632 | |||
633 | static void | ||
634 | parse_reinit(struct parse *p) | ||
635 | { | ||
636 | const struct test_parse *tctx = p->tctx; | ||
637 | |||
638 | p->state.running_test_case = 0; | ||
639 | parse_line_data_clear(p); | ||
640 | tctx->finish(p->ctx); | ||
641 | tctx->init(p->ctx, p); | ||
642 | } | ||
643 | |||
644 | static int | ||
645 | parse_maybe_run_test_case(struct parse *p) | ||
646 | { | ||
647 | int failed = 0; | ||
648 | |||
649 | if (parse_must_run_test_case(p)) { | ||
650 | failed |= parse_run_test_case(p); | ||
651 | parse_reinit(p); | ||
652 | } | ||
653 | |||
654 | parse_advance(p); | ||
655 | |||
656 | return failed; | ||
657 | } | ||
658 | |||
659 | static int | ||
660 | parse_process_line(struct parse *p) | ||
661 | { | ||
662 | if (parse_empty_or_comment_line(p)) | ||
663 | return 0; | ||
664 | |||
665 | parse_maybe_prepare_instruction_line(p); | ||
666 | |||
667 | switch (parse_line_type(p)) { | ||
668 | case LINE_STRING_MATCH: | ||
669 | parse_string_match_line(p); | ||
670 | break; | ||
671 | case LINE_HEX: | ||
672 | parse_hex_line(p); | ||
673 | break; | ||
674 | default: | ||
675 | parse_errx(p, "unknown line type %d", parse_line_type(p)); | ||
676 | } | ||
677 | parse_check_line_consumed(p); | ||
678 | |||
679 | return parse_maybe_run_test_case(p); | ||
680 | } | ||
681 | |||
682 | static void | ||
683 | parse_init(struct parse *p, const char *fn, const struct test_parse *tctx, | ||
684 | void *ctx) | ||
685 | { | ||
686 | FILE *fp; | ||
687 | |||
688 | memset(p, 0, sizeof(*p)); | ||
689 | |||
690 | if ((fp = fopen(fn, "r")) == NULL) | ||
691 | err(1, "error opening %s", fn); | ||
692 | |||
693 | /* Poor man's basename since POSIX basename is stupid. */ | ||
694 | if ((p->fn = strrchr(fn, '/')) != NULL) | ||
695 | p->fn++; | ||
696 | else | ||
697 | p->fn = fn; | ||
698 | |||
699 | p->fp = fp; | ||
700 | parse_state_init(&p->state, tctx->num_states, tctx->num_instructions); | ||
701 | p->tctx = tctx; | ||
702 | p->ctx = ctx; | ||
703 | tctx->init(ctx, p); | ||
704 | } | ||
705 | |||
706 | static int | ||
707 | parse_next_line(struct parse *p) | ||
708 | { | ||
709 | ssize_t len; | ||
710 | uint8_t u8; | ||
711 | |||
712 | if ((len = getline(&p->buf, &p->buf_max, p->fp)) == -1) | ||
713 | return 0; | ||
714 | |||
715 | CBS_init(&p->cbs, (const uint8_t *)p->buf, len); | ||
716 | parse_state_new_line(&p->state); | ||
717 | |||
718 | if (!CBS_get_last_u8(&p->cbs, &u8)) | ||
719 | parse_errx(p, "CBS_get_last_u8"); | ||
720 | |||
721 | assert(u8 == '\n'); | ||
722 | |||
723 | return 1; | ||
724 | } | ||
725 | |||
726 | static void | ||
727 | parse_finish(struct parse *p) | ||
728 | { | ||
729 | parse_state_finish(&p->state); | ||
730 | |||
731 | free(p->buf); | ||
732 | |||
733 | if (ferror(p->fp)) | ||
734 | err(1, "%s", p->fn); | ||
735 | fclose(p->fp); | ||
736 | } | ||
737 | |||
738 | int | ||
739 | parse_test_file(const char *fn, const struct test_parse *tctx, void *ctx) | ||
740 | { | ||
741 | struct parse p; | ||
742 | int failed = 0; | ||
743 | |||
744 | parse_init(&p, fn, tctx, ctx); | ||
745 | |||
746 | while (parse_next_line(&p)) | ||
747 | failed |= parse_process_line(&p); | ||
748 | |||
749 | parse_finish(&p); | ||
750 | |||
751 | return failed; | ||
752 | } | ||
diff --git a/src/regress/lib/libcrypto/mlkem/parse_test_file.h b/src/regress/lib/libcrypto/mlkem/parse_test_file.h new file mode 100644 index 0000000000..772b7f6232 --- /dev/null +++ b/src/regress/lib/libcrypto/mlkem/parse_test_file.h | |||
@@ -0,0 +1,83 @@ | |||
1 | /* $OpenBSD: parse_test_file.h,v 1.1 2024/12/26 00:04:24 tb Exp $ */ | ||
2 | |||
3 | /* | ||
4 | * Copyright (c) 2024 Theo Buehler <tb@openbsd.org> | ||
5 | * | ||
6 | * Permission to use, copy, modify, and distribute this software for any | ||
7 | * purpose with or without fee is hereby granted, provided that the above | ||
8 | * copyright notice and this permission notice appear in all copies. | ||
9 | * | ||
10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||
11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | ||
12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | ||
13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||
14 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | ||
15 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | ||
16 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
17 | */ | ||
18 | |||
19 | #ifndef PARSE_TEST_FILE_H | ||
20 | #define PARSE_TEST_FILE_H | ||
21 | |||
22 | #include <stdint.h> | ||
23 | #include <stdio.h> | ||
24 | |||
25 | #include "bytestring.h" | ||
26 | |||
27 | #if defined(__cplusplus) | ||
28 | extern "C" { | ||
29 | #endif | ||
30 | |||
31 | struct parse; | ||
32 | |||
33 | enum line { | ||
34 | LINE_STRING_MATCH, /* Checks if string after label matches. */ | ||
35 | LINE_HEX, /* Parses hex into cbb from type2cbb. */ | ||
36 | }; | ||
37 | |||
38 | struct line_spec { | ||
39 | int state; | ||
40 | enum line type; | ||
41 | const char *name; | ||
42 | const char *label; /* followed by ": " or " = " */ | ||
43 | const char *match; /* only for LINE_STRING_MATCH */ | ||
44 | }; | ||
45 | |||
46 | struct test_parse { | ||
47 | const struct line_spec *states; | ||
48 | size_t num_states; | ||
49 | |||
50 | const struct line_spec *instructions; | ||
51 | size_t num_instructions; | ||
52 | |||
53 | int (*init)(void *ctx, void *parse_ctx); | ||
54 | void (*finish)(void *ctx); | ||
55 | |||
56 | int (*run_test_case)(void *ctx); | ||
57 | }; | ||
58 | |||
59 | int parse_test_file(const char *fn, const struct test_parse *lctx, void *ctx); | ||
60 | |||
61 | int parse_get_int(struct parse *p, size_t idx, int *out); | ||
62 | int parse_get_cbs(struct parse *p, size_t idx, CBS *out); | ||
63 | |||
64 | int parse_instruction_get_int(struct parse *p, size_t idx, int *out); | ||
65 | int parse_instruction_get_cbs(struct parse *p, size_t idx, CBS *out); | ||
66 | |||
67 | int parse_length_equal(struct parse *p, const char *descr, size_t want, size_t got); | ||
68 | int parse_data_equal(struct parse *p, const char *descr, CBS *want, | ||
69 | const uint8_t *got, size_t len); | ||
70 | |||
71 | void parse_info(struct parse *ctx, const char *fmt, ...) | ||
72 | __attribute__((__format__ (printf, 2, 3))) | ||
73 | __attribute__((__nonnull__ (2))); | ||
74 | void parse_errx(struct parse *ctx, const char *fmt, ...) | ||
75 | __attribute__((__format__ (printf, 2, 3))) | ||
76 | __attribute__((__nonnull__ (2))) | ||
77 | __attribute__((__noreturn__)); | ||
78 | |||
79 | #ifdef __cplusplus | ||
80 | } | ||
81 | #endif | ||
82 | |||
83 | #endif /* PARSE_TEST_FILE_H */ | ||