summaryrefslogtreecommitdiff
path: root/src/regress/lib/libcrypto/mlkem/mlkem1024_iteration_test.c
diff options
context:
space:
mode:
authorbeck <>2024-12-13 00:17:18 +0000
committerbeck <>2024-12-13 00:17:18 +0000
commitee07c6bc022a26df0601ff3acffd488777cb32fa (patch)
tree96342312b2f330ea5c3d02d4c28c8c50ece4ee37 /src/regress/lib/libcrypto/mlkem/mlkem1024_iteration_test.c
parent6d94ba19b3aad3bfdeca665a771586c1a68a3f66 (diff)
downloadopenbsd-ee07c6bc022a26df0601ff3acffd488777cb32fa.tar.gz
openbsd-ee07c6bc022a26df0601ff3acffd488777cb32fa.tar.bz2
openbsd-ee07c6bc022a26df0601ff3acffd488777cb32fa.zip
Add ML-KEM 1024 from BoringSSL
Changes include conversion from C++, basic KNF, then adaptation to use our sha3 functions for sha3 and shake instead of the BorinSSL version. This Adds units tests to run against BoringSSL and NIST test vectors. The future public API is the same as Boring's - but is not yet exposed pending making bytestring.h public (which will happen separately) and a minor bump Currently this will just ensure we build and run regress. ok tb@ to get it into the tree and massage from there.
Diffstat (limited to 'src/regress/lib/libcrypto/mlkem/mlkem1024_iteration_test.c')
-rw-r--r--src/regress/lib/libcrypto/mlkem/mlkem1024_iteration_test.c158
1 files changed, 158 insertions, 0 deletions
diff --git a/src/regress/lib/libcrypto/mlkem/mlkem1024_iteration_test.c b/src/regress/lib/libcrypto/mlkem/mlkem1024_iteration_test.c
new file mode 100644
index 0000000000..d44156e715
--- /dev/null
+++ b/src/regress/lib/libcrypto/mlkem/mlkem1024_iteration_test.c
@@ -0,0 +1,158 @@
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 MLKEM1024_private_key *priv, uint8_t **out_buf,
29 size_t *out_len)
30{
31 CBB cbb;
32 if (!CBB_init(&cbb, MLKEM1024_PUBLIC_KEY_BYTES))
33 return 0;
34 if (!MLKEM1024_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 /*
66 * Filippo says:
67 * ML-KEM-1024: 47ac888fe61544efc0518f46094b4f8a600965fc89822acb06dc7169d24f3543
68 * but Boring believes this:
69 */
70 const uint8_t kExpectedAdam[32] = {
71 0xe3, 0xbf, 0x82, 0xb0, 0x13, 0x30, 0x7b, 0x2e, 0x9d, 0x47, 0xdd,
72 0xe7, 0x91, 0xff, 0x6d, 0xfc, 0x82, 0xe6, 0x94, 0xe6, 0x38, 0x24,
73 0x04, 0xab, 0xdb, 0x94, 0x8b, 0x90, 0x8b, 0x75, 0xba, 0xd5
74 };
75 uint8_t encoded_public_key[MLKEM1024_PUBLIC_KEY_BYTES];
76 uint8_t invalid_ciphertext[MLKEM1024_CIPHERTEXT_BYTES];
77 uint8_t shared_secret[MLKEM_SHARED_SECRET_BYTES];
78 uint8_t ciphertext[MLKEM1024_CIPHERTEXT_BYTES];
79 uint8_t encap_entropy[MLKEM_ENCAP_ENTROPY];
80 uint8_t seed[MLKEM_SEED_BYTES] = {0};
81 struct MLKEM1024_private_key priv;
82 struct MLKEM1024_public_key pub;
83 sha3_ctx drng, results;
84 uint8_t out[32];
85 int i;
86
87 shake128_init(&drng);
88 shake128_init(&results);
89
90 shake_xof(&drng);
91 for (i = 0; i < 10000; i++) {
92 uint8_t *encoded_private_key = NULL;
93 size_t encoded_private_key_len;
94
95 /*
96 * This should draw both d and z from DRNG concatenating in
97 * seed.
98 */
99 shake_out(&drng, seed, sizeof(seed));
100 if (i == 0) {
101 TEST_DATAEQ(seed, kExpectedSeedStart,
102 sizeof(kExpectedSeedStart), "seed start");
103 }
104
105 /* generate ek as encoded_public_key */
106 MLKEM1024_generate_key_external_entropy(encoded_public_key,
107 &priv, seed);
108 MLKEM1024_public_from_private(&pub, &priv);
109
110 /* hash in ek */
111 shake_update(&results, encoded_public_key,
112 sizeof(encoded_public_key));
113
114 /* marshal priv to dk as encoded_private_key */
115 TEST(!encode_private_key(&priv, &encoded_private_key,
116 &encoded_private_key_len), "encode_private_key");
117
118 /* hash in dk */
119 shake_update(&results, encoded_private_key,
120 encoded_private_key_len);
121
122 free(encoded_private_key);
123
124 /* draw m as encap entropy from DRNG */
125 shake_out(&drng, encap_entropy, sizeof(encap_entropy));
126
127 /* generate ct as ciphertext, k as shared_secret */
128 MLKEM1024_encap_external_entropy(ciphertext, shared_secret,
129 &pub, encap_entropy);
130
131 /* hash in ct */
132 shake_update(&results, ciphertext, sizeof(ciphertext));
133 /* hash in k */
134 shake_update(&results, shared_secret, sizeof(shared_secret));
135
136 /* draw ct as invalid_ciphertxt from DRNG */
137 shake_out(&drng, invalid_ciphertext,
138 sizeof(invalid_ciphertext));
139
140 /* generte k as shared secret from invalid ciphertext */
141 TEST(!MLKEM1024_decap(shared_secret, invalid_ciphertext,
142 sizeof(invalid_ciphertext), &priv), "decap failed!");
143
144 /* hash in k */
145 shake_update(&results, shared_secret, sizeof(shared_secret));
146 }
147 shake_xof(&results);
148 shake_out(&results, out, 32);
149
150 TEST_DATAEQ(out, kExpectedAdam, 32, "final result hash");
151}
152
153int
154main(int argc, char **argv)
155{
156 MlkemIterativeTest();
157 exit(failure);
158}