diff options
| author | beck <> | 2025-08-14 15:48:48 +0000 |
|---|---|---|
| committer | beck <> | 2025-08-14 15:48:48 +0000 |
| commit | 6452fa9fc6f33dac80ee572764b9fe29a469f8ce (patch) | |
| tree | 0956ae670e4f193442bcf99d2b1fb70a43a6b5b5 /src/regress/lib/libcrypto | |
| parent | 9bef27f78e41e8026f1d588e4e36e385061f3deb (diff) | |
| download | openbsd-6452fa9fc6f33dac80ee572764b9fe29a469f8ce.tar.gz openbsd-6452fa9fc6f33dac80ee572764b9fe29a469f8ce.tar.bz2 openbsd-6452fa9fc6f33dac80ee572764b9fe29a469f8ce.zip | |
Add a reasonable ML-KEM API for public use.
Adapt the tests to use this API.
This does not yet make the symbols public in Symbols.list
which will happen shortly with a bump.
This includes some partial rototilling of the non-public
interfaces which will be shortly continued when the internal
code is deduplicated to not have multiple copies for ML-KEM
768 and ML-KEM 1024 (which is just an artifact of unravelling
the boring C++ code).
ok jsing@, tb@
Diffstat (limited to 'src/regress/lib/libcrypto')
| -rw-r--r-- | src/regress/lib/libcrypto/mlkem/mlkem_iteration_tests.c | 179 | ||||
| -rw-r--r-- | src/regress/lib/libcrypto/mlkem/mlkem_tests.c | 292 | ||||
| -rw-r--r-- | src/regress/lib/libcrypto/mlkem/mlkem_tests_util.c | 158 | ||||
| -rw-r--r-- | src/regress/lib/libcrypto/mlkem/mlkem_tests_util.h | 58 | ||||
| -rw-r--r-- | src/regress/lib/libcrypto/mlkem/mlkem_unittest.c | 302 |
5 files changed, 396 insertions, 593 deletions
diff --git a/src/regress/lib/libcrypto/mlkem/mlkem_iteration_tests.c b/src/regress/lib/libcrypto/mlkem/mlkem_iteration_tests.c index b93243023c..10c4b1f4e0 100644 --- a/src/regress/lib/libcrypto/mlkem/mlkem_iteration_tests.c +++ b/src/regress/lib/libcrypto/mlkem/mlkem_iteration_tests.c | |||
| @@ -1,4 +1,4 @@ | |||
| 1 | /* $OpenBSD: mlkem_iteration_tests.c,v 1.5 2025/05/20 00:33:41 beck Exp $ */ | 1 | /* $OpenBSD: mlkem_iteration_tests.c,v 1.6 2025/08/14 15:48:48 beck 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> |
| @@ -21,6 +21,7 @@ | |||
| 21 | #include <stdint.h> | 21 | #include <stdint.h> |
| 22 | #include <stdio.h> | 22 | #include <stdio.h> |
| 23 | #include <stdlib.h> | 23 | #include <stdlib.h> |
| 24 | #include <string.h> | ||
| 24 | 25 | ||
| 25 | #include "mlkem.h" | 26 | #include "mlkem.h" |
| 26 | 27 | ||
| @@ -63,46 +64,49 @@ const uint8_t kExpectedAdam1024[32] = { | |||
| 63 | 0x04, 0xab, 0xdb, 0x94, 0x8b, 0x90, 0x8b, 0x75, 0xba, 0xd5 | 64 | 0x04, 0xab, 0xdb, 0x94, 0x8b, 0x90, 0x8b, 0x75, 0xba, 0xd5 |
| 64 | }; | 65 | }; |
| 65 | 66 | ||
| 66 | struct iteration_ctx { | ||
| 67 | uint8_t *encoded_public_key; | ||
| 68 | size_t encoded_public_key_len; | ||
| 69 | uint8_t *ciphertext; | ||
| 70 | size_t ciphertext_len; | ||
| 71 | uint8_t *invalid_ciphertext; | ||
| 72 | size_t invalid_ciphertext_len; | ||
| 73 | void *priv; | ||
| 74 | void *pub; | ||
| 75 | |||
| 76 | mlkem_marshal_private_key_fn marshal_private_key; | ||
| 77 | mlkem_encap_external_entropy_fn encap_external_entropy; | ||
| 78 | mlkem_generate_key_external_entropy_fn generate_key_external_entropy; | ||
| 79 | mlkem_public_from_private_fn public_from_private; | ||
| 80 | mlkem_decap_fn decap; | ||
| 81 | |||
| 82 | const uint8_t *start; | ||
| 83 | size_t start_len; | ||
| 84 | |||
| 85 | const uint8_t *expected; | ||
| 86 | size_t expected_len; | ||
| 87 | }; | ||
| 88 | |||
| 89 | static int | 67 | static int |
| 90 | MlkemIterativeTest(struct iteration_ctx *ctx) | 68 | MlkemIterativeTest(int rank) |
| 91 | { | 69 | { |
| 92 | uint8_t shared_secret[MLKEM_SHARED_SECRET_BYTES]; | 70 | const uint8_t *start, *expected; |
| 71 | size_t start_len; | ||
| 93 | uint8_t encap_entropy[MLKEM_ENCAP_ENTROPY]; | 72 | uint8_t encap_entropy[MLKEM_ENCAP_ENTROPY]; |
| 94 | uint8_t seed[MLKEM_SEED_BYTES] = {0}; | 73 | uint8_t seed[MLKEM_SEED_LENGTH] = {0}; |
| 74 | uint8_t *shared_secret = NULL; | ||
| 95 | sha3_ctx drng, results; | 75 | sha3_ctx drng, results; |
| 96 | uint8_t out[32]; | 76 | uint8_t out[32]; |
| 97 | int i; | 77 | int i; |
| 98 | 78 | ||
| 79 | start = kExpectedSeedStart; | ||
| 80 | start_len = sizeof(kExpectedSeedStart); | ||
| 81 | switch(rank){ | ||
| 82 | case RANK768: | ||
| 83 | expected = kExpectedAdam768; | ||
| 84 | break; | ||
| 85 | case RANK1024: | ||
| 86 | expected = kExpectedAdam1024; | ||
| 87 | break; | ||
| 88 | default: | ||
| 89 | errx(1, "invalid rank %d", rank); | ||
| 90 | } | ||
| 91 | |||
| 99 | shake128_init(&drng); | 92 | shake128_init(&drng); |
| 100 | shake128_init(&results); | 93 | shake128_init(&results); |
| 101 | 94 | ||
| 102 | shake_xof(&drng); | 95 | shake_xof(&drng); |
| 103 | for (i = 0; i < 10000; i++) { | 96 | for (i = 0; i < 10000; i++) { |
| 104 | uint8_t *encoded_private_key = NULL; | 97 | uint8_t *encoded_public_key = NULL, *ciphertext = NULL, |
| 105 | size_t encoded_private_key_len; | 98 | *encoded_private_key = NULL, *invalid_ciphertext = NULL; |
| 99 | size_t encoded_public_key_len, ciphertext_len, | ||
| 100 | encoded_private_key_len, invalid_ciphertext_len; | ||
| 101 | MLKEM_private_key *priv; | ||
| 102 | MLKEM_public_key *pub; | ||
| 103 | size_t s_len = 0; | ||
| 104 | |||
| 105 | /* allocate keys for this iteration */ | ||
| 106 | if ((priv = MLKEM_private_key_new(rank)) == NULL) | ||
| 107 | errx(1, "malloc"); | ||
| 108 | if ((pub = MLKEM_public_key_new(rank)) == NULL) | ||
| 109 | errx(1, "malloc"); | ||
| 106 | 110 | ||
| 107 | /* | 111 | /* |
| 108 | * This should draw both d and z from DRNG concatenating in | 112 | * This should draw both d and z from DRNG concatenating in |
| @@ -110,120 +114,91 @@ MlkemIterativeTest(struct iteration_ctx *ctx) | |||
| 110 | */ | 114 | */ |
| 111 | shake_out(&drng, seed, sizeof(seed)); | 115 | shake_out(&drng, seed, sizeof(seed)); |
| 112 | if (i == 0) { | 116 | if (i == 0) { |
| 113 | if (compare_data(seed, ctx->start, ctx->start_len, | 117 | if (compare_data(seed, start, start_len, |
| 114 | "seed start") != 0) | 118 | "seed start") != 0) |
| 115 | errx(1, "compare_data"); | 119 | errx(1, "compare_data"); |
| 116 | } | 120 | } |
| 117 | 121 | ||
| 118 | /* generate ek as encoded_public_key */ | 122 | /* generate ek as encoded_public_key */ |
| 119 | if (!ctx->generate_key_external_entropy(ctx->encoded_public_key, | 123 | if (!MLKEM_generate_key_external_entropy(priv, |
| 120 | ctx->priv, seed)) { | 124 | &encoded_public_key, &encoded_public_key_len, |
| 125 | seed)) | ||
| 121 | errx(1, "generate_key_external_entropy"); | 126 | errx(1, "generate_key_external_entropy"); |
| 122 | } | 127 | |
| 123 | ctx->public_from_private(ctx->pub, ctx->priv); | 128 | if (!MLKEM_public_from_private(priv, pub)) |
| 129 | errx(1, "public_from_private"); | ||
| 124 | 130 | ||
| 125 | /* hash in ek */ | 131 | /* hash in ek */ |
| 126 | shake_update(&results, ctx->encoded_public_key, | 132 | shake_update(&results, encoded_public_key, |
| 127 | ctx->encoded_public_key_len); | 133 | encoded_public_key_len); |
| 128 | 134 | ||
| 129 | /* marshal priv to dk as encoded_private_key */ | 135 | /* marshal priv to dk as encoded_private_key */ |
| 130 | if (!ctx->marshal_private_key(ctx->priv, &encoded_private_key, | 136 | if (!MLKEM_marshal_private_key(priv, &encoded_private_key, |
| 131 | &encoded_private_key_len)) | 137 | &encoded_private_key_len)) |
| 132 | errx(1, "encode private key"); | 138 | errx(1, "marshal private key"); |
| 133 | 139 | ||
| 134 | /* hash in dk */ | 140 | /* hash in dk */ |
| 135 | shake_update(&results, encoded_private_key, | 141 | shake_update(&results, encoded_private_key, |
| 136 | encoded_private_key_len); | 142 | encoded_private_key_len); |
| 137 | 143 | ||
| 138 | free(encoded_private_key); | 144 | freezero(encoded_private_key, encoded_private_key_len); |
| 139 | 145 | ||
| 140 | /* draw m as encap entropy from DRNG */ | 146 | /* draw m as encap entropy from DRNG */ |
| 141 | shake_out(&drng, encap_entropy, sizeof(encap_entropy)); | 147 | shake_out(&drng, encap_entropy, sizeof(encap_entropy)); |
| 142 | 148 | ||
| 143 | /* generate ct as ciphertext, k as shared_secret */ | 149 | /* generate ct as ciphertext, k as shared_secret */ |
| 144 | ctx->encap_external_entropy(ctx->ciphertext, shared_secret, | 150 | if (!MLKEM_encap_external_entropy(pub, encap_entropy, |
| 145 | ctx->pub, encap_entropy); | 151 | &ciphertext, &ciphertext_len, &shared_secret, &s_len)) |
| 152 | errx(1, "encap_external_entropy"); | ||
| 146 | 153 | ||
| 147 | /* hash in ct */ | 154 | /* hash in ct */ |
| 148 | shake_update(&results, ctx->ciphertext, ctx->ciphertext_len); | 155 | shake_update(&results, ciphertext, ciphertext_len); |
| 149 | /* hash in k */ | 156 | /* hash in k */ |
| 150 | shake_update(&results, shared_secret, sizeof(shared_secret)); | 157 | shake_update(&results, shared_secret, s_len); |
| 158 | |||
| 159 | freezero(shared_secret, s_len); | ||
| 160 | shared_secret = NULL; | ||
| 161 | |||
| 162 | invalid_ciphertext_len = ciphertext_len; | ||
| 163 | if ((invalid_ciphertext = calloc(1, invalid_ciphertext_len)) | ||
| 164 | == NULL) | ||
| 165 | errx(1, "malloc"); | ||
| 151 | 166 | ||
| 152 | /* draw ct as invalid_ciphertxt from DRNG */ | 167 | /* draw ct as invalid_ciphertxt from DRNG */ |
| 153 | shake_out(&drng, ctx->invalid_ciphertext, | 168 | shake_out(&drng, invalid_ciphertext, invalid_ciphertext_len); |
| 154 | ctx->invalid_ciphertext_len); | ||
| 155 | 169 | ||
| 156 | /* generate k as shared secret from invalid ciphertext */ | 170 | /* generate k as shared secret from invalid ciphertext */ |
| 157 | if (!ctx->decap(shared_secret, ctx->invalid_ciphertext, | 171 | if (!MLKEM_decap(priv, invalid_ciphertext, |
| 158 | ctx->invalid_ciphertext_len, ctx->priv)) | 172 | invalid_ciphertext_len, &shared_secret, &s_len)) |
| 159 | errx(1, "decap failed"); | 173 | errx(1, "decap failed, iteration %d", i); |
| 160 | 174 | ||
| 161 | /* hash in k */ | 175 | /* hash in k */ |
| 162 | shake_update(&results, shared_secret, sizeof(shared_secret)); | 176 | shake_update(&results, shared_secret, s_len); |
| 177 | |||
| 178 | freezero(shared_secret, s_len); | ||
| 179 | shared_secret = NULL; | ||
| 180 | freezero(invalid_ciphertext, invalid_ciphertext_len); | ||
| 181 | invalid_ciphertext = NULL; | ||
| 182 | |||
| 183 | /* free keys and intermediate products for this iteration */ | ||
| 184 | MLKEM_private_key_free(priv); | ||
| 185 | MLKEM_public_key_free(pub); | ||
| 186 | freezero(encoded_public_key, encoded_public_key_len); | ||
| 187 | freezero(ciphertext, ciphertext_len); | ||
| 163 | } | 188 | } |
| 164 | shake_xof(&results); | 189 | shake_xof(&results); |
| 165 | shake_out(&results, out, sizeof(out)); | 190 | shake_out(&results, out, sizeof(out)); |
| 166 | 191 | ||
| 167 | return compare_data(ctx->expected, out, sizeof(out), "final result hash"); | 192 | return compare_data(expected, out, sizeof(out), "final result hash"); |
| 168 | } | 193 | } |
| 169 | 194 | ||
| 170 | int | 195 | int |
| 171 | main(void) | 196 | main(void) |
| 172 | { | 197 | { |
| 173 | uint8_t encoded_public_key768[MLKEM768_PUBLIC_KEY_BYTES]; | ||
| 174 | uint8_t ciphertext768[MLKEM768_CIPHERTEXT_BYTES]; | ||
| 175 | uint8_t invalid_ciphertext768[MLKEM768_CIPHERTEXT_BYTES]; | ||
| 176 | struct MLKEM768_private_key priv768; | ||
| 177 | struct MLKEM768_public_key pub768; | ||
| 178 | struct iteration_ctx iteration768 = { | ||
| 179 | .encoded_public_key = encoded_public_key768, | ||
| 180 | .encoded_public_key_len = sizeof(encoded_public_key768), | ||
| 181 | .ciphertext = ciphertext768, | ||
| 182 | .ciphertext_len = sizeof(ciphertext768), | ||
| 183 | .invalid_ciphertext = invalid_ciphertext768, | ||
| 184 | .invalid_ciphertext_len = sizeof(invalid_ciphertext768), | ||
| 185 | .priv = &priv768, | ||
| 186 | .pub = &pub768, | ||
| 187 | .encap_external_entropy = mlkem768_encap_external_entropy, | ||
| 188 | .marshal_private_key = mlkem768_marshal_private_key, | ||
| 189 | .generate_key_external_entropy = | ||
| 190 | mlkem768_generate_key_external_entropy, | ||
| 191 | .public_from_private = mlkem768_public_from_private, | ||
| 192 | .decap = mlkem768_decap, | ||
| 193 | .start = kExpectedSeedStart, | ||
| 194 | .start_len = sizeof(kExpectedSeedStart), | ||
| 195 | .expected = kExpectedAdam768, | ||
| 196 | .expected_len = sizeof(kExpectedAdam768), | ||
| 197 | }; | ||
| 198 | uint8_t encoded_public_key1024[MLKEM1024_PUBLIC_KEY_BYTES]; | ||
| 199 | uint8_t ciphertext1024[MLKEM1024_CIPHERTEXT_BYTES]; | ||
| 200 | uint8_t invalid_ciphertext1024[MLKEM1024_CIPHERTEXT_BYTES]; | ||
| 201 | struct MLKEM1024_private_key priv1024; | ||
| 202 | struct MLKEM1024_public_key pub1024; | ||
| 203 | struct iteration_ctx iteration1024 = { | ||
| 204 | .encoded_public_key = encoded_public_key1024, | ||
| 205 | .encoded_public_key_len = sizeof(encoded_public_key1024), | ||
| 206 | .ciphertext = ciphertext1024, | ||
| 207 | .ciphertext_len = sizeof(ciphertext1024), | ||
| 208 | .invalid_ciphertext = invalid_ciphertext1024, | ||
| 209 | .invalid_ciphertext_len = sizeof(invalid_ciphertext1024), | ||
| 210 | .priv = &priv1024, | ||
| 211 | .pub = &pub1024, | ||
| 212 | .encap_external_entropy = mlkem1024_encap_external_entropy, | ||
| 213 | .marshal_private_key = mlkem1024_marshal_private_key, | ||
| 214 | .generate_key_external_entropy = | ||
| 215 | mlkem1024_generate_key_external_entropy, | ||
| 216 | .public_from_private = mlkem1024_public_from_private, | ||
| 217 | .decap = mlkem1024_decap, | ||
| 218 | .start = kExpectedSeedStart, | ||
| 219 | .start_len = sizeof(kExpectedSeedStart), | ||
| 220 | .expected = kExpectedAdam1024, | ||
| 221 | .expected_len = sizeof(kExpectedAdam1024), | ||
| 222 | }; | ||
| 223 | int failed = 0; | 198 | int failed = 0; |
| 224 | 199 | ||
| 225 | failed |= MlkemIterativeTest(&iteration768); | 200 | failed |= MlkemIterativeTest(RANK768); |
| 226 | failed |= MlkemIterativeTest(&iteration1024); | 201 | failed |= MlkemIterativeTest(RANK1024); |
| 227 | 202 | ||
| 228 | return failed; | 203 | return failed; |
| 229 | } | 204 | } |
diff --git a/src/regress/lib/libcrypto/mlkem/mlkem_tests.c b/src/regress/lib/libcrypto/mlkem/mlkem_tests.c index 8e04dc6ad2..3269ba951f 100644 --- a/src/regress/lib/libcrypto/mlkem/mlkem_tests.c +++ b/src/regress/lib/libcrypto/mlkem/mlkem_tests.c | |||
| @@ -1,4 +1,4 @@ | |||
| 1 | /* $OpenBSD: mlkem_tests.c,v 1.6 2025/05/20 00:33:41 beck Exp $ */ | 1 | /* $OpenBSD: mlkem_tests.c,v 1.7 2025/08/14 15:48:48 beck Exp $ */ |
| 2 | /* | 2 | /* |
| 3 | * Copyright (c) 2024 Google Inc. | 3 | * Copyright (c) 2024 Google Inc. |
| 4 | * Copyright (c) 2024 Theo Buehler <tb@openbsd.org> | 4 | * Copyright (c) 2024 Theo Buehler <tb@openbsd.org> |
| @@ -38,12 +38,8 @@ enum test_type { | |||
| 38 | 38 | ||
| 39 | struct decap_ctx { | 39 | struct decap_ctx { |
| 40 | struct parse *parse_ctx; | 40 | struct parse *parse_ctx; |
| 41 | 41 | int rank; | |
| 42 | void *private_key; | 42 | MLKEM_private_key *private_key; |
| 43 | size_t private_key_len; | ||
| 44 | |||
| 45 | mlkem_parse_private_key_fn parse_private_key; | ||
| 46 | mlkem_decap_fn decap; | ||
| 47 | }; | 43 | }; |
| 48 | 44 | ||
| 49 | enum decap_states { | 45 | enum decap_states { |
| @@ -89,21 +85,26 @@ decap_init(void *ctx, void *parse_ctx) | |||
| 89 | 85 | ||
| 90 | decap->parse_ctx = parse_ctx; | 86 | decap->parse_ctx = parse_ctx; |
| 91 | 87 | ||
| 92 | return 1; | 88 | return (decap->private_key = MLKEM_private_key_new(decap->rank)) |
| 89 | != NULL; | ||
| 93 | } | 90 | } |
| 94 | 91 | ||
| 95 | static void | 92 | static void |
| 96 | decap_finish(void *ctx) | 93 | decap_finish(void *ctx) |
| 97 | { | 94 | { |
| 98 | (void)ctx; | 95 | struct decap_ctx *decap = ctx; |
| 96 | |||
| 97 | MLKEM_private_key_free(decap->private_key); | ||
| 98 | decap->private_key = NULL; | ||
| 99 | } | 99 | } |
| 100 | 100 | ||
| 101 | static int | 101 | static int |
| 102 | MlkemDecapFileTest(struct decap_ctx *decap) | 102 | MlkemDecapFileTest(struct decap_ctx *decap) |
| 103 | { | 103 | { |
| 104 | struct parse *p = decap->parse_ctx; | 104 | struct parse *p = decap->parse_ctx; |
| 105 | uint8_t shared_secret_buf[MLKEM_SHARED_SECRET_BYTES]; | 105 | uint8_t *shared_secret_buf = NULL; |
| 106 | CBS ciphertext, shared_secret, private_key; | 106 | CBS ciphertext, shared_secret, private_key; |
| 107 | size_t s_len = 0; | ||
| 107 | int should_fail; | 108 | int should_fail; |
| 108 | int failed = 1; | 109 | int failed = 1; |
| 109 | 110 | ||
| @@ -112,21 +113,28 @@ MlkemDecapFileTest(struct decap_ctx *decap) | |||
| 112 | parse_get_cbs(p, DECAP_PRIVATE_KEY, &private_key); | 113 | parse_get_cbs(p, DECAP_PRIVATE_KEY, &private_key); |
| 113 | parse_get_int(p, DECAP_RESULT, &should_fail); | 114 | parse_get_int(p, DECAP_RESULT, &should_fail); |
| 114 | 115 | ||
| 115 | if (!decap->parse_private_key(decap->private_key, | 116 | if (!MLKEM_parse_private_key(decap->private_key, |
| 116 | CBS_data(&private_key), CBS_len(&private_key))) { | 117 | CBS_data(&private_key), CBS_len(&private_key))) { |
| 117 | if ((failed = !should_fail)) | 118 | if ((failed = !should_fail)) |
| 118 | parse_info(p, "parse private key"); | 119 | parse_info(p, "parse private key"); |
| 119 | goto err; | 120 | goto err; |
| 120 | } | 121 | } |
| 121 | if (!decap->decap(shared_secret_buf, | 122 | if (!MLKEM_decap(decap->private_key, CBS_data(&ciphertext), |
| 122 | CBS_data(&ciphertext), CBS_len(&ciphertext), decap->private_key)) { | 123 | CBS_len(&ciphertext), &shared_secret_buf, &s_len)) { |
| 123 | if ((failed = !should_fail)) | 124 | if ((failed = !should_fail)) |
| 124 | parse_info(p, "decap"); | 125 | parse_info(p, "decap"); |
| 125 | goto err; | 126 | goto err; |
| 126 | } | 127 | } |
| 127 | 128 | ||
| 129 | if (s_len != MLKEM_SHARED_SECRET_LENGTH) { | ||
| 130 | if ((failed = !should_fail)) | ||
| 131 | parse_info(p, "shared secret length %zu != %d", s_len, | ||
| 132 | MLKEM_SHARED_SECRET_LENGTH); | ||
| 133 | goto err; | ||
| 134 | } | ||
| 135 | |||
| 128 | failed = !parse_data_equal(p, "shared_secret", &shared_secret, | 136 | failed = !parse_data_equal(p, "shared_secret", &shared_secret, |
| 129 | shared_secret_buf, sizeof(shared_secret_buf)); | 137 | shared_secret_buf, s_len); |
| 130 | 138 | ||
| 131 | if (should_fail != failed) { | 139 | if (should_fail != failed) { |
| 132 | parse_info(p, "FAIL: should_fail %d, failed %d", | 140 | parse_info(p, "FAIL: should_fail %d, failed %d", |
| @@ -135,6 +143,7 @@ MlkemDecapFileTest(struct decap_ctx *decap) | |||
| 135 | } | 143 | } |
| 136 | 144 | ||
| 137 | err: | 145 | err: |
| 146 | freezero(shared_secret_buf, s_len); | ||
| 138 | return failed; | 147 | return failed; |
| 139 | } | 148 | } |
| 140 | 149 | ||
| @@ -193,8 +202,9 @@ static int | |||
| 193 | MlkemNistDecapFileTest(struct decap_ctx *decap) | 202 | MlkemNistDecapFileTest(struct decap_ctx *decap) |
| 194 | { | 203 | { |
| 195 | struct parse *p = decap->parse_ctx; | 204 | struct parse *p = decap->parse_ctx; |
| 196 | uint8_t shared_secret[MLKEM_SHARED_SECRET_BYTES]; | 205 | uint8_t *shared_secret = NULL; |
| 197 | CBS dk, c, k; | 206 | CBS dk, c, k; |
| 207 | size_t s_len = 0; | ||
| 198 | int failed = 1; | 208 | int failed = 1; |
| 199 | 209 | ||
| 200 | parse_instruction_get_cbs(p, NIST_DECAP_DK, &dk); | 210 | parse_instruction_get_cbs(p, NIST_DECAP_DK, &dk); |
| @@ -202,27 +212,34 @@ MlkemNistDecapFileTest(struct decap_ctx *decap) | |||
| 202 | parse_get_cbs(p, NIST_DECAP_K, &k); | 212 | parse_get_cbs(p, NIST_DECAP_K, &k); |
| 203 | 213 | ||
| 204 | if (!parse_length_equal(p, "private key", | 214 | if (!parse_length_equal(p, "private key", |
| 205 | decap->private_key_len, CBS_len(&dk))) | 215 | MLKEM_private_key_encoded_length(decap->private_key), CBS_len(&dk))) |
| 206 | goto err; | 216 | goto err; |
| 207 | if (!parse_length_equal(p, "shared secret", | 217 | if (!parse_length_equal(p, "shared secret", |
| 208 | MLKEM_SHARED_SECRET_BYTES, CBS_len(&k))) | 218 | MLKEM_SHARED_SECRET_BYTES, CBS_len(&k))) |
| 209 | goto err; | 219 | goto err; |
| 210 | 220 | ||
| 211 | if (!decap->parse_private_key(decap->private_key, CBS_data(&dk), | 221 | if (!MLKEM_parse_private_key(decap->private_key, CBS_data(&dk), |
| 212 | CBS_len(&dk))) { | 222 | CBS_len(&dk))) { |
| 213 | parse_info(p, "parse private key"); | 223 | parse_info(p, "parse private key"); |
| 214 | goto err; | 224 | goto err; |
| 215 | } | 225 | } |
| 216 | if (!decap->decap(shared_secret, CBS_data(&c), CBS_len(&c), | 226 | if (!MLKEM_decap(decap->private_key, CBS_data(&c), CBS_len(&c), |
| 217 | decap->private_key)) { | 227 | &shared_secret, &s_len)) { |
| 218 | parse_info(p, "decap"); | 228 | parse_info(p, "decap"); |
| 219 | goto err; | 229 | goto err; |
| 220 | } | 230 | } |
| 221 | 231 | ||
| 232 | if (s_len != MLKEM_SHARED_SECRET_LENGTH) { | ||
| 233 | parse_info(p, "shared secret length %zu != %d", s_len, | ||
| 234 | MLKEM_SHARED_SECRET_LENGTH); | ||
| 235 | goto err; | ||
| 236 | } | ||
| 237 | |||
| 222 | failed = !parse_data_equal(p, "shared secret", &k, | 238 | failed = !parse_data_equal(p, "shared secret", &k, |
| 223 | shared_secret, MLKEM_SHARED_SECRET_BYTES); | 239 | shared_secret, s_len); |
| 224 | 240 | ||
| 225 | err: | 241 | err: |
| 242 | free(shared_secret); | ||
| 226 | return failed; | 243 | return failed; |
| 227 | } | 244 | } |
| 228 | 245 | ||
| @@ -246,46 +263,31 @@ static const struct test_parse nist_decap_parse = { | |||
| 246 | }; | 263 | }; |
| 247 | 264 | ||
| 248 | static int | 265 | static int |
| 249 | mlkem_decap_tests(const char *fn, size_t size, enum test_type test_type) | 266 | mlkem_decap_tests(const char *fn, int rank, enum test_type test_type) |
| 250 | { | 267 | { |
| 251 | struct MLKEM768_private_key private_key768; | 268 | struct decap_ctx decap = { |
| 252 | struct decap_ctx decap768 = { | 269 | .rank = rank, |
| 253 | .private_key = &private_key768, | ||
| 254 | .private_key_len = MLKEM768_PRIVATE_KEY_BYTES, | ||
| 255 | |||
| 256 | .parse_private_key = mlkem768_parse_private_key, | ||
| 257 | .decap = mlkem768_decap, | ||
| 258 | }; | ||
| 259 | struct MLKEM1024_private_key private_key1024; | ||
| 260 | struct decap_ctx decap1024 = { | ||
| 261 | .private_key = &private_key1024, | ||
| 262 | .private_key_len = MLKEM1024_PRIVATE_KEY_BYTES, | ||
| 263 | |||
| 264 | .parse_private_key = mlkem1024_parse_private_key, | ||
| 265 | .decap = mlkem1024_decap, | ||
| 266 | }; | 270 | }; |
| 271 | int ret = 0; | ||
| 267 | 272 | ||
| 268 | if (size == 768 && test_type == TEST_TYPE_NORMAL) | 273 | if (test_type == TEST_TYPE_NORMAL) |
| 269 | return parse_test_file(fn, &decap_parse, &decap768); | 274 | ret = parse_test_file(fn, &decap_parse, &decap); |
| 270 | if (size == 768 && test_type == TEST_TYPE_NIST) | 275 | else if (test_type == TEST_TYPE_NIST) |
| 271 | return parse_test_file(fn, &nist_decap_parse, &decap768); | 276 | ret = parse_test_file(fn, &nist_decap_parse, &decap); |
| 272 | if (size == 1024 && test_type == TEST_TYPE_NORMAL) | 277 | else |
| 273 | return parse_test_file(fn, &decap_parse, &decap1024); | 278 | errx(1, "unknown decap test: rank %d, type %d", rank, |
| 274 | if (size == 1024 && test_type == TEST_TYPE_NIST) | 279 | test_type); |
| 275 | return parse_test_file(fn, &nist_decap_parse, &decap1024); | ||
| 276 | 280 | ||
| 277 | errx(1, "unknown decap test: size %zu, type %d", size, test_type); | 281 | return ret; |
| 278 | } | 282 | } |
| 279 | 283 | ||
| 280 | struct encap_ctx { | 284 | struct encap_ctx { |
| 281 | struct parse *parse_ctx; | 285 | struct parse *parse_ctx; |
| 282 | 286 | ||
| 283 | void *public_key; | 287 | int rank; |
| 288 | MLKEM_public_key *public_key; | ||
| 284 | uint8_t *ciphertext; | 289 | uint8_t *ciphertext; |
| 285 | size_t ciphertext_len; | 290 | size_t ciphertext_len; |
| 286 | |||
| 287 | mlkem_parse_public_key_fn parse_public_key; | ||
| 288 | mlkem_encap_external_entropy_fn encap_external_entropy; | ||
| 289 | }; | 291 | }; |
| 290 | 292 | ||
| 291 | enum encap_states { | 293 | enum encap_states { |
| @@ -338,21 +340,30 @@ encap_init(void *ctx, void *parse_ctx) | |||
| 338 | 340 | ||
| 339 | encap->parse_ctx = parse_ctx; | 341 | encap->parse_ctx = parse_ctx; |
| 340 | 342 | ||
| 341 | return 1; | 343 | encap->ciphertext = NULL; |
| 344 | return (encap->public_key = MLKEM_public_key_new(encap->rank)) | ||
| 345 | != NULL; | ||
| 342 | } | 346 | } |
| 343 | 347 | ||
| 344 | static void | 348 | static void |
| 345 | encap_finish(void *ctx) | 349 | encap_finish(void *ctx) |
| 346 | { | 350 | { |
| 347 | (void)ctx; | 351 | struct encap_ctx *encap = ctx; |
| 352 | |||
| 353 | freezero(encap->ciphertext, encap->ciphertext_len); | ||
| 354 | encap->ciphertext = NULL; | ||
| 355 | MLKEM_public_key_free(encap->public_key); | ||
| 356 | encap->public_key = NULL; | ||
| 348 | } | 357 | } |
| 349 | 358 | ||
| 350 | static int | 359 | static int |
| 351 | MlkemEncapFileTest(struct encap_ctx *encap) | 360 | MlkemEncapFileTest(struct encap_ctx *encap) |
| 352 | { | 361 | { |
| 353 | struct parse *p = encap->parse_ctx; | ||
| 354 | uint8_t shared_secret_buf[MLKEM_SHARED_SECRET_BYTES]; | ||
| 355 | CBS entropy, public_key, ciphertext, shared_secret; | 362 | CBS entropy, public_key, ciphertext, shared_secret; |
| 363 | struct parse *p = encap->parse_ctx; | ||
| 364 | uint8_t *shared_secret_buf = NULL; | ||
| 365 | size_t s_len = 0; | ||
| 366 | |||
| 356 | int should_fail; | 367 | int should_fail; |
| 357 | int failed = 1; | 368 | int failed = 1; |
| 358 | 369 | ||
| @@ -362,20 +373,33 @@ MlkemEncapFileTest(struct encap_ctx *encap) | |||
| 362 | parse_get_cbs(p, ENCAP_SHARED_SECRET, &shared_secret); | 373 | parse_get_cbs(p, ENCAP_SHARED_SECRET, &shared_secret); |
| 363 | parse_get_int(p, ENCAP_RESULT, &should_fail); | 374 | parse_get_int(p, ENCAP_RESULT, &should_fail); |
| 364 | 375 | ||
| 365 | if (!encap->parse_public_key(encap->public_key, CBS_data(&public_key), | 376 | if (!MLKEM_parse_public_key(encap->public_key, CBS_data(&public_key), |
| 366 | CBS_len(&public_key))) { | 377 | CBS_len(&public_key))) { |
| 367 | if ((failed = !should_fail)) | 378 | if ((failed = !should_fail)) |
| 368 | parse_info(p, "parse public key"); | 379 | parse_info(p, "parse public key"); |
| 369 | goto err; | 380 | goto err; |
| 370 | } | 381 | } |
| 371 | encap->encap_external_entropy(encap->ciphertext, shared_secret_buf, | 382 | if (!MLKEM_encap_external_entropy(encap->public_key, CBS_data(&entropy), |
| 372 | encap->public_key, CBS_data(&entropy)); | 383 | &encap->ciphertext, &encap->ciphertext_len, &shared_secret_buf, |
| 384 | &s_len)) { | ||
| 385 | if ((failed = !should_fail)) | ||
| 386 | parse_info(p, "encap_external_entropy"); | ||
| 387 | goto err; | ||
| 388 | } | ||
| 389 | |||
| 390 | if (s_len != MLKEM_SHARED_SECRET_LENGTH) { | ||
| 391 | if ((failed = !should_fail)) | ||
| 392 | parse_info(p, "shared secret length %zu != %d", s_len, | ||
| 393 | MLKEM_SHARED_SECRET_LENGTH); | ||
| 394 | goto err; | ||
| 395 | } | ||
| 373 | 396 | ||
| 374 | failed = !parse_data_equal(p, "shared_secret", &shared_secret, | 397 | failed = !parse_data_equal(p, "shared_secret", &shared_secret, |
| 375 | shared_secret_buf, sizeof(shared_secret_buf)); | 398 | shared_secret_buf, s_len); |
| 376 | failed |= !parse_data_equal(p, "ciphertext", &ciphertext, | 399 | failed |= !parse_data_equal(p, "ciphertext", &ciphertext, |
| 377 | encap->ciphertext, encap->ciphertext_len); | 400 | encap->ciphertext, encap->ciphertext_len); |
| 378 | 401 | ||
| 402 | |||
| 379 | if (should_fail != failed) { | 403 | if (should_fail != failed) { |
| 380 | parse_info(p, "FAIL: should_fail %d, failed %d", | 404 | parse_info(p, "FAIL: should_fail %d, failed %d", |
| 381 | should_fail, failed); | 405 | should_fail, failed); |
| @@ -383,6 +407,7 @@ MlkemEncapFileTest(struct encap_ctx *encap) | |||
| 383 | } | 407 | } |
| 384 | 408 | ||
| 385 | err: | 409 | err: |
| 410 | freezero(shared_secret_buf, s_len); | ||
| 386 | return failed; | 411 | return failed; |
| 387 | } | 412 | } |
| 388 | 413 | ||
| @@ -403,48 +428,22 @@ static const struct test_parse encap_parse = { | |||
| 403 | }; | 428 | }; |
| 404 | 429 | ||
| 405 | static int | 430 | static int |
| 406 | mlkem_encap_tests(const char *fn, size_t size) | 431 | mlkem_encap_tests(const char *fn, int rank) |
| 407 | { | 432 | { |
| 408 | struct MLKEM768_public_key public_key768; | 433 | struct encap_ctx encap = { |
| 409 | uint8_t ciphertext768[MLKEM768_CIPHERTEXT_BYTES]; | 434 | .rank = rank, |
| 410 | struct encap_ctx encap768 = { | ||
| 411 | .public_key = &public_key768, | ||
| 412 | .ciphertext = ciphertext768, | ||
| 413 | .ciphertext_len = sizeof(ciphertext768), | ||
| 414 | |||
| 415 | .parse_public_key = mlkem768_parse_public_key, | ||
| 416 | .encap_external_entropy = mlkem768_encap_external_entropy, | ||
| 417 | }; | ||
| 418 | struct MLKEM1024_public_key public_key1024; | ||
| 419 | uint8_t ciphertext1024[MLKEM1024_CIPHERTEXT_BYTES]; | ||
| 420 | struct encap_ctx encap1024 = { | ||
| 421 | .public_key = &public_key1024, | ||
| 422 | .ciphertext = ciphertext1024, | ||
| 423 | .ciphertext_len = sizeof(ciphertext1024), | ||
| 424 | |||
| 425 | .parse_public_key = mlkem1024_parse_public_key, | ||
| 426 | .encap_external_entropy = mlkem1024_encap_external_entropy, | ||
| 427 | }; | 435 | }; |
| 428 | 436 | ||
| 429 | if (size == 768) | 437 | return parse_test_file(fn, &encap_parse, &encap); |
| 430 | return parse_test_file(fn, &encap_parse, &encap768); | ||
| 431 | if (size == 1024) | ||
| 432 | return parse_test_file(fn, &encap_parse, &encap1024); | ||
| 433 | |||
| 434 | errx(1, "unknown encap test: size %zu", size); | ||
| 435 | } | 438 | } |
| 436 | 439 | ||
| 437 | struct keygen_ctx { | 440 | struct keygen_ctx { |
| 438 | struct parse *parse_ctx; | 441 | struct parse *parse_ctx; |
| 439 | 442 | ||
| 440 | void *private_key; | 443 | int rank; |
| 441 | void *encoded_public_key; | 444 | MLKEM_private_key *private_key; |
| 445 | uint8_t *encoded_public_key; | ||
| 442 | size_t encoded_public_key_len; | 446 | size_t encoded_public_key_len; |
| 443 | size_t private_key_len; | ||
| 444 | size_t public_key_len; | ||
| 445 | |||
| 446 | mlkem_generate_key_external_entropy_fn generate_key_external_entropy; | ||
| 447 | mlkem_marshal_private_key_fn marshal_private_key; | ||
| 448 | }; | 447 | }; |
| 449 | 448 | ||
| 450 | enum keygen_states { | 449 | enum keygen_states { |
| @@ -482,13 +481,19 @@ keygen_init(void *ctx, void *parse_ctx) | |||
| 482 | 481 | ||
| 483 | keygen->parse_ctx = parse_ctx; | 482 | keygen->parse_ctx = parse_ctx; |
| 484 | 483 | ||
| 485 | return 1; | 484 | return (keygen->private_key = MLKEM_private_key_new(keygen->rank)) |
| 485 | != NULL; | ||
| 486 | } | 486 | } |
| 487 | 487 | ||
| 488 | static void | 488 | static void |
| 489 | keygen_finish(void *ctx) | 489 | keygen_finish(void *ctx) |
| 490 | { | 490 | { |
| 491 | (void)ctx; | 491 | struct keygen_ctx *keygen = ctx; |
| 492 | |||
| 493 | freezero(keygen->encoded_public_key, keygen->encoded_public_key_len); | ||
| 494 | keygen->encoded_public_key = NULL; | ||
| 495 | MLKEM_private_key_free(keygen->private_key); | ||
| 496 | keygen->private_key = NULL; | ||
| 492 | } | 497 | } |
| 493 | 498 | ||
| 494 | static int | 499 | static int |
| @@ -504,18 +509,25 @@ MlkemKeygenFileTest(struct keygen_ctx *keygen) | |||
| 504 | parse_get_cbs(p, KEYGEN_PUBLIC_KEY, &public_key); | 509 | parse_get_cbs(p, KEYGEN_PUBLIC_KEY, &public_key); |
| 505 | parse_get_cbs(p, KEYGEN_PRIVATE_KEY, &private_key); | 510 | parse_get_cbs(p, KEYGEN_PRIVATE_KEY, &private_key); |
| 506 | 511 | ||
| 507 | if (!parse_length_equal(p, "seed", MLKEM_SEED_BYTES, CBS_len(&seed))) | 512 | if (!parse_length_equal(p, "seed", MLKEM_SEED_LENGTH, CBS_len(&seed))) |
| 508 | goto err; | 513 | goto err; |
| 514 | |||
| 515 | if (!MLKEM_generate_key_external_entropy(keygen->private_key, | ||
| 516 | &keygen->encoded_public_key, &keygen->encoded_public_key_len, | ||
| 517 | CBS_data(&seed))) { | ||
| 518 | parse_info(p, "generate_key_external_entropy"); | ||
| 519 | goto err; | ||
| 520 | } | ||
| 521 | |||
| 509 | if (!parse_length_equal(p, "public key", | 522 | if (!parse_length_equal(p, "public key", |
| 510 | keygen->public_key_len, CBS_len(&public_key))) | 523 | keygen->encoded_public_key_len, CBS_len(&public_key))) |
| 511 | goto err; | 524 | goto err; |
| 512 | if (!parse_length_equal(p, "private key", | 525 | if (!parse_length_equal(p, "private key", |
| 513 | keygen->private_key_len, CBS_len(&private_key))) | 526 | MLKEM_private_key_encoded_length(keygen->private_key), |
| 527 | CBS_len(&private_key))) | ||
| 514 | goto err; | 528 | goto err; |
| 515 | 529 | ||
| 516 | keygen->generate_key_external_entropy(keygen->encoded_public_key, | 530 | if (!MLKEM_marshal_private_key(keygen->private_key, |
| 517 | keygen->private_key, CBS_data(&seed)); | ||
| 518 | if (!keygen->marshal_private_key(keygen->private_key, | ||
| 519 | &encoded_private_key, &encoded_private_key_len)) { | 531 | &encoded_private_key, &encoded_private_key_len)) { |
| 520 | parse_info(p, "encode private key"); | 532 | parse_info(p, "encode private key"); |
| 521 | goto err; | 533 | goto err; |
| @@ -589,7 +601,7 @@ MlkemNistKeygenFileTest(struct keygen_ctx *keygen) | |||
| 589 | struct parse *p = keygen->parse_ctx; | 601 | struct parse *p = keygen->parse_ctx; |
| 590 | CBB seed_cbb; | 602 | CBB seed_cbb; |
| 591 | CBS z, d, ek, dk; | 603 | CBS z, d, ek, dk; |
| 592 | uint8_t seed[MLKEM_SEED_BYTES]; | 604 | uint8_t seed[MLKEM_SEED_LENGTH]; |
| 593 | size_t seed_len; | 605 | size_t seed_len; |
| 594 | uint8_t *encoded_private_key = NULL; | 606 | uint8_t *encoded_private_key = NULL; |
| 595 | size_t encoded_private_key_len = 0; | 607 | size_t encoded_private_key_len = 0; |
| @@ -609,12 +621,17 @@ MlkemNistKeygenFileTest(struct keygen_ctx *keygen) | |||
| 609 | if (!CBB_finish(&seed_cbb, NULL, &seed_len)) | 621 | if (!CBB_finish(&seed_cbb, NULL, &seed_len)) |
| 610 | parse_errx(p, "CBB_finish"); | 622 | parse_errx(p, "CBB_finish"); |
| 611 | 623 | ||
| 612 | if (!parse_length_equal(p, "bogus z or d", MLKEM_SEED_BYTES, seed_len)) | 624 | if (!parse_length_equal(p, "bogus z or d", MLKEM_SEED_LENGTH, seed_len)) |
| 613 | goto err; | 625 | goto err; |
| 614 | 626 | ||
| 615 | keygen->generate_key_external_entropy(keygen->encoded_public_key, | 627 | if (!MLKEM_generate_key_external_entropy(keygen->private_key, |
| 616 | keygen->private_key, seed); | 628 | &keygen->encoded_public_key, &keygen->encoded_public_key_len, |
| 617 | if (!keygen->marshal_private_key(keygen->private_key, | 629 | seed)) { |
| 630 | parse_info(p, "generate_key_external_entropy"); | ||
| 631 | goto err; | ||
| 632 | } | ||
| 633 | |||
| 634 | if (!MLKEM_marshal_private_key(keygen->private_key, | ||
| 618 | &encoded_private_key, &encoded_private_key_len)) { | 635 | &encoded_private_key, &encoded_private_key_len)) { |
| 619 | parse_info(p, "encode private key"); | 636 | parse_info(p, "encode private key"); |
| 620 | goto err; | 637 | goto err; |
| @@ -648,74 +665,49 @@ static const struct test_parse nist_keygen_parse = { | |||
| 648 | }; | 665 | }; |
| 649 | 666 | ||
| 650 | static int | 667 | static int |
| 651 | mlkem_keygen_tests(const char *fn, size_t size, enum test_type test_type) | 668 | mlkem_keygen_tests(const char *fn, int rank, enum test_type test_type) |
| 652 | { | 669 | { |
| 653 | struct MLKEM768_private_key private_key768; | 670 | struct keygen_ctx keygen = { |
| 654 | uint8_t encoded_public_key768[MLKEM768_PUBLIC_KEY_BYTES]; | 671 | .rank = rank, |
| 655 | struct keygen_ctx keygen768 = { | ||
| 656 | .private_key = &private_key768, | ||
| 657 | .encoded_public_key = encoded_public_key768, | ||
| 658 | .encoded_public_key_len = sizeof(encoded_public_key768), | ||
| 659 | .private_key_len = MLKEM768_PRIVATE_KEY_BYTES, | ||
| 660 | .public_key_len = MLKEM768_PUBLIC_KEY_BYTES, | ||
| 661 | |||
| 662 | .generate_key_external_entropy = | ||
| 663 | mlkem768_generate_key_external_entropy, | ||
| 664 | .marshal_private_key = | ||
| 665 | mlkem768_marshal_private_key, | ||
| 666 | }; | ||
| 667 | struct MLKEM1024_private_key private_key1024; | ||
| 668 | uint8_t encoded_public_key1024[MLKEM1024_PUBLIC_KEY_BYTES]; | ||
| 669 | struct keygen_ctx keygen1024 = { | ||
| 670 | .private_key = &private_key1024, | ||
| 671 | .encoded_public_key = encoded_public_key1024, | ||
| 672 | .encoded_public_key_len = sizeof(encoded_public_key1024), | ||
| 673 | .private_key_len = MLKEM1024_PRIVATE_KEY_BYTES, | ||
| 674 | .public_key_len = MLKEM1024_PUBLIC_KEY_BYTES, | ||
| 675 | |||
| 676 | .generate_key_external_entropy = | ||
| 677 | mlkem1024_generate_key_external_entropy, | ||
| 678 | .marshal_private_key = | ||
| 679 | mlkem1024_marshal_private_key, | ||
| 680 | }; | 672 | }; |
| 673 | int ret = 0; | ||
| 681 | 674 | ||
| 682 | if (size == 768 && test_type == TEST_TYPE_NORMAL) | 675 | if (test_type == TEST_TYPE_NORMAL) |
| 683 | return parse_test_file(fn, &keygen_parse, &keygen768); | 676 | ret = parse_test_file(fn, &keygen_parse, &keygen); |
| 684 | if (size == 768 && test_type == TEST_TYPE_NIST) | 677 | else if (test_type == TEST_TYPE_NIST) |
| 685 | return parse_test_file(fn, &nist_keygen_parse, &keygen768); | 678 | ret = parse_test_file(fn, &nist_keygen_parse, &keygen); |
| 686 | if (size == 1024 && test_type == TEST_TYPE_NORMAL) | 679 | else |
| 687 | return parse_test_file(fn, &keygen_parse, &keygen1024); | 680 | errx(1, "unknown keygen test: rank %d, type %d", rank, |
| 688 | if (size == 1024 && test_type == TEST_TYPE_NIST) | 681 | test_type); |
| 689 | return parse_test_file(fn, &nist_keygen_parse, &keygen1024); | ||
| 690 | 682 | ||
| 691 | errx(1, "unknown keygen test: size %zu, type %d", size, test_type); | 683 | return ret; |
| 692 | } | 684 | } |
| 693 | 685 | ||
| 694 | static int | 686 | static int |
| 695 | run_mlkem_test(const char *test, const char *fn) | 687 | run_mlkem_test(const char *test, const char *fn) |
| 696 | { | 688 | { |
| 697 | if (strcmp(test, "mlkem768_decap_tests") == 0) | 689 | if (strcmp(test, "mlkem768_decap_tests") == 0) |
| 698 | return mlkem_decap_tests(fn, 768, TEST_TYPE_NORMAL); | 690 | return mlkem_decap_tests(fn, RANK768, TEST_TYPE_NORMAL); |
| 699 | if (strcmp(test, "mlkem768_nist_decap_tests") == 0) | 691 | if (strcmp(test, "mlkem768_nist_decap_tests") == 0) |
| 700 | return mlkem_decap_tests(fn, 768, TEST_TYPE_NIST); | 692 | return mlkem_decap_tests(fn, RANK768, TEST_TYPE_NIST); |
| 701 | if (strcmp(test, "mlkem1024_decap_tests") == 0) | 693 | if (strcmp(test, "mlkem1024_decap_tests") == 0) |
| 702 | return mlkem_decap_tests(fn, 1024, TEST_TYPE_NORMAL); | 694 | return mlkem_decap_tests(fn, RANK1024, TEST_TYPE_NORMAL); |
| 703 | if (strcmp(test, "mlkem1024_nist_decap_tests") == 0) | 695 | if (strcmp(test, "mlkem1024_nist_decap_tests") == 0) |
| 704 | return mlkem_decap_tests(fn, 1024, TEST_TYPE_NIST); | 696 | return mlkem_decap_tests(fn, RANK1024, TEST_TYPE_NIST); |
| 705 | 697 | ||
| 706 | if (strcmp(test, "mlkem768_encap_tests") == 0) | 698 | if (strcmp(test, "mlkem768_encap_tests") == 0) |
| 707 | return mlkem_encap_tests(fn, 768); | 699 | return mlkem_encap_tests(fn, RANK768); |
| 708 | if (strcmp(test, "mlkem1024_encap_tests") == 0) | 700 | if (strcmp(test, "mlkem1024_encap_tests") == 0) |
| 709 | return mlkem_encap_tests(fn, 1024); | 701 | return mlkem_encap_tests(fn, RANK1024); |
| 710 | 702 | ||
| 711 | if (strcmp(test, "mlkem768_keygen_tests") == 0) | 703 | if (strcmp(test, "mlkem768_keygen_tests") == 0) |
| 712 | return mlkem_keygen_tests(fn, 768, TEST_TYPE_NORMAL); | 704 | return mlkem_keygen_tests(fn, RANK768, TEST_TYPE_NORMAL); |
| 713 | if (strcmp(test, "mlkem768_nist_keygen_tests") == 0) | 705 | if (strcmp(test, "mlkem768_nist_keygen_tests") == 0) |
| 714 | return mlkem_keygen_tests(fn, 768, TEST_TYPE_NIST); | 706 | return mlkem_keygen_tests(fn, RANK768, TEST_TYPE_NIST); |
| 715 | if (strcmp(test, "mlkem1024_keygen_tests") == 0) | 707 | if (strcmp(test, "mlkem1024_keygen_tests") == 0) |
| 716 | return mlkem_keygen_tests(fn, 1024, TEST_TYPE_NORMAL); | 708 | return mlkem_keygen_tests(fn, RANK1024, TEST_TYPE_NORMAL); |
| 717 | if (strcmp(test, "mlkem1024_nist_keygen_tests") == 0) | 709 | if (strcmp(test, "mlkem1024_nist_keygen_tests") == 0) |
| 718 | return mlkem_keygen_tests(fn, 1024, TEST_TYPE_NIST); | 710 | return mlkem_keygen_tests(fn, RANK1024, TEST_TYPE_NIST); |
| 719 | 711 | ||
| 720 | errx(1, "unknown test %s (test file %s)", test, fn); | 712 | errx(1, "unknown test %s (test file %s)", test, fn); |
| 721 | } | 713 | } |
diff --git a/src/regress/lib/libcrypto/mlkem/mlkem_tests_util.c b/src/regress/lib/libcrypto/mlkem/mlkem_tests_util.c index 68bd5d4871..9d6e604386 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.8 2025/05/20 00:33:41 beck Exp $ */ | 1 | /* $OpenBSD: mlkem_tests_util.c,v 1.9 2025/08/14 15:48:48 beck 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> |
| @@ -23,7 +23,7 @@ | |||
| 23 | #include <string.h> | 23 | #include <string.h> |
| 24 | 24 | ||
| 25 | #include "bytestring.h" | 25 | #include "bytestring.h" |
| 26 | #include "mlkem.h" | 26 | #include <openssl/mlkem.h> |
| 27 | 27 | ||
| 28 | #include "mlkem_internal.h" | 28 | #include "mlkem_internal.h" |
| 29 | 29 | ||
| @@ -59,157 +59,3 @@ compare_data(const uint8_t *want, const uint8_t *got, size_t len, const char *ms | |||
| 59 | 59 | ||
| 60 | return 1; | 60 | return 1; |
| 61 | } | 61 | } |
| 62 | |||
| 63 | int | ||
| 64 | mlkem768_marshal_private_key(const void *private_key, uint8_t **out_buf, | ||
| 65 | size_t *out_len) | ||
| 66 | { | ||
| 67 | return MLKEM768_marshal_private_key(private_key, out_buf, out_len); | ||
| 68 | } | ||
| 69 | |||
| 70 | int | ||
| 71 | mlkem768_marshal_public_key(const void *public_key, uint8_t **out_buf, | ||
| 72 | size_t *out_len) | ||
| 73 | { | ||
| 74 | return MLKEM768_marshal_public_key(out_buf, out_len, public_key); | ||
| 75 | } | ||
| 76 | |||
| 77 | int | ||
| 78 | mlkem1024_marshal_private_key(const void *private_key, uint8_t **out_buf, | ||
| 79 | size_t *out_len) | ||
| 80 | { | ||
| 81 | return MLKEM1024_marshal_private_key(private_key, out_buf, out_len); | ||
| 82 | } | ||
| 83 | |||
| 84 | int | ||
| 85 | mlkem1024_marshal_public_key(const void *public_key, uint8_t **out_buf, | ||
| 86 | size_t *out_len) | ||
| 87 | { | ||
| 88 | return MLKEM1024_marshal_public_key(out_buf, out_len, public_key); | ||
| 89 | } | ||
| 90 | |||
| 91 | int | ||
| 92 | mlkem768_decap(uint8_t out_shared_secret[MLKEM_SHARED_SECRET_BYTES], | ||
| 93 | const uint8_t *ciphertext, size_t ciphertext_len, const void *private_key) | ||
| 94 | { | ||
| 95 | return MLKEM768_decap(out_shared_secret, ciphertext, ciphertext_len, | ||
| 96 | private_key); | ||
| 97 | } | ||
| 98 | |||
| 99 | void | ||
| 100 | mlkem768_encap(uint8_t *out_ciphertext, | ||
| 101 | uint8_t out_shared_secret[MLKEM_SHARED_SECRET_BYTES], | ||
| 102 | const void *public_key) | ||
| 103 | { | ||
| 104 | MLKEM768_encap(out_ciphertext, out_shared_secret, public_key); | ||
| 105 | } | ||
| 106 | |||
| 107 | void | ||
| 108 | mlkem768_encap_external_entropy(uint8_t *out_ciphertext, | ||
| 109 | uint8_t out_shared_secret[MLKEM_SHARED_SECRET_BYTES], | ||
| 110 | const void *public_key, const uint8_t entropy[MLKEM_ENCAP_ENTROPY]) | ||
| 111 | { | ||
| 112 | MLKEM768_encap_external_entropy(out_ciphertext, out_shared_secret, | ||
| 113 | public_key, entropy); | ||
| 114 | } | ||
| 115 | |||
| 116 | int | ||
| 117 | mlkem768_generate_key(uint8_t *out_encoded_public_key, | ||
| 118 | uint8_t optional_out_seed[MLKEM_SEED_BYTES], void *out_private_key) | ||
| 119 | { | ||
| 120 | return MLKEM768_generate_key(out_encoded_public_key, optional_out_seed, | ||
| 121 | out_private_key); | ||
| 122 | } | ||
| 123 | |||
| 124 | int | ||
| 125 | mlkem768_generate_key_external_entropy(uint8_t *out_encoded_public_key, | ||
| 126 | void *out_private_key, const uint8_t entropy[MLKEM_SEED_BYTES]) | ||
| 127 | { | ||
| 128 | return MLKEM768_generate_key_external_entropy(out_encoded_public_key, | ||
| 129 | out_private_key, entropy); | ||
| 130 | } | ||
| 131 | |||
| 132 | int | ||
| 133 | mlkem768_parse_private_key(void *out_private_key, const uint8_t *private_key, | ||
| 134 | size_t private_key_len) | ||
| 135 | { | ||
| 136 | return MLKEM768_parse_private_key(out_private_key, private_key, | ||
| 137 | private_key_len); | ||
| 138 | } | ||
| 139 | |||
| 140 | int | ||
| 141 | mlkem768_parse_public_key(void *out_public_key, const uint8_t *public_key, | ||
| 142 | size_t public_key_len) | ||
| 143 | { | ||
| 144 | return MLKEM768_parse_public_key(out_public_key, public_key, | ||
| 145 | public_key_len); | ||
| 146 | } | ||
| 147 | |||
| 148 | void | ||
| 149 | mlkem768_public_from_private(void *out_public_key, const void *private_key) | ||
| 150 | { | ||
| 151 | MLKEM768_public_from_private(out_public_key, private_key); | ||
| 152 | } | ||
| 153 | |||
| 154 | int | ||
| 155 | mlkem1024_decap(uint8_t out_shared_secret[MLKEM_SHARED_SECRET_BYTES], | ||
| 156 | const uint8_t *ciphertext, size_t ciphertext_len, const void *private_key) | ||
| 157 | { | ||
| 158 | return MLKEM1024_decap(out_shared_secret, ciphertext, ciphertext_len, | ||
| 159 | private_key); | ||
| 160 | } | ||
| 161 | |||
| 162 | void | ||
| 163 | mlkem1024_encap(uint8_t *out_ciphertext, | ||
| 164 | uint8_t out_shared_secret[MLKEM_SHARED_SECRET_BYTES], | ||
| 165 | const void *public_key) | ||
| 166 | { | ||
| 167 | MLKEM1024_encap(out_ciphertext, out_shared_secret, public_key); | ||
| 168 | } | ||
| 169 | |||
| 170 | void | ||
| 171 | mlkem1024_encap_external_entropy(uint8_t *out_ciphertext, | ||
| 172 | uint8_t out_shared_secret[MLKEM_SHARED_SECRET_BYTES], | ||
| 173 | const void *public_key, const uint8_t entropy[MLKEM_ENCAP_ENTROPY]) | ||
| 174 | { | ||
| 175 | MLKEM1024_encap_external_entropy(out_ciphertext, out_shared_secret, | ||
| 176 | public_key, entropy); | ||
| 177 | } | ||
| 178 | |||
| 179 | int | ||
| 180 | mlkem1024_generate_key(uint8_t *out_encoded_public_key, | ||
| 181 | uint8_t optional_out_seed[MLKEM_SEED_BYTES], void *out_private_key) | ||
| 182 | { | ||
| 183 | return MLKEM1024_generate_key(out_encoded_public_key, optional_out_seed, | ||
| 184 | out_private_key); | ||
| 185 | } | ||
| 186 | |||
| 187 | int | ||
| 188 | mlkem1024_generate_key_external_entropy(uint8_t *out_encoded_public_key, | ||
| 189 | void *out_private_key, const uint8_t entropy[MLKEM_SEED_BYTES]) | ||
| 190 | { | ||
| 191 | return MLKEM1024_generate_key_external_entropy(out_encoded_public_key, | ||
| 192 | out_private_key, entropy); | ||
| 193 | } | ||
| 194 | |||
| 195 | int | ||
| 196 | mlkem1024_parse_private_key(void *out_private_key, const uint8_t *private_key, | ||
| 197 | size_t private_key_len) | ||
| 198 | { | ||
| 199 | return MLKEM1024_parse_private_key(out_private_key, private_key, | ||
| 200 | private_key_len); | ||
| 201 | } | ||
| 202 | |||
| 203 | void | ||
| 204 | mlkem1024_public_from_private(void *out_public_key, const void *private_key) | ||
| 205 | { | ||
| 206 | MLKEM1024_public_from_private(out_public_key, private_key); | ||
| 207 | } | ||
| 208 | |||
| 209 | int | ||
| 210 | mlkem1024_parse_public_key(void *out_public_key, const uint8_t *public_key, | ||
| 211 | size_t public_key_len) | ||
| 212 | { | ||
| 213 | return MLKEM1024_parse_public_key(out_public_key, public_key, | ||
| 214 | public_key_len); | ||
| 215 | } | ||
diff --git a/src/regress/lib/libcrypto/mlkem/mlkem_tests_util.h b/src/regress/lib/libcrypto/mlkem/mlkem_tests_util.h index 1235309f60..a2348c75f3 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.7 2025/05/20 00:33:41 beck Exp $ */ | 1 | /* $OpenBSD: mlkem_tests_util.h,v 1.8 2025/08/14 15:48:48 beck 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> |
| @@ -30,60 +30,4 @@ | |||
| 30 | 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, |
| 31 | const char *msg); | 31 | const char *msg); |
| 32 | 32 | ||
| 33 | int mlkem768_marshal_private_key(const void *priv, uint8_t **out_buf, | ||
| 34 | size_t *out_len); | ||
| 35 | int mlkem768_marshal_public_key(const void *pub, uint8_t **out_buf, | ||
| 36 | size_t *out_len); | ||
| 37 | int mlkem1024_marshal_private_key(const void *priv, uint8_t **out_buf, | ||
| 38 | size_t *out_len); | ||
| 39 | int mlkem1024_marshal_public_key(const void *pub, uint8_t **out_buf, | ||
| 40 | size_t *out_len); | ||
| 41 | |||
| 42 | int mlkem768_decap(uint8_t out_shared_secret[MLKEM_SHARED_SECRET_BYTES], | ||
| 43 | const uint8_t *ciphertext, size_t ciphertext_len, const void *priv); | ||
| 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 | int mlkem768_generate_key(uint8_t *out_encoded_public_key, | ||
| 50 | uint8_t optional_out_seed[MLKEM_SEED_BYTES], void *out_private_key); | ||
| 51 | int 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, const uint8_t *in, size_t in_len); | ||
| 54 | int mlkem768_parse_public_key(void *pub, const uint8_t *in, size_t in_len); | ||
| 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 | int mlkem1024_generate_key(uint8_t *out_encoded_public_key, | ||
| 65 | uint8_t optional_out_seed[MLKEM_SEED_BYTES], void *out_private_key); | ||
| 66 | int 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, const uint8_t *in, size_t in_len); | ||
| 69 | int mlkem1024_parse_public_key(void *pub, const uint8_t *in, size_t in_len); | ||
| 70 | void mlkem1024_public_from_private(void *out_public_key, const void *private_key); | ||
| 71 | |||
| 72 | typedef int (*mlkem_marshal_private_key_fn)(const void *, uint8_t **, size_t *); | ||
| 73 | typedef int (*mlkem_marshal_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 int (*mlkem_generate_key_fn)(uint8_t *, uint8_t *, void *); | ||
| 82 | typedef int (*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 *, const uint8_t *, size_t); | ||
| 85 | typedef int (*mlkem_parse_public_key_fn)(void *, const uint8_t *, size_t); | ||
| 86 | typedef void (*mlkem_public_from_private_fn)(void *out_public_key, | ||
| 87 | const void *private_key); | ||
| 88 | |||
| 89 | #endif /* MLKEM_TEST_UTIL_H */ | 33 | #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 adb1c47d8e..417d40555f 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.11 2025/05/21 03:46:20 tb Exp $ */ | 1 | /* $OpenBSD: mlkem_unittest.c,v 1.12 2025/08/14 15:48:48 beck 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,95 +27,161 @@ | |||
| 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_marshal_private_key_fn marshal_private_key; | ||
| 45 | mlkem_marshal_public_key_fn marshal_public_key; | ||
| 46 | mlkem_public_from_private_fn public_from_private; | ||
| 47 | }; | ||
| 48 | |||
| 49 | static int | 30 | static int |
| 50 | MlKemUnitTest(struct unittest_ctx *ctx) | 31 | MlKemUnitTest(int rank) |
| 51 | { | 32 | { |
| 52 | uint8_t shared_secret1[MLKEM_SHARED_SECRET_BYTES]; | 33 | MLKEM_private_key *priv = NULL, *priv2 = NULL, *priv3 = NULL; |
| 53 | uint8_t shared_secret2[MLKEM_SHARED_SECRET_BYTES]; | 34 | MLKEM_public_key *pub = NULL, *pub2 = NULL, *pub3 = NULL; |
| 35 | uint8_t *encoded_public_key = NULL, *ciphertext = NULL, | ||
| 36 | *shared_secret2 = NULL, *shared_secret1 = NULL, | ||
| 37 | *encoded_private_key = NULL, *tmp_buf = NULL, *seed_buf = NULL; | ||
| 38 | size_t encoded_public_key_len, ciphertext_len, | ||
| 39 | encoded_private_key_len, tmp_buf_len; | ||
| 54 | uint8_t first_two_bytes[2]; | 40 | uint8_t first_two_bytes[2]; |
| 55 | uint8_t *encoded_private_key = NULL, *tmp_buf = NULL; | 41 | size_t s_len = 0; |
| 56 | size_t encoded_private_key_len, tmp_buf_len; | ||
| 57 | int failed = 0; | 42 | int failed = 0; |
| 58 | 43 | ||
| 59 | if (!ctx->generate_key(ctx->encoded_public_key, NULL, ctx->priv)) { | 44 | if ((pub = MLKEM_public_key_new(rank)) == NULL) { |
| 45 | warnx("public_key_new"); | ||
| 46 | failed |= 1; | ||
| 47 | } | ||
| 48 | |||
| 49 | if ((pub2 = MLKEM_public_key_new(rank)) == NULL) { | ||
| 50 | warnx("public_key_new"); | ||
| 51 | failed |= 1; | ||
| 52 | } | ||
| 53 | |||
| 54 | if ((priv = MLKEM_private_key_new(rank)) == NULL) { | ||
| 55 | warnx("private_key_new"); | ||
| 56 | failed |= 1; | ||
| 57 | } | ||
| 58 | |||
| 59 | if ((priv2 = MLKEM_private_key_new(rank)) == NULL) { | ||
| 60 | warnx("private_key_new"); | ||
| 61 | failed |= 1; | ||
| 62 | } | ||
| 63 | |||
| 64 | if (!MLKEM_generate_key(priv, &encoded_public_key, | ||
| 65 | &encoded_public_key_len, &seed_buf, &s_len)) { | ||
| 60 | warnx("generate_key failed"); | 66 | warnx("generate_key failed"); |
| 61 | failed |= 1; | 67 | failed |= 1; |
| 62 | } | 68 | } |
| 63 | 69 | ||
| 64 | memcpy(first_two_bytes, ctx->encoded_public_key, sizeof(first_two_bytes)); | 70 | if (s_len != MLKEM_SEED_LENGTH) { |
| 65 | memset(ctx->encoded_public_key, 0xff, sizeof(first_two_bytes)); | 71 | warnx("seed length %zu != %d", s_len, MLKEM_SEED_LENGTH); |
| 72 | failed |= 1; | ||
| 73 | } | ||
| 74 | |||
| 75 | if ((priv3 = MLKEM_private_key_new(rank)) == NULL) { | ||
| 76 | warnx("private_key_new"); | ||
| 77 | failed |= 1; | ||
| 78 | } | ||
| 79 | |||
| 80 | if ((pub3 = MLKEM_public_key_new(rank)) == NULL) { | ||
| 81 | warnx("public_key_new"); | ||
| 82 | failed |= 1; | ||
| 83 | } | ||
| 84 | |||
| 85 | if (!MLKEM_private_key_from_seed(priv3, seed_buf, s_len)) { | ||
| 86 | warnx("private_key_from_seed failed"); | ||
| 87 | failed |= 1; | ||
| 88 | } | ||
| 89 | |||
| 90 | free(seed_buf); | ||
| 91 | seed_buf = NULL; | ||
| 92 | |||
| 93 | if (!MLKEM_public_from_private(priv3, pub3)) { | ||
| 94 | warnx("public_from_private"); | ||
| 95 | failed |= 1; | ||
| 96 | } | ||
| 97 | |||
| 98 | memcpy(first_two_bytes, encoded_public_key, sizeof(first_two_bytes)); | ||
| 99 | memset(encoded_public_key, 0xff, sizeof(first_two_bytes)); | ||
| 66 | 100 | ||
| 67 | /* Parsing should fail because the first coefficient is >= kPrime. */ | 101 | /* Parsing should fail because the first coefficient is >= kPrime. */ |
| 68 | if (ctx->parse_public_key(ctx->pub, ctx->encoded_public_key, | 102 | if (MLKEM_parse_public_key(pub, encoded_public_key, |
| 69 | ctx->encoded_public_key_len)) { | 103 | encoded_public_key_len)) { |
| 70 | warnx("parse_public_key should have failed"); | 104 | warnx("parse_public_key should have failed"); |
| 71 | failed |= 1; | 105 | failed |= 1; |
| 72 | } | 106 | } |
| 73 | 107 | ||
| 74 | memcpy(ctx->encoded_public_key, first_two_bytes, sizeof(first_two_bytes)); | 108 | memcpy(encoded_public_key, first_two_bytes, sizeof(first_two_bytes)); |
| 75 | if (!ctx->parse_public_key(ctx->pub, ctx->encoded_public_key, | 109 | |
| 76 | ctx->encoded_public_key_len)) { | 110 | MLKEM_public_key_free(pub); |
| 77 | warnx("MLKEM768_parse_public_key"); | 111 | if ((pub = MLKEM_public_key_new(rank)) == NULL) { |
| 112 | warnx("public_key_new"); | ||
| 113 | failed |= 1; | ||
| 114 | } | ||
| 115 | if (!MLKEM_parse_public_key(pub, encoded_public_key, | ||
| 116 | encoded_public_key_len)) { | ||
| 117 | warnx("MLKEM_parse_public_key"); | ||
| 118 | failed |= 1; | ||
| 119 | } | ||
| 120 | |||
| 121 | if (!MLKEM_marshal_public_key(pub, &tmp_buf, &tmp_buf_len)) { | ||
| 122 | warnx("marshal_public_key"); | ||
| 123 | failed |= 1; | ||
| 124 | } | ||
| 125 | if (encoded_public_key_len != tmp_buf_len) { | ||
| 126 | warnx("encoded public key lengths differ %d != %d", | ||
| 127 | (int) encoded_public_key_len, (int) tmp_buf_len); | ||
| 128 | failed |= 1; | ||
| 129 | } | ||
| 130 | |||
| 131 | if (compare_data(encoded_public_key, tmp_buf, tmp_buf_len, | ||
| 132 | "encoded public keys") != 0) { | ||
| 133 | warnx("compare_data"); | ||
| 78 | failed |= 1; | 134 | failed |= 1; |
| 79 | } | 135 | } |
| 136 | free(tmp_buf); | ||
| 137 | tmp_buf = NULL; | ||
| 138 | tmp_buf_len = 0; | ||
| 80 | 139 | ||
| 81 | if (!ctx->marshal_public_key(ctx->pub, &tmp_buf, &tmp_buf_len)) { | 140 | if (!MLKEM_marshal_public_key(pub3, &tmp_buf, &tmp_buf_len)) { |
| 82 | warnx("marshal_public_key"); | 141 | warnx("marshal_public_key"); |
| 83 | failed |= 1; | 142 | failed |= 1; |
| 84 | } | 143 | } |
| 85 | if (ctx->encoded_public_key_len != tmp_buf_len) { | 144 | if (encoded_public_key_len != tmp_buf_len) { |
| 86 | warnx("encoded public key lengths differ"); | 145 | warnx("encoded public key lengths differ %d != %d", |
| 146 | (int) encoded_public_key_len, (int) tmp_buf_len); | ||
| 87 | failed |= 1; | 147 | failed |= 1; |
| 88 | } | 148 | } |
| 89 | 149 | ||
| 90 | if (compare_data(ctx->encoded_public_key, tmp_buf, tmp_buf_len, | 150 | if (compare_data(encoded_public_key, tmp_buf, tmp_buf_len, |
| 91 | "encoded public keys") != 0) { | 151 | "encoded public keys") != 0) { |
| 92 | warnx("compare_data"); | 152 | warnx("compare_data"); |
| 93 | failed |= 1; | 153 | failed |= 1; |
| 94 | } | 154 | } |
| 95 | free(tmp_buf); | 155 | free(tmp_buf); |
| 96 | tmp_buf = NULL; | 156 | tmp_buf = NULL; |
| 157 | tmp_buf_len = 0; | ||
| 97 | 158 | ||
| 98 | ctx->public_from_private(ctx->pub2, ctx->priv); | 159 | if (!MLKEM_public_from_private(priv, pub2)) { |
| 99 | if (!ctx->marshal_public_key(ctx->pub2, &tmp_buf, &tmp_buf_len)) { | 160 | warnx("public_from_private"); |
| 161 | failed |= 1; | ||
| 162 | } | ||
| 163 | if (!MLKEM_marshal_public_key(pub2, &tmp_buf, &tmp_buf_len)) { | ||
| 100 | warnx("marshal_public_key"); | 164 | warnx("marshal_public_key"); |
| 101 | failed |= 1; | 165 | failed |= 1; |
| 102 | } | 166 | } |
| 103 | if (ctx->encoded_public_key_len != tmp_buf_len) { | 167 | if (encoded_public_key_len != tmp_buf_len) { |
| 104 | warnx("encoded public key lengths differ"); | 168 | warnx("encoded public key lengths differ %d %d", |
| 169 | (int) encoded_public_key_len, (int) tmp_buf_len); | ||
| 105 | failed |= 1; | 170 | failed |= 1; |
| 106 | } | 171 | } |
| 107 | 172 | ||
| 108 | if (compare_data(ctx->encoded_public_key, tmp_buf, tmp_buf_len, | 173 | if (compare_data(encoded_public_key, tmp_buf, tmp_buf_len, |
| 109 | "encoded public keys") != 0) { | 174 | "encoded public keys") != 0) { |
| 110 | warnx("compare_data"); | 175 | warnx("compare_data"); |
| 111 | failed |= 1; | 176 | failed |= 1; |
| 112 | } | 177 | } |
| 113 | free(tmp_buf); | 178 | free(tmp_buf); |
| 114 | tmp_buf = NULL; | 179 | tmp_buf = NULL; |
| 180 | tmp_buf_len = 0; | ||
| 115 | 181 | ||
| 116 | if (!ctx->marshal_private_key(ctx->priv, &encoded_private_key, | 182 | if (!MLKEM_marshal_private_key(priv, &encoded_private_key, |
| 117 | &encoded_private_key_len)) { | 183 | &encoded_private_key_len)) { |
| 118 | warnx("mlkem768_encode_private_key"); | 184 | warnx("marshal_private_key"); |
| 119 | failed |= 1; | 185 | failed |= 1; |
| 120 | } | 186 | } |
| 121 | 187 | ||
| @@ -123,27 +189,34 @@ MlKemUnitTest(struct unittest_ctx *ctx) | |||
| 123 | memset(encoded_private_key, 0xff, sizeof(first_two_bytes)); | 189 | memset(encoded_private_key, 0xff, sizeof(first_two_bytes)); |
| 124 | 190 | ||
| 125 | /* Parsing should fail because the first coefficient is >= kPrime. */ | 191 | /* Parsing should fail because the first coefficient is >= kPrime. */ |
| 126 | if (ctx->parse_private_key(ctx->priv2, encoded_private_key, | 192 | if (MLKEM_parse_private_key(priv2, encoded_private_key, |
| 127 | encoded_private_key_len)) { | 193 | encoded_private_key_len)) { |
| 128 | warnx("MLKEM768_parse_private_key should have failed"); | 194 | warnx("parse_private_key should have failed"); |
| 129 | failed |= 1; | 195 | failed |= 1; |
| 130 | } | 196 | } |
| 131 | 197 | ||
| 132 | memcpy(encoded_private_key, first_two_bytes, sizeof(first_two_bytes)); | 198 | memcpy(encoded_private_key, first_two_bytes, sizeof(first_two_bytes)); |
| 133 | 199 | ||
| 134 | if (!ctx->parse_private_key(ctx->priv2, encoded_private_key, | 200 | MLKEM_private_key_free(priv2); |
| 201 | priv2 = NULL; | ||
| 202 | |||
| 203 | if ((priv2 = MLKEM_private_key_new(rank)) == NULL) { | ||
| 204 | warnx("private_key_new"); | ||
| 205 | failed |= 1; | ||
| 206 | } | ||
| 207 | if (!MLKEM_parse_private_key(priv2, encoded_private_key, | ||
| 135 | encoded_private_key_len)) { | 208 | encoded_private_key_len)) { |
| 136 | warnx("MLKEM768_parse_private_key"); | 209 | warnx("parse_private_key"); |
| 137 | failed |= 1; | 210 | failed |= 1; |
| 138 | } | 211 | } |
| 139 | 212 | ||
| 140 | if (!ctx->marshal_private_key(ctx->priv2, &tmp_buf, &tmp_buf_len)) { | 213 | if (!MLKEM_marshal_private_key(priv2, &tmp_buf, &tmp_buf_len)) { |
| 141 | warnx("encode_private_key"); | 214 | warnx("marshal_private_key"); |
| 142 | failed |= 1; | 215 | failed |= 1; |
| 143 | } | 216 | } |
| 144 | 217 | ||
| 145 | if (encoded_private_key_len != tmp_buf_len) { | 218 | if (encoded_private_key_len != tmp_buf_len) { |
| 146 | warnx("encode private key lengths differ"); | 219 | warnx("encoded private key lengths differ"); |
| 147 | failed |= 1; | 220 | failed |= 1; |
| 148 | } | 221 | } |
| 149 | 222 | ||
| @@ -156,106 +229,79 @@ MlKemUnitTest(struct unittest_ctx *ctx) | |||
| 156 | free(tmp_buf); | 229 | free(tmp_buf); |
| 157 | tmp_buf = NULL; | 230 | tmp_buf = NULL; |
| 158 | 231 | ||
| 159 | ctx->encap(ctx->ciphertext, shared_secret1, ctx->pub); | 232 | if (!MLKEM_encap(pub, &ciphertext, &ciphertext_len, &shared_secret1, |
| 160 | if (!ctx->decap(shared_secret2, ctx->ciphertext, ctx->ciphertext_len, | 233 | &s_len)) { |
| 161 | ctx->priv)) { | 234 | warnx("encap failed using pub"); |
| 235 | failed |= 1; | ||
| 236 | } | ||
| 237 | |||
| 238 | if (s_len != MLKEM_SHARED_SECRET_LENGTH) { | ||
| 239 | warnx("seed length %zu != %d", s_len, | ||
| 240 | MLKEM_SHARED_SECRET_LENGTH); | ||
| 241 | failed |= 1; | ||
| 242 | } | ||
| 243 | |||
| 244 | if (!MLKEM_decap(priv, ciphertext, ciphertext_len, | ||
| 245 | &shared_secret2, &s_len)) { | ||
| 162 | warnx("decap() failed using priv"); | 246 | warnx("decap() failed using priv"); |
| 163 | failed |= 1; | 247 | failed |= 1; |
| 164 | } | 248 | } |
| 165 | if (compare_data(shared_secret1, shared_secret2, MLKEM_SHARED_SECRET_BYTES, | 249 | |
| 250 | if (s_len != MLKEM_SHARED_SECRET_LENGTH) { | ||
| 251 | warnx("seed length %zu != %d", s_len, | ||
| 252 | MLKEM_SHARED_SECRET_LENGTH); | ||
| 253 | failed |= 1; | ||
| 254 | } | ||
| 255 | |||
| 256 | if (compare_data(shared_secret1, shared_secret2, s_len, | ||
| 166 | "shared secrets with priv") != 0) { | 257 | "shared secrets with priv") != 0) { |
| 167 | warnx("compare_data"); | 258 | warnx("compare_data"); |
| 168 | failed |= 1; | 259 | failed |= 1; |
| 169 | } | 260 | } |
| 170 | 261 | ||
| 171 | if (!ctx->decap(shared_secret2, ctx->ciphertext, ctx->ciphertext_len, | 262 | free(shared_secret2); |
| 172 | ctx->priv2)) { | 263 | shared_secret2 = NULL; |
| 264 | |||
| 265 | if (!MLKEM_decap(priv2, ciphertext, ciphertext_len, | ||
| 266 | &shared_secret2, &s_len)){ | ||
| 173 | warnx("decap() failed using priv2"); | 267 | warnx("decap() failed using priv2"); |
| 174 | failed |= 1; | 268 | failed |= 1; |
| 175 | } | 269 | } |
| 176 | if (compare_data(shared_secret1, shared_secret2, MLKEM_SHARED_SECRET_BYTES, | 270 | |
| 271 | if (s_len != MLKEM_SHARED_SECRET_LENGTH) { | ||
| 272 | warnx("seed length %zu != %d", s_len, | ||
| 273 | MLKEM_SHARED_SECRET_LENGTH); | ||
| 274 | failed |= 1; | ||
| 275 | } | ||
| 276 | |||
| 277 | if (compare_data(shared_secret1, shared_secret2, s_len, | ||
| 177 | "shared secrets with priv2") != 0) { | 278 | "shared secrets with priv2") != 0) { |
| 178 | warnx("compare_data"); | 279 | warnx("compare_data"); |
| 179 | failed |= 1; | 280 | failed |= 1; |
| 180 | } | 281 | } |
| 181 | 282 | ||
| 283 | MLKEM_public_key_free(pub); | ||
| 284 | MLKEM_public_key_free(pub2); | ||
| 285 | MLKEM_public_key_free(pub3); | ||
| 286 | MLKEM_private_key_free(priv); | ||
| 287 | MLKEM_private_key_free(priv2); | ||
| 288 | MLKEM_private_key_free(priv3); | ||
| 289 | free(encoded_public_key); | ||
| 290 | free(ciphertext); | ||
| 182 | free(encoded_private_key); | 291 | free(encoded_private_key); |
| 292 | free(shared_secret1); | ||
| 293 | free(shared_secret2); | ||
| 183 | 294 | ||
| 184 | return failed; | 295 | return failed; |
| 185 | } | 296 | } |
| 186 | 297 | ||
| 187 | static int | ||
| 188 | mlkem768_unittest(void) | ||
| 189 | { | ||
| 190 | struct MLKEM768_private_key mlkem768_priv, mlkem768_priv2; | ||
| 191 | struct MLKEM768_public_key mlkem768_pub, mlkem768_pub2; | ||
| 192 | uint8_t mlkem768_encoded_public_key[MLKEM768_PUBLIC_KEY_BYTES]; | ||
| 193 | uint8_t mlkem768_ciphertext[MLKEM768_CIPHERTEXT_BYTES]; | ||
| 194 | struct unittest_ctx mlkem768_test = { | ||
| 195 | .priv = &mlkem768_priv, | ||
| 196 | .pub = &mlkem768_pub, | ||
| 197 | .priv2 = &mlkem768_priv2, | ||
| 198 | .pub2 = &mlkem768_pub2, | ||
| 199 | .encoded_public_key = mlkem768_encoded_public_key, | ||
| 200 | .encoded_public_key_len = sizeof(mlkem768_encoded_public_key), | ||
| 201 | .ciphertext = mlkem768_ciphertext, | ||
| 202 | .ciphertext_len = sizeof(mlkem768_ciphertext), | ||
| 203 | .decap = mlkem768_decap, | ||
| 204 | .encap = mlkem768_encap, | ||
| 205 | .generate_key = mlkem768_generate_key, | ||
| 206 | .parse_private_key = mlkem768_parse_private_key, | ||
| 207 | .parse_public_key = mlkem768_parse_public_key, | ||
| 208 | .marshal_private_key = mlkem768_marshal_private_key, | ||
| 209 | .marshal_public_key = mlkem768_marshal_public_key, | ||
| 210 | .public_from_private = mlkem768_public_from_private, | ||
| 211 | }; | ||
| 212 | |||
| 213 | return MlKemUnitTest(&mlkem768_test); | ||
| 214 | } | ||
| 215 | |||
| 216 | static int | ||
| 217 | mlkem1024_unittest(void) | ||
| 218 | { | ||
| 219 | struct MLKEM1024_private_key mlkem1024_priv, mlkem1024_priv2; | ||
| 220 | struct MLKEM1024_public_key mlkem1024_pub, mlkem1024_pub2; | ||
| 221 | uint8_t mlkem1024_encoded_public_key[MLKEM1024_PUBLIC_KEY_BYTES]; | ||
| 222 | uint8_t mlkem1024_ciphertext[MLKEM1024_CIPHERTEXT_BYTES]; | ||
| 223 | struct unittest_ctx mlkem1024_test = { | ||
| 224 | .priv = &mlkem1024_priv, | ||
| 225 | .pub = &mlkem1024_pub, | ||
| 226 | .priv2 = &mlkem1024_priv2, | ||
| 227 | .pub2 = &mlkem1024_pub2, | ||
| 228 | .encoded_public_key = mlkem1024_encoded_public_key, | ||
| 229 | .encoded_public_key_len = sizeof(mlkem1024_encoded_public_key), | ||
| 230 | .ciphertext = mlkem1024_ciphertext, | ||
| 231 | .ciphertext_len = sizeof(mlkem1024_ciphertext), | ||
| 232 | .decap = mlkem1024_decap, | ||
| 233 | .encap = mlkem1024_encap, | ||
| 234 | .generate_key = mlkem1024_generate_key, | ||
| 235 | .parse_private_key = mlkem1024_parse_private_key, | ||
| 236 | .parse_public_key = mlkem1024_parse_public_key, | ||
| 237 | .marshal_private_key = mlkem1024_marshal_private_key, | ||
| 238 | .marshal_public_key = mlkem1024_marshal_public_key, | ||
| 239 | .public_from_private = mlkem1024_public_from_private, | ||
| 240 | }; | ||
| 241 | |||
| 242 | return MlKemUnitTest(&mlkem1024_test); | ||
| 243 | } | ||
| 244 | |||
| 245 | int | 298 | int |
| 246 | main(void) | 299 | main(void) |
| 247 | { | 300 | { |
| 248 | int failed = 0; | 301 | int ret = 0; |
| 249 | 302 | ||
| 250 | /* | 303 | ret |= MlKemUnitTest(RANK768); |
| 251 | * XXX - this is split into two helper functions since having a few | 304 | ret |= MlKemUnitTest(RANK1024); |
| 252 | * ML-KEM key blobs on the stack makes Emscripten's stack explode, | ||
| 253 | * leading to inscrutable silent failures unless ASAN is enabled. | ||
| 254 | * Go figure. | ||
| 255 | */ | ||
| 256 | 305 | ||
| 257 | failed |= mlkem768_unittest(); | 306 | return ret; |
| 258 | failed |= mlkem1024_unittest(); | ||
| 259 | |||
| 260 | return failed; | ||
| 261 | } | 307 | } |
