diff options
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 */ | ||