diff options
Diffstat (limited to 'src/regress/lib/libcrypto/mlkem/mlkem768_nist_decap_tests.c')
-rw-r--r-- | src/regress/lib/libcrypto/mlkem/mlkem768_nist_decap_tests.c | 210 |
1 files changed, 146 insertions, 64 deletions
diff --git a/src/regress/lib/libcrypto/mlkem/mlkem768_nist_decap_tests.c b/src/regress/lib/libcrypto/mlkem/mlkem768_nist_decap_tests.c index 0778c921b6..c72ad5c388 100644 --- a/src/regress/lib/libcrypto/mlkem/mlkem768_nist_decap_tests.c +++ b/src/regress/lib/libcrypto/mlkem/mlkem768_nist_decap_tests.c | |||
@@ -1,7 +1,8 @@ | |||
1 | /* $OpenBSD: mlkem768_nist_decap_tests.c,v 1.2 2024/12/14 19:16:24 tb Exp $ */ | 1 | /* $OpenBSD: mlkem768_nist_decap_tests.c,v 1.3 2024/12/20 00:07:12 tb Exp $ */ |
2 | /* | 2 | /* |
3 | * Copyright (c) 2024, Google Inc. | 3 | * Copyright (c) 2024 Google Inc. |
4 | * Copyright (c) 2024, Bob Beck <beck@obtuse.com> | 4 | * Copyright (c) 2024 Bob Beck <beck@obtuse.com> |
5 | * Copyright (c) 2024 Theo Buehler <tb@openbsd.org> | ||
5 | * | 6 | * |
6 | * Permission to use, copy, modify, and/or distribute this software for any | 7 | * Permission to use, copy, modify, and/or distribute this software for any |
7 | * purpose with or without fee is hereby granted, provided that the above | 8 | * purpose with or without fee is hereby granted, provided that the above |
@@ -16,96 +17,177 @@ | |||
16 | * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | 17 | * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
17 | */ | 18 | */ |
18 | 19 | ||
20 | #include <assert.h> | ||
21 | #include <err.h> | ||
19 | #include <stdint.h> | 22 | #include <stdint.h> |
20 | #include <stdio.h> | 23 | #include <stdio.h> |
21 | #include <stdlib.h> | 24 | #include <stdlib.h> |
22 | #include <string.h> | ||
23 | 25 | ||
24 | #include <openssl/bytestring.h> | 26 | #include "bytestring.h" |
25 | #include <openssl/mlkem.h> | 27 | #include "mlkem.h" |
26 | 28 | ||
27 | #include "mlkem_internal.h" | 29 | #include "mlkem_internal.h" |
28 | #include "mlkem_tests_util.h" | 30 | #include "mlkem_tests_util.h" |
29 | 31 | ||
30 | static void | 32 | static int |
31 | MlkemNistDecapFileTest(CBS *c, CBS *k, CBS *dk) | 33 | MlkemNistDecapFileTest(CBB *c_cbb, CBB *k_cbb, CBS *dk, size_t line) |
32 | { | 34 | { |
35 | uint8_t *c = NULL, *k = NULL; | ||
36 | size_t c_len = 0, k_len = 0; | ||
33 | uint8_t shared_secret[MLKEM_SHARED_SECRET_BYTES]; | 37 | uint8_t shared_secret[MLKEM_SHARED_SECRET_BYTES]; |
34 | struct MLKEM768_private_key priv; | 38 | struct MLKEM768_private_key priv; |
39 | int failed = 1; | ||
35 | 40 | ||
36 | TEST(CBS_len(dk) != MLKEM768_PRIVATE_KEY_BYTES, | 41 | if (!CBB_finish(c_cbb, &c, &c_len)) |
37 | "private key len bogus"); | 42 | goto err; |
38 | TEST(CBS_len(k) != MLKEM_SHARED_SECRET_BYTES, | 43 | if (!CBB_finish(k_cbb, &k, &k_len)) |
39 | "shared secret len bogus"); | 44 | goto err; |
40 | 45 | ||
41 | TEST(!MLKEM768_parse_private_key(&priv, dk), "parse_private_key"); | 46 | if (!compare_length(MLKEM768_PRIVATE_KEY_BYTES, CBS_len(dk), line, |
42 | TEST(!MLKEM768_decap(shared_secret, CBS_data(c), CBS_len(c), &priv), | 47 | "private key len bogus")) |
43 | "decap"); | 48 | goto err; |
44 | TEST_DATAEQ(shared_secret, CBS_data(k), | 49 | if (!compare_length(MLKEM_SHARED_SECRET_BYTES, k_len, line, |
45 | MLKEM_SHARED_SECRET_BYTES, "shared_secret"); | 50 | "shared secret len bogus")) |
51 | goto err; | ||
52 | |||
53 | if (!MLKEM768_parse_private_key(&priv, dk)) { | ||
54 | warnx("#%zu MLKEM768_parse_private_key", line); | ||
55 | goto err; | ||
56 | } | ||
57 | if (!MLKEM768_decap(shared_secret, c, c_len, &priv)) { | ||
58 | warnx("#%zu MLKEM768_decap", line); | ||
59 | goto err; | ||
60 | } | ||
61 | |||
62 | failed = compare_data(shared_secret, k, k_len, line, "shared_secret"); | ||
63 | |||
64 | err: | ||
65 | CBB_cleanup(c_cbb); | ||
66 | CBB_cleanup(k_cbb); | ||
67 | freezero(c, c_len); | ||
68 | freezero(k, k_len); | ||
69 | |||
70 | return failed; | ||
46 | } | 71 | } |
47 | 72 | ||
48 | #define S_START 0 | 73 | #define S_START 0 |
49 | #define S_CIPHERTEXT 1 | 74 | #define S_C 1 |
50 | #define S_SHARED_SECRET 2 | 75 | #define S_K 2 |
51 | #define S_PRIVATE_KEY 3 | 76 | #define S_EMPTY 3 |
77 | |||
78 | #define S2S(x) case x: return #x | ||
79 | |||
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 | } | ||
52 | 92 | ||
53 | int | 93 | int |
54 | main(int argc, char **argv) | 94 | main(int argc, char **argv) |
55 | { | 95 | { |
56 | CBS ciphertext, shared_secret, private_key; | 96 | CBB dk_cbb = { 0 }, c = { 0 }, k = { 0 }; |
57 | const uint8_t *p; | 97 | CBS instr; |
58 | char *buf; | 98 | uint8_t *dk = NULL; |
99 | size_t dk_len = 0; | ||
100 | uint8_t bracket, newline; | ||
101 | const char *test; | ||
102 | size_t line; | ||
103 | char *buf = NULL; | ||
104 | size_t buflen = 0; | ||
105 | ssize_t len; | ||
59 | FILE *fp; | 106 | FILE *fp; |
60 | int state; | 107 | int state; |
108 | int failed = 0; | ||
109 | |||
110 | if (argc < 2) | ||
111 | errx(1, "%s: missing test file", argv[0]); | ||
112 | |||
113 | test = argv[1]; | ||
114 | |||
115 | if ((fp = fopen(test, "r")) == NULL) | ||
116 | err(1, "cant't open test file"); | ||
117 | |||
118 | if ((len = getline(&buf, &buflen, fp)) == -1) | ||
119 | err(1, "failed to read instruction line"); | ||
120 | |||
121 | /* | ||
122 | * The private key is enclosed in brackets in an "instruction line". | ||
123 | */ | ||
124 | line = 1; | ||
125 | CBS_init(&instr, buf, len); | ||
126 | if (!CBS_get_u8(&instr, &bracket)) | ||
127 | err(1, "failed to parse instruction line '['"); | ||
128 | assert(bracket == '['); | ||
129 | if (!CBS_get_last_u8(&instr, &newline)) | ||
130 | errx(1, "failed to parse instruction line '\\n'"); | ||
131 | assert(newline == '\n'); | ||
132 | if (!CBS_get_last_u8(&instr, &bracket)) | ||
133 | errx(1, "failed to parse instruction line ']'"); | ||
134 | assert(bracket == ']'); | ||
135 | if (!get_string_cbs(&instr, "dk: ", line, "private key")) | ||
136 | errx(1, "failed to read instruction line 'dk: '"); | ||
137 | hex_decode_cbs(&instr, &dk_cbb, line, "private key"); | ||
138 | assert(CBS_len(&instr) == 0); | ||
139 | |||
140 | if (!CBB_finish(&dk_cbb, &dk, &dk_len)) | ||
141 | errx(1, "CBB finish instruction line"); | ||
142 | |||
143 | state = S_START; | ||
144 | |||
145 | while ((len = getline(&buf, &buflen, fp)) != -1) { | ||
146 | const char *msg = state2str(state); | ||
147 | CBS cbs, dk_cbs; | ||
148 | uint8_t u8; | ||
149 | |||
150 | line++; | ||
151 | CBS_init(&cbs, buf, len); | ||
152 | |||
153 | if (!CBS_get_last_u8(&cbs, &u8)) | ||
154 | errx(1, "#%zu %s: CBB_get_last_u8", line, msg); | ||
155 | assert(u8 == '\n'); | ||
61 | 156 | ||
62 | fprintf(stderr, "Testing NIST decap test vectors in %s\n", argv[1]); | ||
63 | TEST((fp = fopen(argv[1], "r")) == NULL, "can't open test file"); | ||
64 | MALLOC(buf, 16*1024); | ||
65 | state = S_CIPHERTEXT; | ||
66 | test_number = 1; | ||
67 | while (fgets(buf, 16*1024, fp) != NULL) { | ||
68 | switch (state) { | 157 | switch (state) { |
69 | case S_START: | 158 | case S_START: |
70 | if (strcmp(buf, "\n") != 0) | 159 | state = S_C; |
71 | break; | ||
72 | state = S_CIPHERTEXT; | ||
73 | break; | 160 | break; |
74 | case S_CIPHERTEXT: | 161 | case S_C: |
75 | if (strncmp(buf, "ciphertext: ", | 162 | if (!get_string_cbs(&cbs, "c: ", line, msg)) |
76 | strlen("ciphertext: ")) != 0) { | 163 | errx(1, "#%zu %s: get_string_cbs", line, msg); |
77 | break; | 164 | hex_decode_cbs(&cbs, &c, line, msg); |
78 | } | 165 | state = S_K; |
79 | grab_data(&ciphertext, buf, strlen("ciphertext: ")); | ||
80 | state = S_SHARED_SECRET; | ||
81 | break; | 166 | break; |
82 | case S_SHARED_SECRET: | 167 | case S_K: |
83 | if (strncmp(buf, "shared_secret: ", | 168 | if (!get_string_cbs(&cbs, "k: ", line, msg)) |
84 | strlen("shared_secret: ")) != 0) | 169 | errx(1, "#%zu %s: get_string_cbs", line, msg); |
85 | break; | 170 | hex_decode_cbs(&cbs, &k, line, msg); |
86 | grab_data(&shared_secret, buf, | 171 | state = S_EMPTY; |
87 | strlen("shared_secret: ")); | ||
88 | state = S_PRIVATE_KEY; | ||
89 | break; | 172 | break; |
90 | case S_PRIVATE_KEY: | 173 | case S_EMPTY: |
91 | if (strncmp(buf, "private_key: ", | 174 | CBS_init(&dk_cbs, dk, dk_len); |
92 | strlen("private_key: ")) != 0) | 175 | |
93 | break; | 176 | failed |= MlkemNistDecapFileTest(&c, &k, &dk_cbs, line); |
94 | grab_data(&private_key, buf, strlen("private_key: ")); | 177 | |
95 | p = CBS_data(&private_key); | 178 | state = S_C; |
96 | |||
97 | MlkemNistDecapFileTest(&ciphertext, &shared_secret, | ||
98 | &private_key); | ||
99 | free((void *)CBS_data(&ciphertext)); | ||
100 | free((void *)CBS_data(&shared_secret)); | ||
101 | free((void *)p); | ||
102 | |||
103 | state = S_START; | ||
104 | test_number++; | ||
105 | break; | 179 | break; |
106 | } | 180 | } |
181 | if (CBS_len(&cbs) > 0) | ||
182 | errx(1, "#%zu %s: CBS_len", line, msg); | ||
107 | } | 183 | } |
108 | |||
109 | free(buf); | 184 | free(buf); |
110 | exit(failure); | 185 | |
186 | if (ferror(fp)) | ||
187 | err(1, NULL); | ||
188 | fclose(fp); | ||
189 | |||
190 | freezero(dk, dk_len); | ||
191 | |||
192 | return failed; | ||
111 | } | 193 | } |