summaryrefslogtreecommitdiff
path: root/src/regress/lib/libcrypto/mlkem/mlkem_iteration_tests.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/regress/lib/libcrypto/mlkem/mlkem_iteration_tests.c')
-rw-r--r--src/regress/lib/libcrypto/mlkem/mlkem_iteration_tests.c230
1 files changed, 230 insertions, 0 deletions
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 */
39const 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 */
49const 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 */
60const 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
66typedef void (*mlkem_public_from_private_fn)(void *out_public_key,
67 const void *private_key);
68
69struct 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
92static int
93MlkemIterativeTest(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
171int
172main(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}