summaryrefslogtreecommitdiff
path: root/src/regress/lib/libcrypto/mlkem/mlkem768_iteration_test.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/regress/lib/libcrypto/mlkem/mlkem768_iteration_test.c')
-rw-r--r--src/regress/lib/libcrypto/mlkem/mlkem768_iteration_test.c157
1 files changed, 157 insertions, 0 deletions
diff --git a/src/regress/lib/libcrypto/mlkem/mlkem768_iteration_test.c b/src/regress/lib/libcrypto/mlkem/mlkem768_iteration_test.c
new file mode 100644
index 0000000000..4df8171273
--- /dev/null
+++ b/src/regress/lib/libcrypto/mlkem/mlkem768_iteration_test.c
@@ -0,0 +1,157 @@
1/* Copyright (c) 2024, Google Inc.
2 * Copyright (c) 2024, Bob Beck <beck@obtuse.com>
3 *
4 * Permission to use, copy, modify, and/or distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
11 * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
13 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
14 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
15
16#include <stdlib.h>
17#include <stdio.h>
18#include <string.h>
19
20#include "bytestring.h"
21
22#include "sha3_internal.h"
23#include "mlkem.h"
24#include "mlkem_internal.h"
25#include "mlkem_tests_util.h"
26
27static int
28encode_private_key(const struct MLKEM768_private_key *priv, uint8_t **out_buf,
29 size_t *out_len)
30{
31 CBB cbb;
32 if (!CBB_init(&cbb, MLKEM768_PUBLIC_KEY_BYTES))
33 return 0;
34 if (!MLKEM768_marshal_private_key(&cbb, priv))
35 return 0;
36 if (!CBB_finish(&cbb, out_buf, out_len))
37 return 0;
38 CBB_cleanup(&cbb);
39 return 1;
40}
41
42/*
43 * The structure of this test is taken from
44 * https://github.com/C2SP/CCTV/blob/main/ML-KEM/README.md?ref=words.filippo.io#accumulated-pq-crystals-vectors
45 * but the final value has been updated to reflect the change from Kyber to
46 * ML-KEM.
47 *
48 * The deterministic RNG is a single SHAKE-128 instance with an empty input.
49 * (The RNG stream starts with 7f9c2ba4e88f827d616045507605853e.)
50 */
51
52static void
53MlkemIterativeTest()
54{
55 /* https://github.com/C2SP/CCTV/tree/main/ML-KEM */
56 /*
57 * The deterministic RNG is a single SHAKE-128 instance with an empty input.
58 * (The RNG stream starts with 7f9c2ba4e88f827d616045507605853e.)
59 */
60 const uint8_t kExpectedSeedStart[16] = {
61 0x7f, 0x9c, 0x2b, 0xa4, 0xe8, 0x8f, 0x82, 0x7d, 0x61, 0x60, 0x45,
62 0x50, 0x76, 0x05, 0x85, 0x3e
63 };
64 /*
65 * Filippo says:
66 * ML-KEM-768: f7db260e1137a742e05fe0db9525012812b004d29040a5b606aad3d134b548d3
67 * but Boring believes this:
68 */
69 const uint8_t kExpectedAdam[32] = {
70 0xf9, 0x59, 0xd1, 0x8d, 0x3d, 0x11, 0x80, 0x12, 0x14, 0x33, 0xbf,
71 0x0e, 0x05, 0xf1, 0x1e, 0x79, 0x08, 0xcf, 0x9d, 0x03, 0xed, 0xc1,
72 0x50, 0xb2, 0xb0, 0x7c, 0xb9, 0x0b, 0xef, 0x5b, 0xc1, 0xc1
73 };
74 uint8_t encoded_public_key[MLKEM768_PUBLIC_KEY_BYTES];
75 uint8_t invalid_ciphertext[MLKEM768_CIPHERTEXT_BYTES];
76 uint8_t shared_secret[MLKEM_SHARED_SECRET_BYTES];
77 uint8_t ciphertext[MLKEM768_CIPHERTEXT_BYTES];
78 uint8_t encap_entropy[MLKEM_ENCAP_ENTROPY];
79 uint8_t seed[MLKEM_SEED_BYTES] = {0};
80 struct MLKEM768_private_key priv;
81 struct MLKEM768_public_key pub;
82 sha3_ctx drng, results;
83 uint8_t out[32];
84 int i;
85
86 shake128_init(&drng);
87 shake128_init(&results);
88
89 shake_xof(&drng);
90 for (i = 0; i < 10000; i++) {
91 uint8_t *encoded_private_key = NULL;
92 size_t encoded_private_key_len;
93
94 /*
95 * This should draw both d and z from DRNG concatenating in
96 * seed.
97 */
98 shake_out(&drng, seed, sizeof(seed));
99 if (i == 0) {
100 TEST_DATAEQ(seed, kExpectedSeedStart,
101 sizeof(kExpectedSeedStart), "seed start");
102 }
103
104 /* generate ek as encoded_public_key */
105 MLKEM768_generate_key_external_entropy(encoded_public_key,
106 &priv, seed);
107 MLKEM768_public_from_private(&pub, &priv);
108
109 /* hash in ek */
110 shake_update(&results, encoded_public_key,
111 sizeof(encoded_public_key));
112
113 /* marshal priv to dk as encoded_private_key */
114 TEST(!encode_private_key(&priv, &encoded_private_key,
115 &encoded_private_key_len), "encode_private_key");
116
117 /* hash in dk */
118 shake_update(&results, encoded_private_key,
119 encoded_private_key_len);
120
121 free(encoded_private_key);
122
123 /* draw m as encap entropy from DRNG */
124 shake_out(&drng, encap_entropy, sizeof(encap_entropy));
125
126 /* generate ct as ciphertext, k as shared_secret */
127 MLKEM768_encap_external_entropy(ciphertext, shared_secret,
128 &pub, encap_entropy);
129
130 /* hash in ct */
131 shake_update(&results, ciphertext, sizeof(ciphertext));
132 /* hash in k */
133 shake_update(&results, shared_secret, sizeof(shared_secret));
134
135 /* draw ct as invalid_ciphertxt from DRNG */
136 shake_out(&drng, invalid_ciphertext,
137 sizeof(invalid_ciphertext));
138
139 /* generte k as shared secret from invalid ciphertext */
140 TEST(!MLKEM768_decap(shared_secret, invalid_ciphertext,
141 sizeof(invalid_ciphertext), &priv), "decap failed!");
142
143 /* hash in k */
144 shake_update(&results, shared_secret, sizeof(shared_secret));
145 }
146 shake_xof(&results);
147 shake_out(&results, out, 32);
148
149 TEST_DATAEQ(out, kExpectedAdam, 32, "final result hash");
150}
151
152int
153main(int argc, char **argv)
154{
155 MlkemIterativeTest();
156 exit(failure);
157}