diff options
Diffstat (limited to 'src/regress/lib/libcrypto/mlkem/mlkem768_encap_tests.c')
| -rw-r--r-- | src/regress/lib/libcrypto/mlkem/mlkem768_encap_tests.c | 221 |
1 files changed, 148 insertions, 73 deletions
diff --git a/src/regress/lib/libcrypto/mlkem/mlkem768_encap_tests.c b/src/regress/lib/libcrypto/mlkem/mlkem768_encap_tests.c index be6c6149da..55e3fe66bb 100644 --- a/src/regress/lib/libcrypto/mlkem/mlkem768_encap_tests.c +++ b/src/regress/lib/libcrypto/mlkem/mlkem768_encap_tests.c | |||
| @@ -1,7 +1,8 @@ | |||
| 1 | /* $OpenBSD: mlkem768_encap_tests.c,v 1.2 2024/12/14 19:16:24 tb Exp $ */ | 1 | /* $OpenBSD: mlkem768_encap_tests.c,v 1.3 2024/12/20 00:07:12 tb Exp $ */ |
| 2 | /* | 2 | /* |
| 3 | * Copyright (c) 2024, Google Inc. | 3 | * Copyright (c) 2024 Google Inc. |
| 4 | * Copyright (c) 2024, Bob Beck <beck@obtuse.com> | 4 | * Copyright (c) 2024 Bob Beck <beck@obtuse.com> |
| 5 | * Copyright (c) 2024 Theo Buehler <tb@openbsd.org> | ||
| 5 | * | 6 | * |
| 6 | * Permission to use, copy, modify, and/or distribute this software for any | 7 | * Permission to use, copy, modify, and/or distribute this software for any |
| 7 | * purpose with or without fee is hereby granted, provided that the above | 8 | * purpose with or without fee is hereby granted, provided that the above |
| @@ -16,120 +17,194 @@ | |||
| 16 | * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | 17 | * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
| 17 | */ | 18 | */ |
| 18 | 19 | ||
| 20 | #include <assert.h> | ||
| 21 | #include <err.h> | ||
| 19 | #include <stdint.h> | 22 | #include <stdint.h> |
| 20 | #include <stdio.h> | 23 | #include <stdio.h> |
| 21 | #include <stdlib.h> | 24 | #include <stdlib.h> |
| 22 | #include <string.h> | ||
| 23 | 25 | ||
| 24 | #include <openssl/bytestring.h> | 26 | #include "bytestring.h" |
| 25 | #include <openssl/mlkem.h> | 27 | #include "mlkem.h" |
| 26 | 28 | ||
| 29 | #include "mlkem_internal.h" | ||
| 27 | #include "mlkem_tests_util.h" | 30 | #include "mlkem_tests_util.h" |
| 28 | 31 | ||
| 29 | static void | 32 | static int |
| 30 | MlkemEncapFileTest(CBS *entropy, CBS *public_key, CBS *expected_ciphertext, | 33 | MlkemEncapFileTest(CBB *entropy_cbb, CBB *pubkey_cbb, CBB *ciphertext_cbb, |
| 31 | CBS *expected_shared_secret, int should_fail) | 34 | CBB *shared_secret_cbb, int should_fail, size_t line) |
| 32 | { | 35 | { |
| 33 | uint8_t shared_secret[MLKEM_SHARED_SECRET_BYTES]; | ||
| 34 | uint8_t ciphertext[MLKEM768_CIPHERTEXT_BYTES]; | ||
| 35 | struct MLKEM768_public_key pub; | 36 | struct MLKEM768_public_key pub; |
| 36 | int parse_ok; | 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; | ||
| 37 | 45 | ||
| 38 | parse_ok = MLKEM768_parse_public_key(&pub, public_key); | 46 | if (!CBB_finish(entropy_cbb, &entropy, &entropy_len)) |
| 39 | if (!parse_ok) { | 47 | goto err; |
| 40 | TEST(!should_fail, "parse_public_key"); | 48 | if (!CBB_finish(pubkey_cbb, &public_key, &public_key_len)) |
| 41 | return; | 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; | ||
| 42 | } | 61 | } |
| 43 | MLKEM768_encap(ciphertext, shared_secret, &pub); | 62 | MLKEM768_encap_external_entropy(ciphertext_buf, shared_secret_buf, |
| 44 | TEST_DATAEQ(shared_secret, CBS_data(expected_shared_secret), | 63 | &pub, entropy); |
| 45 | MLKEM_SHARED_SECRET_BYTES, "shared_secret"); | 64 | |
| 46 | TEST_DATAEQ(ciphertext, CBS_data(expected_ciphertext), | 65 | failed = compare_data(shared_secret, shared_secret_buf, |
| 47 | MLKEM768_CIPHERTEXT_BYTES, "shared_secret"); | 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; | ||
| 48 | } | 87 | } |
| 49 | 88 | ||
| 50 | #define S_START 0 | 89 | #define S_START 0 |
| 51 | #define S_COMMENT 1 | 90 | #define S_COMMENT 1 |
| 52 | #define S_ENTROPY 2 | 91 | #define S_ENTROPY 2 |
| 53 | #define S_PUBLIC_KEY 3 | 92 | #define S_PUBLIC_KEY 3 |
| 54 | #define S_RESULT 4 | 93 | #define S_RESULT 4 |
| 55 | #define S_CIPHERTEXT 5 | 94 | #define S_CIPHERTEXT 5 |
| 56 | #define S_SHARED_SECRET 6 | 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 | } | ||
| 57 | 114 | ||
| 58 | int | 115 | int |
| 59 | main(int argc, char **argv) | 116 | main(int argc, char **argv) |
| 60 | { | 117 | { |
| 61 | CBS entropy, public_key, ciphertext, shared_secret; | 118 | CBB entropy = { 0 }, public_key = { 0 }, ciphertext = { 0 }, shared_secret = { 0 }; |
| 62 | const uint8_t *p = NULL; | ||
| 63 | int should_fail = 0; | 119 | int should_fail = 0; |
| 64 | char *buf; | 120 | const char *test; |
| 121 | size_t line; | ||
| 122 | char *buf = NULL; | ||
| 123 | size_t buflen = 0; | ||
| 124 | ssize_t len; | ||
| 65 | FILE *fp; | 125 | FILE *fp; |
| 66 | int state; | 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, "cant't open test file"); | ||
| 67 | 137 | ||
| 68 | fprintf(stderr, "Testing encap test vectors in %s\n", argv[1]); | ||
| 69 | TEST((fp = fopen(argv[1], "r")) == NULL, "can't open test file"); | ||
| 70 | MALLOC(buf, 16*1024); | ||
| 71 | state = S_COMMENT; | 138 | state = S_COMMENT; |
| 72 | test_number = 1; | 139 | line = 0; |
| 73 | while (fgets(buf, 16*1024, fp) != NULL) { | 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 | |||
| 74 | switch (state) { | 153 | switch (state) { |
| 75 | case S_START: | 154 | case S_START: |
| 76 | if (strcmp(buf, "\n") != 0) | ||
| 77 | break; | ||
| 78 | state = S_COMMENT; | 155 | state = S_COMMENT; |
| 79 | break; | 156 | break; |
| 80 | case S_COMMENT: | 157 | case S_COMMENT: |
| 81 | if (strncmp(buf, "#", 1) != 0) | 158 | if (!CBS_get_u8(&cbs, &u8)) |
| 82 | break; | 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); | ||
| 83 | state = S_ENTROPY; | 163 | state = S_ENTROPY; |
| 84 | break; | 164 | break; |
| 85 | case S_ENTROPY: | 165 | case S_ENTROPY: |
| 86 | if (strncmp(buf, "entropy: ", strlen("entropy: ")) != 0) | 166 | if (!get_string_cbs(&cbs, "entropy: ", line, msg)) |
| 87 | break; | 167 | errx(1, "#%zu %s: get_string_cbs", line, msg); |
| 88 | grab_data(&entropy, buf, strlen("entropy: ")); | 168 | hex_decode_cbs(&cbs, &entropy, line, msg); |
| 89 | p = CBS_data(&entropy); | ||
| 90 | state = S_PUBLIC_KEY; | 169 | state = S_PUBLIC_KEY; |
| 91 | break; | 170 | break; |
| 92 | case S_PUBLIC_KEY: | 171 | case S_PUBLIC_KEY: |
| 93 | if (strncmp(buf, "public_key: ", | 172 | if (!get_string_cbs(&cbs, "public_key = ", line, msg)) |
| 94 | strlen("public_key: ")) != 0) | 173 | errx(1, "#%zu %s: get_string_cbs", line, msg); |
| 95 | break; | 174 | hex_decode_cbs(&cbs, &public_key, line, msg); |
| 96 | grab_data(&public_key, buf, strlen("public_key: ")); | ||
| 97 | p = CBS_data(&public_key); | ||
| 98 | state = S_RESULT; | 175 | state = S_RESULT; |
| 99 | break; | 176 | break; |
| 100 | case S_RESULT: | 177 | case S_RESULT: |
| 101 | if (strncmp(buf, "result: pass", | 178 | if (!get_string_cbs(&cbs, "result: ", line, msg)) |
| 102 | strlen("result: pass")) != 0) | 179 | errx(1, "#%zu %s: get_string_cbs", line, msg); |
| 103 | should_fail = 1; | 180 | should_fail = get_string_cbs(&cbs, "fail", line, msg); |
| 104 | else | ||
| 105 | should_fail = 0; | ||
| 106 | state = S_CIPHERTEXT; | 181 | state = S_CIPHERTEXT; |
| 107 | break; | 182 | break; |
| 108 | case S_CIPHERTEXT: | 183 | case S_CIPHERTEXT: |
| 109 | if (strncmp(buf, "ciphertext: ", | 184 | if (!get_string_cbs(&cbs, "ciphertext: ", line, msg)) |
| 110 | strlen("ciphertext: ")) != 0) | 185 | errx(1, "#%zu %s: get_string_cbs", line, msg); |
| 111 | break; | 186 | hex_decode_cbs(&cbs, &ciphertext, line, msg); |
| 112 | grab_data(&ciphertext, buf, strlen("ciphertext: ")); | 187 | state = S_SHARED_SECRET; |
| 113 | state = S_RESULT; | ||
| 114 | break; | 188 | break; |
| 115 | case S_SHARED_SECRET: | 189 | case S_SHARED_SECRET: |
| 116 | if (strncmp(buf, "shared_secret: ", | 190 | if (!get_string_cbs(&cbs, "shared_secret: ", line, msg)) |
| 117 | strlen("shared_secret: ")) != 0) | 191 | errx(1, "#%zu %s: get_string_cbs", line, msg); |
| 118 | break; | 192 | hex_decode_cbs(&cbs, &shared_secret, line, msg); |
| 119 | grab_data(&shared_secret, buf, | 193 | |
| 120 | strlen("shared_secret: ")); | 194 | failed |= MlkemEncapFileTest(&entropy, &public_key, |
| 121 | MlkemEncapFileTest(&entropy, &public_key, &ciphertext, | 195 | &ciphertext, &shared_secret, should_fail, line); |
| 122 | &shared_secret, should_fail); | 196 | |
| 123 | free((void *)CBS_data(&ciphertext)); | ||
| 124 | free((void *)CBS_data(&shared_secret)); | ||
| 125 | free((void *)p); | ||
| 126 | |||
| 127 | test_number++; | ||
| 128 | state = S_START; | 197 | state = S_START; |
| 129 | break; | 198 | break; |
| 130 | } | 199 | } |
| 200 | if (CBS_len(&cbs) > 0) | ||
| 201 | errx(1, "#%zu %s: CBS_len", line, msg); | ||
| 131 | } | 202 | } |
| 132 | |||
| 133 | free(buf); | 203 | free(buf); |
| 134 | exit(failure); | 204 | |
| 205 | if (ferror(fp)) | ||
| 206 | err(1, NULL); | ||
| 207 | fclose(fp); | ||
| 208 | |||
| 209 | return failed; | ||
| 135 | } | 210 | } |
