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