slh-fors.c slh-merkle.c slh-wots.c slh-xmss.c \
slh-dsa.c slh-dsa-128s.c slh-dsa-128f.c \
slh-dsa-shake-128s.c slh-dsa-shake-128f.c slh-dsa-sha2-128s.c slh-dsa-sha2-128f.c \
- sntrup761.c sntrup761-keygen.c sntrup761-decap.c sntrup761-encap.c
+ sntrup761.c sntrup761-keygen.c sntrup761-decap.c sntrup761-encap.c \
+ ml-kem.c ml-kem-768.c ml-kem-1024.c ml-kem-internal.c
hogweed_SOURCES = sexp.c sexp-format.c \
sexp-transport.c sexp-transport-format.c \
salsa20.h sexp.h serpent.h \
sha1.h sha2.h sha3.h slh-dsa.h sm3.h sm4.h streebog.h twofish.h \
umac.h yarrow.h xts.h poly1305.h nist-keywrap.h \
- drbg-ctr.h sntrup.h
+ drbg-ctr.h sntrup.h ml-kem.h
INSTALL_HEADERS = $(HEADERS) version.h @IF_MINI_GMP@ mini-gmp.h
salsa20-internal.h umac-internal.h hogweed-internal.h \
rsa-internal.h pkcs1-internal.h dsa-internal.h eddsa-internal.h \
slh-dsa-internal.h sntrup-internal.h sntrup761-encoding.h \
+ ml-kem-internal.h \
gmp-glue.h ecc-internal.h fat-setup.h oaep.h \
mini-gmp.h asm.m4 m4-utils.m4 \
nettle.texinfo nettle.info nettle.html nettle.pdf sha-example.c
#include "curve448.h"
#include "slh-dsa.h"
#include "sntrup.h"
+#include "ml-kem.h"
#include "nettle-meta.h"
#include "sexp.h"
free (p);
}
+struct ml_kem_ctx
+{
+ const struct ml_kem_params *params;
+ uint8_t public_key[ML_KEM_1024_PUBLIC_KEY_SIZE];
+ uint8_t secret_key[ML_KEM_1024_PRIVATE_KEY_SIZE];
+ uint8_t ciphertext[ML_KEM_1024_CIPHERTEXT_SIZE];
+ struct knuth_lfib_ctx lfib;
+ uint16_t *scratch;
+};
+
+static void *
+bench_ml_kem_init (unsigned size)
+{
+ struct ml_kem_ctx *ctx;
+ uint8_t session_key[ML_KEM_SESSION_KEY_SIZE];
+ uint8_t seed[ML_KEM_SEED_SIZE];
+
+ assert (size == 768 || size == 1024);
+ ctx = xalloc (sizeof (*ctx));
+
+ ctx->params = size == 768 ?
+ nettle_get_ml_kem_768_params () : nettle_get_ml_kem_1024_params ();
+
+ ctx->scratch = xalloc (ml_kem_decap_itch (ctx->params) *
+ sizeof(uint16_t));
+ knuth_lfib_init (&ctx->lfib, 1);
+ knuth_lfib_random (&ctx->lfib, sizeof (seed), seed);
+
+ ml_kem_generate_keypair (ctx->params, ctx->public_key, ctx->secret_key,
+ seed, ctx->scratch);
+
+ ml_kem_encap (ctx->params,
+ ctx->public_key,
+ session_key, ctx->ciphertext,
+ &ctx->lfib, (nettle_random_func *)knuth_lfib_random,
+ ctx->scratch);
+
+ return ctx;
+}
+
+static void
+bench_ml_kem_keygen (void *p)
+{
+ struct ml_kem_ctx *ctx = p;
+ uint8_t public_key[ML_KEM_1024_PUBLIC_KEY_SIZE];
+ uint8_t secret_key[ML_KEM_1024_PRIVATE_KEY_SIZE];
+ uint8_t seed[ML_KEM_SEED_SIZE];
+
+ knuth_lfib_init (&ctx->lfib, 1);
+ knuth_lfib_random (&ctx->lfib, sizeof (seed), seed);
+
+ ml_kem_generate_keypair (ctx->params, public_key, secret_key, seed,
+ ctx->scratch);
+}
+
+static void
+bench_ml_kem_encrypt (void *p)
+{
+ struct ml_kem_ctx *ctx = p;
+ uint8_t session_key[ML_KEM_SESSION_KEY_SIZE];
+
+ ml_kem_encap (ctx->params, ctx->public_key, session_key, ctx->ciphertext,
+ &ctx->lfib, (nettle_random_func *)knuth_lfib_random,
+ ctx->scratch);
+}
+
+static void
+bench_ml_kem_decrypt (void *p)
+{
+ struct ml_kem_ctx *ctx = p;
+ uint8_t session_key[ML_KEM_SESSION_KEY_SIZE];
+ ml_kem_decap (ctx->params, ctx->secret_key, session_key, ctx->ciphertext,
+ ctx->scratch);
+}
+
+static void
+bench_ml_kem_clear (void *p)
+{
+ struct ml_kem_ctx *ctx = p;
+ free (ctx->scratch);
+ free (ctx);
+}
+
static const struct sign_alg sign_alg_list[] = {
{ "rsa", 1024, bench_rsa_init, bench_rsa_sign, bench_rsa_verify, bench_rsa_clear },
{ "rsa", 2048, bench_rsa_init, bench_rsa_sign, bench_rsa_verify, bench_rsa_clear },
static const struct kem_alg kem_alg_list[] = {
{ "sntrup", 761, bench_sntrup_init, bench_sntrup_keygen, bench_sntrup_encrypt, bench_sntrup_decrypt, bench_sntrup_clear },
+ { "ml_kem", 768, bench_ml_kem_init, bench_ml_kem_keygen, bench_ml_kem_encrypt, bench_ml_kem_decrypt, bench_ml_kem_clear },
+ { "ml_kem", 1024, bench_ml_kem_init, bench_ml_kem_keygen, bench_ml_kem_encrypt, bench_ml_kem_decrypt, bench_ml_kem_clear },
};
#define numberof(x) (sizeof (x) / sizeof ((x)[0]))
--- /dev/null
+/* ml-kem-1024.c
+
+ The ML-KEM (Kyber) key encapsulation mechanism, FIPS 203
+
+ Copyright (C) 2024 Red Hat, Inc.
+
+ This file is part of GNU Nettle.
+
+ GNU Nettle is free software: you can redistribute it and/or
+ modify it under the terms of either:
+
+ * the GNU Lesser General Public License as published by the Free
+ Software Foundation; either version 3 of the License, or (at your
+ option) any later version.
+
+ or
+
+ * the GNU General Public License as published by the Free
+ Software Foundation; either version 2 of the License, or (at your
+ option) any later version.
+
+ or both in parallel, as here.
+
+ GNU Nettle is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received copies of the GNU General Public License and
+ the GNU Lesser General Public License along with this program. If
+ not, see http://www.gnu.org/licenses/.
+*/
+
+#if HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include "ml-kem.h"
+
+#include "ml-kem-internal.h"
+
+#define ML_KEM_1024_K 4
+#define ML_KEM_1024_DU 11
+#define ML_KEM_1024_DV 5
+#define ML_KEM_1024_ETA1 2
+
+static const struct ml_kem_params _nettle_ml_kem_1024_params =
+ {
+ ML_KEM_1024_INNER_PUBLIC_KEY_SIZE,
+ ML_KEM_1024_INNER_PRIVATE_KEY_SIZE,
+ ML_KEM_1024_PUBLIC_KEY_SIZE,
+ ML_KEM_1024_PRIVATE_KEY_SIZE,
+ ML_KEM_1024_CIPHERTEXT_SIZE,
+ ML_KEM_1024_K,
+ ML_KEM_1024_DU,
+ ML_KEM_1024_DV,
+ ML_KEM_1024_ETA1
+ };
+
+const struct ml_kem_params *nettle_get_ml_kem_1024_params (void)
+{
+ return &_nettle_ml_kem_1024_params;
+}
--- /dev/null
+/* ml-kem-768.c
+
+ The ML-KEM (Kyber) key encapsulation mechanism, FIPS 203
+
+ Copyright (C) 2024 Red Hat, Inc.
+
+ This file is part of GNU Nettle.
+
+ GNU Nettle is free software: you can redistribute it and/or
+ modify it under the terms of either:
+
+ * the GNU Lesser General Public License as published by the Free
+ Software Foundation; either version 3 of the License, or (at your
+ option) any later version.
+
+ or
+
+ * the GNU General Public License as published by the Free
+ Software Foundation; either version 2 of the License, or (at your
+ option) any later version.
+
+ or both in parallel, as here.
+
+ GNU Nettle is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received copies of the GNU General Public License and
+ the GNU Lesser General Public License along with this program. If
+ not, see http://www.gnu.org/licenses/.
+*/
+
+#if HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include "ml-kem.h"
+
+#include "ml-kem-internal.h"
+
+#define ML_KEM_768_K 3
+#define ML_KEM_768_DU 10
+#define ML_KEM_768_DV 4
+#define ML_KEM_768_ETA1 2
+
+static const struct ml_kem_params _nettle_ml_kem_768_params =
+ {
+ ML_KEM_768_INNER_PUBLIC_KEY_SIZE,
+ ML_KEM_768_INNER_PRIVATE_KEY_SIZE,
+ ML_KEM_768_PUBLIC_KEY_SIZE,
+ ML_KEM_768_PRIVATE_KEY_SIZE,
+ ML_KEM_768_CIPHERTEXT_SIZE,
+ ML_KEM_768_K,
+ ML_KEM_768_DU,
+ ML_KEM_768_DV,
+ ML_KEM_768_ETA1
+ };
+
+const struct ml_kem_params *nettle_get_ml_kem_768_params (void)
+{
+ return &_nettle_ml_kem_768_params;
+}
--- /dev/null
+/* ml-kem-internal.c
+
+ ML-KEM (Kyber) key encapsulation mechanism, FIPS 203
+
+ Copyright (C) 2024 Red Hat, Inc.
+
+ This file is part of GNU Nettle.
+
+ GNU Nettle is free software: you can redistribute it and/or
+ modify it under the terms of either:
+
+ * the GNU Lesser General Public License as published by the Free
+ Software Foundation; either version 3 of the License, or (at your
+ option) any later version.
+
+ or
+
+ * the GNU General Public License as published by the Free
+ Software Foundation; either version 2 of the License, or (at your
+ option) any later version.
+
+ or both in parallel, as here.
+
+ GNU Nettle is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received copies of the GNU General Public License and
+ the GNU Lesser General Public License along with this program. If
+ not, see http://www.gnu.org/licenses/.
+*/
+
+#if HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include "ml-kem-internal.h"
+
+#include "sha3.h"
+#include <string.h>
+
+#define Q 3329
+#define Q_BITS 12
+#define N 256
+#define N_BITS 8
+#define INV2 1665
+
+#define ZETA 17
+#define ETA2 2
+#define MAX_ETA1 3
+
+/* Check if a bit at IDX in a byte array ARR */
+#define IS_BIT_SET(arr, idx) \
+ ((((arr)[(idx) >> 3] >> ((idx) & 7))) & 1)
+
+/* Set a bit at IDX in a byte array ARR */
+#define SET_BIT(arr, idx, bit) \
+ ((arr)[(idx) >> 3] |= (((bit) & 1) << ((idx) & 7)))
+
+/* A polynomial is represented as a uint16_t array of length N, where
+ * an element at index i represents the coefficient of x^i.
+ *
+ * Vectors and matrices of polynomials are represented as a flat,
+ * one-dimensional array of uint16_t, where a vector of k polynomials
+ * is an array of uint16_t, of length N * k. A matrix of l vectors is
+ * an array of uint16_t, of length N * k * l.
+ */
+#define VECTOR_GET_POLY(vec, i) &(vec)[(i) * N]
+#define MATRIX_GET_VECTOR(mat, k, i) &(mat)[(k) * (i) * N]
+#define MATRIX_GET_POLY(mat, k, l, i, j) &(mat)[(k) * (i) * N + (l) * (j) * N]
+
+static inline void
+G2 (struct sha3_ctx *ctx,
+ size_t len1, const uint8_t *msg1,
+ size_t len2, const uint8_t *msg2,
+ uint8_t *dst)
+{
+ sha3_init (ctx);
+ sha3_512_update (ctx, len1, msg1);
+ sha3_512_update (ctx, len2, msg2);
+ sha3_512_digest (ctx, dst);
+}
+
+static inline void
+J2 (struct sha3_ctx *ctx,
+ size_t len1, const uint8_t *msg1,
+ size_t len2, const uint8_t *msg2,
+ uint8_t *dst)
+{
+ sha3_init (ctx);
+ sha3_256_update (ctx, len1, msg1);
+ sha3_256_update (ctx, len2, msg2);
+ sha3_256_shake (ctx, 32, dst);
+}
+
+#define KDF2(ctx, prekey1, prekey2, dst) \
+ J2(ctx, 32, prekey1, 32, prekey2, dst)
+
+static inline void
+PRF (struct sha3_ctx *ctx,
+ const uint8_t *seed,
+ uint8_t nonce,
+ size_t length,
+ uint8_t *dst)
+{
+ sha3_init (ctx);
+ sha3_256_update (ctx, 32, seed);
+ sha3_256_update (ctx, 1, &nonce);
+ sha3_256_shake (ctx, length, dst);
+}
+
+/* Compress(x, d) = Round((2^d/Q)x) mod 2^d
+ for 0 <= x < Q and d < 12, the result is in [0, 2^d) */
+static inline uint16_t
+compress (uint16_t x, unsigned int d)
+{
+ return ((UINT64_C(20642679) * ((x << d) + (Q >> 1)) >> 36) & ((1 << d) - 1));
+}
+
+/* Decompress(y, d) = Round((Q/2^d)y)
+ for 0 <= y < 2^d and d < 12, the result is in [0, Q) */
+static inline uint16_t
+decompress (uint16_t y, unsigned int d)
+{
+ return ((Q * y + (1 << (d - 1))) >> d);
+}
+
+/* Calculate x mod Q using Barrett reduction
+ for x in range [0, Q^2) */
+static inline uint16_t
+reduce (uint64_t a)
+{
+ uint64_t mask;
+
+ a -= ((a * 5039) >> (Q_BITS << 1)) * Q;
+ mask = -(uint64_t) (a >= Q);
+
+ return a - (Q & mask);
+}
+
+/* Calculate a - b mod Q, where 0 <= a < Q and 0 <= b <= Q */
+static inline uint16_t
+mod_sub (uint16_t a, uint16_t b)
+{
+ uint16_t mask;
+
+ mask = -(uint16_t) (a < b);
+
+ return a + (Q & mask) - b;
+}
+
+/* Calculate a + b mod Q, where a and b are already reduced by Q */
+static inline uint16_t
+mod_add (uint16_t a, uint16_t b)
+{
+ return mod_sub (a, Q - b);
+}
+
+static const uint16_t zeta_pow_table[128] =
+ {
+ 0x0001, 0x06c1, 0x0a14, 0x0cd9, 0x0a52, 0x0276, 0x0769, 0x0350,
+ 0x0426, 0x077f, 0x00c1, 0x031d, 0x0ae2, 0x0cbc, 0x0239, 0x06d2,
+ 0x0128, 0x098f, 0x053b, 0x05c4, 0x0be6, 0x0038, 0x08c0, 0x0535,
+ 0x0592, 0x082e, 0x0217, 0x0b42, 0x0959, 0x0b3f, 0x07b6, 0x0335,
+ 0x0121, 0x014b, 0x0cb5, 0x06dc, 0x04ad, 0x0900, 0x08e5, 0x0807,
+ 0x028a, 0x07b9, 0x09d1, 0x0278, 0x0b31, 0x0021, 0x0528, 0x077b,
+ 0x090f, 0x059b, 0x0327, 0x01c4, 0x059e, 0x0b34, 0x05fe, 0x0962,
+ 0x0a57, 0x0a39, 0x05c9, 0x0288, 0x09aa, 0x0c26, 0x04cb, 0x038e,
+ 0x0011, 0x0ac9, 0x0247, 0x0a59, 0x0665, 0x02d3, 0x08f0, 0x044c,
+ 0x0581, 0x0a66, 0x0cd1, 0x00e9, 0x02f4, 0x086c, 0x0bc7, 0x0bea,
+ 0x06a7, 0x0673, 0x0ae5, 0x06fd, 0x0737, 0x03b8, 0x05b5, 0x0a7f,
+ 0x03ab, 0x0904, 0x0985, 0x0954, 0x02dd, 0x0921, 0x010c, 0x0281,
+ 0x0630, 0x08fa, 0x07f5, 0x0c94, 0x0177, 0x09f5, 0x082a, 0x066d,
+ 0x0427, 0x013f, 0x0ad5, 0x02f5, 0x0833, 0x0231, 0x09a2, 0x0a22,
+ 0x0af4, 0x0444, 0x0193, 0x0402, 0x0477, 0x0866, 0x0ad7, 0x0376,
+ 0x06ba, 0x04bc, 0x0752, 0x0405, 0x083e, 0x0b77, 0x0375, 0x086a,
+ };
+
+static const uint16_t zeta_pow_table2[128] =
+ {
+ 0x0011, 0x0cf0, 0x0ac9, 0x0238, 0x0247, 0x0aba, 0x0a59, 0x02a8,
+ 0x0665, 0x069c, 0x02d3, 0x0a2e, 0x08f0, 0x0411, 0x044c, 0x08b5,
+ 0x0581, 0x0780, 0x0a66, 0x029b, 0x0cd1, 0x0030, 0x00e9, 0x0c18,
+ 0x02f4, 0x0a0d, 0x086c, 0x0495, 0x0bc7, 0x013a, 0x0bea, 0x0117,
+ 0x06a7, 0x065a, 0x0673, 0x068e, 0x0ae5, 0x021c, 0x06fd, 0x0604,
+ 0x0737, 0x05ca, 0x03b8, 0x0949, 0x05b5, 0x074c, 0x0a7f, 0x0282,
+ 0x03ab, 0x0956, 0x0904, 0x03fd, 0x0985, 0x037c, 0x0954, 0x03ad,
+ 0x02dd, 0x0a24, 0x0921, 0x03e0, 0x010c, 0x0bf5, 0x0281, 0x0a80,
+ 0x0630, 0x06d1, 0x08fa, 0x0407, 0x07f5, 0x050c, 0x0c94, 0x006d,
+ 0x0177, 0x0b8a, 0x09f5, 0x030c, 0x082a, 0x04d7, 0x066d, 0x0694,
+ 0x0427, 0x08da, 0x013f, 0x0bc2, 0x0ad5, 0x022c, 0x02f5, 0x0a0c,
+ 0x0833, 0x04ce, 0x0231, 0x0ad0, 0x09a2, 0x035f, 0x0a22, 0x02df,
+ 0x0af4, 0x020d, 0x0444, 0x08bd, 0x0193, 0x0b6e, 0x0402, 0x08ff,
+ 0x0477, 0x088a, 0x0866, 0x049b, 0x0ad7, 0x022a, 0x0376, 0x098b,
+ 0x06ba, 0x0647, 0x04bc, 0x0845, 0x0752, 0x05af, 0x0405, 0x08fc,
+ 0x083e, 0x04c3, 0x0b77, 0x018a, 0x0375, 0x098c, 0x086a, 0x0497,
+ };
+
+/* Move a polynomial PP into NTT domain. */
+static void
+poly_into_ntt (uint16_t *pp)
+{
+ size_t layer, zi;
+
+ for (layer = N >> 1, zi = 1; layer >= 2; layer >>= 1)
+ {
+ size_t offset;
+
+ for (offset = 0; offset < N - layer; offset += 2 * layer)
+ {
+ size_t j;
+ uint16_t z;
+
+ z = zeta_pow_table[zi++];
+ for (j = offset; j < offset + layer; j++)
+ {
+ uint16_t t;
+
+ t = reduce (z * pp[j + layer]);
+ pp[j + layer] = mod_sub (pp[j], t);
+ pp[j] = mod_add (pp[j], t);
+ }
+ }
+ }
+}
+
+/* Move a polynomial PP back from NTT domain. */
+static void
+poly_from_ntt (uint16_t *pp)
+{
+ size_t layer, zi;
+
+ for (layer = 2, zi = (N >> 1) - 1; layer < N; layer <<= 1)
+ {
+ size_t offset;
+
+ for (offset = 0; offset < N - layer; offset += 2 * layer)
+ {
+ size_t j;
+ uint16_t z;
+
+ z = zeta_pow_table[zi--];
+ for (j = offset; j < offset + layer; j++)
+ {
+ uint16_t t;
+
+ t = mod_sub (pp[j + layer], pp[j]);
+ pp[j] = reduce (INV2 * mod_add (pp[j], pp[j + layer]));
+ pp[j + layer] = reduce (INV2 * reduce (z * t));
+ }
+ }
+ }
+}
+
+/* Calculate a product of two polynomials AP and BP in NTT domain.
+ *
+ * Returns the results as a polynomial in RP, which should not overlap
+ * with AP nor BP.
+ */
+static void
+poly_mul_ntt (uint16_t *rp, const uint16_t *ap, const uint16_t *bp)
+{
+ size_t i;
+
+ memset (rp, 0, sizeof(uint16_t) * N);
+
+ for (i = 0; i < N; i += 2)
+ {
+ uint16_t z, a1, a2, b1, b2;
+
+ a1 = ap[i];
+ a2 = ap[i + 1];
+ b1 = bp[i];
+ b2 = bp[i + 1];
+
+ z = zeta_pow_table2[i >> 1];
+
+ rp[i] = mod_add (reduce (a1 * b1), reduce (z * reduce (a2 * b2)));
+ rp[i + 1] = mod_add (reduce (a2 * b1), reduce (a1 * b2));
+ }
+}
+
+/* Calculate dot product of two vectors AP and BP with length K in NTT domain.
+ *
+ * Returns the result as a polynomial in RP.
+ */
+static void
+vector_mul_ntt (uint16_t *rp, const uint16_t *ap, const uint16_t *bp,
+ unsigned int k)
+{
+ uint16_t tp[N];
+ size_t i;
+
+ memset (rp, 0, sizeof(uint16_t) * N);
+
+ for (i = 0; i < k; i++)
+ {
+ size_t j;
+
+ poly_mul_ntt (tp, VECTOR_GET_POLY (ap, i), VECTOR_GET_POLY (bp, i));
+
+ for (j = 0; j < N; j++)
+ {
+ uint16_t t = tp[j];
+ uint16_t r = rp[j];
+
+ rp[j] = t + r;
+ }
+ }
+
+ for (i = 0; i < N; i++)
+ rp[i] = reduce (rp[i]);
+}
+
+/* Calculate a product of a K x K matrix AP and a vector with K
+ * elements BP in NTT domain. ROW_STRIDE and COLUMN_STRIDE specify how
+ * AP is accessed. To access in a row-major order, set ROW_STRIDE to K
+ * and COLUMN_STRIDE to 1; otherwise set ROW_STRIDE to 1 and
+ * COLUMN_STRIDE to K.
+ *
+ * Returns the result as a vector in RP.
+ */
+static void
+matrix_mul_ntt (uint16_t *rp, const uint16_t *ap, const uint16_t *bp,
+ unsigned int k,
+ unsigned int row_stride,
+ unsigned int column_stride)
+{
+ size_t i;
+
+ for (i = 0; i < k; i++)
+ {
+ uint16_t *pp;
+ size_t j;
+
+ pp = VECTOR_GET_POLY (rp, i);
+
+ memset (pp, 0, sizeof(uint16_t) * N);
+
+ for (j = 0; j < k; j++)
+ {
+ uint16_t tp[N];
+ size_t l;
+
+ poly_mul_ntt (tp, MATRIX_GET_POLY (ap, row_stride, column_stride,
+ i, j),
+ VECTOR_GET_POLY (bp, j));
+
+ for (l = 0; l < N; l++)
+ {
+ uint16_t t = tp[l];
+ uint16_t r = pp[l];
+
+ pp[l] = mod_add (t, r);
+ }
+ }
+ }
+}
+
+static void
+poly_sample (uint16_t *pp, struct sha3_128_ctx *xof)
+{
+ uint8_t b[3];
+ size_t n = 0;
+
+ memset (pp, 0, sizeof(uint8_t) * N);
+
+ for (;;)
+ {
+ uint16_t d1, d2;
+
+ sha3_128_shake_output (xof, sizeof(b), b);
+
+ d1 = b[0] + ((b[1] & 15) << 8);
+ d2 = (b[1] >> 4) + (b[2] << 4);
+
+ if (d1 < Q)
+ {
+ pp[n++] = d1;
+ if (n == N)
+ break;
+ }
+
+ if (d2 < Q)
+ {
+ pp[n++] = d2;
+ if (n == N)
+ break;
+ }
+ }
+}
+
+static void
+vector_sample (uint16_t *vp, const uint8_t *sigma, unsigned int eta1,
+ unsigned int offset, unsigned int k)
+{
+ size_t i;
+
+ for (i = 0; i < k; i++)
+ {
+ struct sha3_ctx ctx;
+ uint8_t arr[64 * MAX_ETA1];
+ uint16_t *rp;
+ size_t j, n;
+
+ PRF (&ctx, sigma, offset + i, 64 * eta1, arr);
+
+ rp = VECTOR_GET_POLY (vp, i);
+ memset (rp, 0, sizeof(uint16_t) * N);
+
+ for (j = 0, n = 0; j < N; j++, n += 2)
+ {
+ size_t l, bitcnt1 = 0, bitcnt2 = 0;
+
+ for (l = 0; l < eta1; l++)
+ {
+ bitcnt1 += IS_BIT_SET (arr, n * eta1 + l);
+ bitcnt2 += IS_BIT_SET (arr, (n + 1) * eta1 + l);
+ }
+
+ rp[j] = mod_sub (bitcnt1, bitcnt2);
+ }
+ }
+}
+
+static void
+matrix_sample (uint16_t *mp, const uint8_t *rho, unsigned int k)
+{
+ uint8_t i;
+
+ for (i = 0; i < k; i++)
+ {
+ uint16_t *v;
+ uint8_t j;
+
+ v = MATRIX_GET_VECTOR (mp, k, i);
+
+ for (j = 0; j < k; j++)
+ {
+ struct sha3_128_ctx xof;
+ uint16_t *p;
+
+ sha3_128_init (&xof);
+ sha3_128_update (&xof, 32, rho);
+ sha3_128_update (&xof, 1, &j);
+ sha3_128_update (&xof, 1, &i);
+
+ p = VECTOR_GET_POLY (v, j);
+ poly_sample (p, &xof);
+ }
+ }
+}
+
+static void
+poly_encode (uint8_t *rp, const uint16_t *ap, unsigned int w)
+{
+ size_t i;
+
+ for (i = 0; i < N; i++)
+ {
+ uint16_t a;
+ size_t j;
+
+ a = ap[i];
+ for (j = 0; j < w; j++)
+ {
+ SET_BIT (rp, i * w + j, a);
+ a >>= 1;
+ }
+ }
+}
+
+static void
+poly_decode (uint16_t *rp, const uint8_t *ap, unsigned int w)
+{
+ size_t i;
+
+ for (i = 0; i < N; i++)
+ {
+ uint16_t a = 0;
+ size_t j;
+
+ for (j = 0; j < w; j++)
+ a += IS_BIT_SET (ap, i * w + j) * (1 << j);
+
+ rp[i] = reduce (a);
+ }
+}
+
+static void
+vector_encode (uint8_t *rp, const uint16_t *ap, unsigned int k, unsigned int w)
+{
+ size_t i;
+
+ for (i = 0; i < k; i++)
+ poly_encode (&rp[((w * N) >> 3) * i], VECTOR_GET_POLY (ap, i), w);
+}
+
+static void
+vector_decode (uint16_t *rp, const uint8_t *ap, unsigned int k, unsigned int w)
+{
+ size_t i;
+
+ for (i = 0; i < k; i++)
+ poly_decode (VECTOR_GET_POLY (rp, i), &ap[((w * N) >> 3) * i], w);
+}
+
+size_t
+_ml_kem_inner_generate_keypair_itch (const struct ml_kem_params *params)
+{
+ return N * (params->k * params->k + params->k + params->k + params->k);
+}
+
+void
+_ml_kem_inner_generate_keypair (const struct ml_kem_params *params,
+ uint8_t *pub,
+ uint8_t *key,
+ const uint8_t *seed,
+ uint16_t *scratch)
+{
+ struct sha3_ctx gctx;
+ uint8_t buffer[64];
+ uint8_t *rho = buffer, *sigma = &buffer[32];
+ unsigned int i;
+ uint16_t *a, *s, *e, *t;
+ uint8_t k = params->k;
+
+ a = scratch;
+ s = a + N * params->k * params->k;
+ e = s + N * params->k;
+ t = e + N * params->k;
+
+ G2 (&gctx, 32, seed, 1, &k, buffer);
+
+ matrix_sample (a, rho, params->k);
+ vector_sample (s, sigma, params->eta1, 0, params->k);
+ vector_sample (e, sigma, params->eta1, params->k, params->k);
+
+ for (i = 0; i < params->k; i++)
+ {
+ poly_into_ntt (VECTOR_GET_POLY (s, i));
+ poly_into_ntt (VECTOR_GET_POLY (e, i));
+ }
+
+ /* row-major */
+ matrix_mul_ntt (t, a, s, params->k, params->k, 1);
+
+ for (i = 0; i < params->k; i++)
+ {
+ uint16_t *tp, *ep;
+ size_t j;
+
+ tp = VECTOR_GET_POLY (t, i);
+ ep = VECTOR_GET_POLY (e, i);
+
+ for (j = 0; j < N; j++)
+ tp[j] = mod_add (tp[j], ep[j]);
+ }
+
+ memset (pub, 0, params->inner_public_key_size);
+ memset (key, 0, params->inner_private_key_size);
+
+ vector_encode (pub, t, params->k, Q_BITS);
+
+ memcpy (pub + (params->k * Q_BITS * N) / 8, rho, 32);
+
+ vector_encode (key, s, params->k, Q_BITS);
+}
+
+size_t
+_ml_kem_inner_encrypt_itch (const struct ml_kem_params *params)
+{
+ return N * (params->k * params->k + params->k + 1 +
+ params->k + params->k + params->k);
+}
+
+void
+_ml_kem_inner_encrypt (const struct ml_kem_params *params,
+ const uint8_t *pub,
+ const uint8_t *msg,
+ const uint8_t *seed,
+ uint8_t *ciphertext,
+ uint16_t *scratch)
+{
+ const uint8_t *rho = &pub[(params->k * Q_BITS * N) / 8];
+ uint16_t *a, *r, *e1, *e2, *t, *u;
+ uint16_t m[N], v[N];
+ size_t i;
+
+ a = scratch;
+ e1 = a + N * params->k * params->k;
+ e2 = e1 + N * params->k;
+ r = e2 + N;
+ t = r + N * params->k;
+ u = t + N * params->k;
+
+ vector_decode (t, pub, params->k, Q_BITS);
+
+ matrix_sample (a, rho, params->k);
+
+ vector_sample (r, seed, params->eta1, 0, params->k);
+ vector_sample (e1, seed, ETA2, params->k, params->k);
+ vector_sample (e2, seed, ETA2, 2 * params->k, 1);
+
+ for (i = 0; i < params->k; i++)
+ poly_into_ntt (VECTOR_GET_POLY (r, i));
+
+ /* column-major */
+ matrix_mul_ntt (u, a, r, params->k, 1, params->k);
+
+ for (i = 0; i < params->k; i++)
+ poly_from_ntt (VECTOR_GET_POLY (u, i));
+
+ for (i = 0; i < params->k; i++)
+ {
+ uint16_t *up, *ep;
+ size_t j;
+
+ up = VECTOR_GET_POLY (u, i);
+ ep = VECTOR_GET_POLY (e1, i);
+
+ for (j = 0; j < N; j++)
+ up[j] = mod_add (up[j], ep[j]);
+ }
+
+ for (i = 0; i < N; i++)
+ m[i] = decompress (IS_BIT_SET (msg, i), 1);
+
+ vector_mul_ntt (v, t, r, params->k);
+ poly_from_ntt (v);
+
+ for (i = 0; i < N; i++)
+ v[i] = mod_add (mod_add (v[i], e2[i]), m[i]);
+
+ for (i = 0; i < params->k; i++)
+ {
+ size_t j;
+ uint16_t *up;
+
+ up = VECTOR_GET_POLY (u, i);
+ for (j = 0; j < N; j++)
+ up[j] = compress (up[j], params->du);
+ }
+
+ memset (ciphertext, 0, params->ciphertext_size);
+
+ vector_encode (ciphertext, u, params->k, params->du);
+
+ for (i = 0; i < N; i++)
+ v[i] = compress (v[i], params->dv);
+
+ poly_encode (&ciphertext[(params->du * params->k * N) / 8], v,
+ params->dv);
+}
+
+size_t
+_ml_kem_inner_decrypt_itch (const struct ml_kem_params *params)
+{
+ return N * (params->k + params->k);
+}
+
+void
+_ml_kem_inner_decrypt (const struct ml_kem_params *params,
+ const uint8_t *key,
+ const uint8_t *ciphertext,
+ uint8_t *plaintext,
+ uint16_t *scratch)
+{
+ uint16_t r[N], *s, *u, v[N];
+ size_t i;
+
+ s = scratch;
+ u = s + N * params->k;
+
+ vector_decode (u, ciphertext, params->k, params->du);
+
+ for (i = 0; i < params->k; i++)
+ {
+ size_t j;
+ uint16_t *up;
+
+ up = VECTOR_GET_POLY (u, i);
+ for (j = 0; j < N; j++)
+ up[j] = decompress (up[j], params->du);
+ }
+
+ poly_decode (v, &ciphertext[(params->du * params->k * N) / 8],
+ params->dv);
+
+ for (i = 0; i < N; i++)
+ v[i] = decompress (v[i], params->dv);
+
+ vector_decode (s, key, params->k, Q_BITS);
+
+ for (i = 0; i < params->k; i++)
+ poly_into_ntt (VECTOR_GET_POLY (u, i));
+
+ vector_mul_ntt (r, s, u, params->k);
+ poly_from_ntt (r);
+
+ for (i = 0; i < N; i++)
+ v[i] = mod_sub (v[i], r[i]);
+
+ for (i = 0; i < N; i++)
+ v[i] = compress (v[i], 1);
+
+ memset (plaintext, 0, 32);
+
+ poly_encode (plaintext, v, 1);
+}
--- /dev/null
+/* ml-kem-internal.h
+
+ ML-KEM (Kyber) key encapsulation mechanism, FIPS 203
+
+ Copyright (C) 2024 Red Hat, Inc.
+
+ This file is part of GNU Nettle.
+
+ GNU Nettle is free software: you can redistribute it and/or
+ modify it under the terms of either:
+
+ * the GNU Lesser General Public License as published by the Free
+ Software Foundation; either version 3 of the License, or (at your
+ option) any later version.
+
+ or
+
+ * the GNU General Public License as published by the Free
+ Software Foundation; either version 2 of the License, or (at your
+ option) any later version.
+
+ or both in parallel, as here.
+
+ GNU Nettle is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received copies of the GNU General Public License and
+ the GNU Lesser General Public License along with this program. If
+ not, see http://www.gnu.org/licenses/.
+*/
+
+#ifndef NETTLE_ML_KEM_INTERNAL_H_INCLUDED
+#define NETTLE_ML_KEM_INTERNAL_H_INCLUDED
+
+#include "ml-kem.h"
+
+#define ML_KEM_768_INNER_PUBLIC_KEY_SIZE 1184
+#define ML_KEM_768_INNER_PRIVATE_KEY_SIZE 1152
+
+#define ML_KEM_1024_INNER_PUBLIC_KEY_SIZE 1568
+#define ML_KEM_1024_INNER_PRIVATE_KEY_SIZE 1536
+
+/* Name mangling */
+#define _ml_kem_inner_generate_keypair_itch _nettle_ml_kem_inner_generate_keypair_itch
+#define _ml_kem_inner_generate_keypair _nettle_ml_kem_inner_generate_keypair
+#define _ml_kem_inner_encrypt_itch _nettle_ml_kem_inner_encrypt_itch
+#define _ml_kem_inner_encrypt _nettle_ml_kem_inner_encrypt
+#define _ml_kem_inner_decrypt_itch _nettle_ml_kem_inner_decrypt_itch
+#define _ml_kem_inner_decrypt _nettle_ml_kem_inner_decrypt
+
+struct ml_kem_params
+{
+ size_t inner_public_key_size;
+ size_t inner_private_key_size;
+ size_t public_key_size;
+ size_t private_key_size;
+ size_t ciphertext_size;
+
+ unsigned int k;
+ unsigned int du;
+ unsigned int dv;
+ unsigned int eta1;
+};
+
+size_t
+_ml_kem_inner_generate_keypair_itch (const struct ml_kem_params *params);
+
+void
+_ml_kem_inner_generate_keypair (const struct ml_kem_params *params,
+ uint8_t *pub,
+ uint8_t *key,
+ const uint8_t *seed,
+ uint16_t *scratch);
+
+size_t
+_ml_kem_inner_encrypt_itch (const struct ml_kem_params *params);
+
+void
+_ml_kem_inner_encrypt (const struct ml_kem_params *params,
+ const uint8_t *pub,
+ const uint8_t *msg,
+ const uint8_t *seed,
+ uint8_t *ciphertext,
+ uint16_t *scratch);
+
+size_t
+_ml_kem_inner_decrypt_itch (const struct ml_kem_params *params);
+
+void
+_ml_kem_inner_decrypt (const struct ml_kem_params *params,
+ const uint8_t *key,
+ const uint8_t *ciphertext,
+ uint8_t *plaintext,
+ uint16_t *scratch);
+
+#endif /* NETTLE_ML_KEM_INTERNAL_H_INCLUDED */
--- /dev/null
+/* ml-kem.c
+
+ The ML-KEM (Kyber) key encapsulation mechanism, FIPS 203
+
+ Copyright (C) 2024 Red Hat, Inc.
+
+ This file is part of GNU Nettle.
+
+ GNU Nettle is free software: you can redistribute it and/or
+ modify it under the terms of either:
+
+ * the GNU Lesser General Public License as published by the Free
+ Software Foundation; either version 3 of the License, or (at your
+ option) any later version.
+
+ or
+
+ * the GNU General Public License as published by the Free
+ Software Foundation; either version 2 of the License, or (at your
+ option) any later version.
+
+ or both in parallel, as here.
+
+ GNU Nettle is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received copies of the GNU General Public License and
+ the GNU Lesser General Public License along with this program. If
+ not, see http://www.gnu.org/licenses/.
+*/
+
+#if HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include "ml-kem.h"
+
+#include "memops.h"
+#include "ml-kem-internal.h"
+#include "sha3.h"
+#include <string.h>
+
+static inline void
+H (struct sha3_ctx *ctx,
+ size_t len,
+ const uint8_t *msg,
+ uint8_t *dst)
+{
+ sha3_init (ctx);
+ sha3_256_update (ctx, len, msg);
+ sha3_256_digest (ctx, dst);
+}
+
+static inline void
+G2 (struct sha3_ctx *ctx,
+ size_t len1, const uint8_t *msg1,
+ size_t len2, const uint8_t *msg2,
+ uint8_t *dst)
+{
+ sha3_init (ctx);
+ sha3_512_update (ctx, len1, msg1);
+ sha3_512_update (ctx, len2, msg2);
+ sha3_512_digest (ctx, dst);
+}
+
+static inline void
+J2 (struct sha3_ctx *ctx,
+ size_t len1, const uint8_t *msg1,
+ size_t len2, const uint8_t *msg2,
+ uint8_t *dst)
+{
+ sha3_init (ctx);
+ sha3_256_update (ctx, len1, msg1);
+ sha3_256_update (ctx, len2, msg2);
+ sha3_256_shake (ctx, 32, dst);
+}
+
+#define MAX(a, b) ((a) >= (b) ? (a) : (b))
+
+size_t
+ml_kem_generate_keypair_itch (const struct ml_kem_params *params)
+{
+ return _ml_kem_inner_generate_keypair_itch (params);
+}
+
+void
+ml_kem_generate_keypair (const struct ml_kem_params *params,
+ uint8_t *pub,
+ uint8_t *key,
+ const uint8_t *seed,
+ uint16_t *scratch)
+{
+ struct sha3_ctx hctx;
+ uint8_t *p;
+
+ _ml_kem_inner_generate_keypair (params, pub, key, seed, scratch);
+
+ /* dk = dk|ek|H(ek)|z */
+ p = &key[params->inner_private_key_size];
+ memcpy (p, pub, params->inner_public_key_size);
+ p += params->inner_public_key_size;
+
+ H (&hctx, params->inner_public_key_size, pub, p);
+ p += 32;
+
+ memcpy (p, &seed[32], 32);
+}
+
+size_t
+ml_kem_encap_itch (const struct ml_kem_params *params)
+{
+ return _ml_kem_inner_encrypt_itch (params);
+}
+
+void
+ml_kem_encap (const struct ml_kem_params *params,
+ const uint8_t *pub,
+ uint8_t *secret, uint8_t *ciphertext,
+ void *random_ctx, nettle_random_func *random,
+ uint16_t *scratch)
+{
+ uint8_t m[32], buffer[64], *r = &buffer[32];
+ struct sha3_ctx hctx;
+ struct sha3_ctx gctx;
+
+ random (random_ctx, sizeof(m), m);
+
+ H (&hctx, params->public_key_size, pub, buffer);
+ G2 (&gctx, sizeof(m), m, 32, buffer, buffer);
+
+ _ml_kem_inner_encrypt (params, pub, m, r, ciphertext, scratch);
+
+ memcpy (secret, buffer, 32);
+}
+
+size_t
+ml_kem_decap_itch (const struct ml_kem_params *params)
+{
+ /* The scratch space consists of two parts: the first part is used
+ for encrypt/decrypt and the second part
+ is used for a new ciphertext (for implicit rejection).
+
+ This makes use of the fact that:
+ - _ml_kem_inner_encrypt_itch is larger than
+ _ml_kem_inner_decrypt_itch
+ - params->ciphertext_size is multiple of 32-byte blocks and
+ therefore no alignment violation
+ */
+ return _ml_kem_inner_encrypt_itch (params) + params->ciphertext_size;
+}
+
+void
+ml_kem_decap (const struct ml_kem_params *params,
+ const uint8_t *key,
+ uint8_t *secret,
+ const uint8_t *ciphertext,
+ uint16_t *scratch)
+{
+ uint8_t m[32], buffer[64], k2[32];
+ const uint8_t *pub = key + params->inner_private_key_size;
+ const uint8_t *h = pub + params->inner_public_key_size;
+ const uint8_t *z = h + 32;
+ struct sha3_ctx hctx;
+ struct sha3_ctx gctx;
+ volatile int ok = 1;
+ uint8_t *ciphertext2 = (uint8_t *)(scratch + _ml_kem_inner_encrypt_itch (params));
+
+ _ml_kem_inner_decrypt (params, key, ciphertext, m, scratch);
+
+ G2 (&gctx, sizeof(m), m, 32, h, buffer);
+
+ _ml_kem_inner_encrypt (params, pub, m, &buffer[32], ciphertext2, scratch);
+
+ /* K1 = KBar2 */
+ memcpy (secret, buffer, 32);
+
+ /* K2 = J(z || cipherText) */
+ J2 (&hctx, 32, z, params->ciphertext_size, ciphertext, k2);
+
+ ok &= memeql_sec (ciphertext, ciphertext2, params->ciphertext_size);
+
+ cnd_memcpy (!ok, secret, k2, 32);
+}
--- /dev/null
+/* ml-kem.h
+
+ The ML-KEM (Kyber) key encapsulation mechanism, FIPS 203
+
+ Copyright (C) 2024 Red Hat, Inc.
+
+ This file is part of GNU Nettle.
+
+ GNU Nettle is free software: you can redistribute it and/or
+ modify it under the terms of either:
+
+ * the GNU Lesser General Public License as published by the Free
+ Software Foundation; either version 3 of the License, or (at your
+ option) any later version.
+
+ or
+
+ * the GNU General Public License as published by the Free
+ Software Foundation; either version 2 of the License, or (at your
+ option) any later version.
+
+ or both in parallel, as here.
+
+ GNU Nettle is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received copies of the GNU General Public License and
+ the GNU Lesser General Public License along with this program. If
+ not, see http://www.gnu.org/licenses/.
+*/
+
+#ifndef NETTLE_MLKEM_H_INCLUDED
+#define NETTLE_MLKEM_H_INCLUDED
+
+#include "nettle-types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Name mangling */
+#define ml_kem_generate_keypair_itch nettle_ml_kem_generate_keypair_itch
+#define ml_kem_generate_keypair nettle_ml_kem_generate_keypair
+#define ml_kem_encap_itch nettle_ml_kem_encap_itch
+#define ml_kem_encap nettle_ml_kem_encap
+#define ml_kem_decap_itch nettle_ml_kem_decap_itch
+#define ml_kem_decap nettle_ml_kem_decap
+
+#define ML_KEM_SEED_SIZE 64
+#define ML_KEM_SESSION_KEY_SIZE 32
+
+#define ML_KEM_768_PUBLIC_KEY_SIZE 1184
+#define ML_KEM_768_PRIVATE_KEY_SIZE 2400
+#define ML_KEM_768_CIPHERTEXT_SIZE 1088
+
+#define ML_KEM_1024_PUBLIC_KEY_SIZE 1568
+#define ML_KEM_1024_PRIVATE_KEY_SIZE 3168
+#define ML_KEM_1024_CIPHERTEXT_SIZE 1568
+
+const struct ml_kem_params * _NETTLE_ATTRIBUTE_PURE nettle_get_ml_kem_768_params (void);
+const struct ml_kem_params * _NETTLE_ATTRIBUTE_PURE nettle_get_ml_kem_1024_params (void);
+
+size_t
+ml_kem_generate_keypair_itch (const struct ml_kem_params *params);
+
+void
+ml_kem_generate_keypair (const struct ml_kem_params *params,
+ uint8_t *pub,
+ uint8_t *key,
+ const uint8_t *seed,
+ uint16_t *scratch);
+
+size_t
+ml_kem_encap_itch (const struct ml_kem_params *params);
+
+void
+ml_kem_encap (const struct ml_kem_params *params,
+ const uint8_t *pub,
+ uint8_t *secret, uint8_t *ciphertext,
+ void *random_ctx, nettle_random_func *random,
+ uint16_t *scratch);
+
+size_t
+ml_kem_decap_itch (const struct ml_kem_params *params);
+
+void
+ml_kem_decap (const struct ml_kem_params *params,
+ const uint8_t *key,
+ uint8_t *secret,
+ const uint8_t *ciphertext,
+ uint16_t *scratch);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* NETTLE_ML_KEM_H_INCLUDED */
/hkdf-test
/hmac-test
/knuth-lfib-test
+/ml-kem-test
/md2-test
/md4-test
/md5-test
meta-aead-test.c meta-mac-test.c \
buffer-test.c yarrow-test.c xts-test.c pbkdf2-test.c \
x86-ibt-test.c drbg-ctr-aes256-test.c \
- slh-dsa-test.c sntrup761-test.c
+ slh-dsa-test.c sntrup761-test.c ml-kem-test.c
TS_HOGWEED_SOURCES = sexp-test.c sexp-format-test.c \
rsa2sexp-test.c sexp2rsa-test.c \
sc-ecdsa-sign-test sc-curve25519-dh-test sc-curve448-dh-test \
sc-ed25519-test sc-ed448-test sc-sntrup761-test
-TS_SC_NETTLE = sc-cnd-memcpy-test sc-gcm-test sc-memeql-test sc-slh-dsa-test
+TS_SC_NETTLE = sc-cnd-memcpy-test sc-gcm-test sc-memeql-test sc-slh-dsa-test sc-ml-kem-test
TS_SC = @IF_VALGRIND@ $(TS_SC_NETTLE) @IF_HOGWEED@ $(TS_SC_HOGWEED)
TS_SH = symbols-test
--- /dev/null
+fb25dbafa2cd7dce 979be90e31179fcc c24aed8a86d60c3b 84dd6f701b249afb
+eaee926f05859f81 8cb356fad2593b63 40b6e59480d7e78e 54c54d3178bde122
+f0d3010ba5bf2b65 468220088df430e1 974416e12bf5b3b3 eacc2a3abfc03846
+0d83257a8cc7f428 3c6b3d0070da8c8b ceeb976c0d708d05 6f04c86e35b81e99
+162ac72618f3a398 32fb90b378dc914e 0732f3140049b149 292c8d00addd9c05
+22f3bb1775074aab 4f1e279b5946e88d 7c46ccff453b5562 1817b8411e24bd0b
+90bdc275822a8164 ba11f9477ae9b03d e7dea010100b164e 02a91f0a27b84b58
+5cc48d4ab84b0a17 27454bbe84b1e8b7 23c2bc7a4efbfa65 7f08e7ad2670cdc4
+97d534f307246265 c89ab4066e2e1101 282a328e00cd1b58 e4d23f24cc364cd9
+2f891f4815ffd974 ed36c4d29e3c0c7f 302f0e912e108022 2134ed6c973c8635
+062f63a39762ec96 c883a012f369566b 62fa5afc142e1e28 4675e7c1eb474453
+3eec5de95ab8adac e27259ddf76553b4 82cdb83f1414c663 07389f82a51b949a
+facacf5e38d67745 6a8ca1806cc82e3b ea884edc7b4c5ed6 6007b143f1a19afe
+1a5540fa69f999fe 86386fe1e83fc0e5 7423df35e82749ac c856d3f05efb9591
+69cf03c9cb3d11d8 8fba1f85979f213f c59f084b01f4febd 9cb560c0f969f8f0
+21c30644fc8721cd 12e2e2bb0014b39d 9fb4916fd38c6f8d 9b02d67dcda44332
+dc519528a86dd516 1e8b4c100cdfcc58 e3e05763e9fe5e69 cc5d5c28e6d2ab24
+a4bf853264a3cbda e0a72aa380d37cd0 d306770d711bba1d 55a13ee7ca017025
+56b57be5f002fdb6 ce00de00cef28690 92803ce44f4944a6 0cca2b30978f39fa
+644a96a66156705e f1e473bf38eab139 aec783230472ca49 d071a817375191b8
+91a9bf63723bf028 30d1f443660b33c5 ebcebd8fe04be481 2409e82ad48a21c5
+0c241ceed5126ab4 0148ade08e12b381 623e5471d173e272 2daab90859150260
+88537eead054c720 7ffa1b68f9cc75dc 34d540b7933f78fc fe5728841af808c0
+fb9d83f6a80ebce6 b51534370db55e27 4b74d216c249759f 80d9494ea1fe0ad0
+58f057fe3c72759f 5f787b35b13c3fbe c4b730244c0056fe 694d801c021dfc1f
+179ff6bb8435878e ab8936ffdcad68ff bcbeadd1bacd3a69 22759da01e72ad93
+3f34d10f29d74470 f70632a3d6daba1b 069de9459d15e58a e12130e2414df92c
+36dcbdfe2ec3eb17 e37393035ed810fb b857d971ecd41347 b09c5c8deeab060e
+2759549a05c37a2c 93f30cf906a9c599 91da921848363ceb 06cf9914e76e1635
+aa0337a540470c9b 3e58d152fe692ab3 a1ab5f3e5c725984 28dfb9d46e77c320
+01cc1e942902a4a1 cd94d526042d3c16 ae79a7f440f06acc 331e445e47fbcea3
+ad5b2d4237e320c3 df1fd16cba99ad93 b136d971f4d72338 98f1ed5e4017e4de
+5b2243e6add776c4 591e28b6f4a5ffa4 ad7d273708d2c7c8 2ba28a0d621e9a10
+fae863750c8fcbab ccf3f1d92e9e2fbd 5d3d44b6c4c1a1a7 3c34523356a8b8db
+1b8e7e6af8b9a02f a03c705dec578d6e ce7f1ab9c9498ffb 1e283142b258342b
+53959b6e60bd23fd a24a53447049a6f5 bd525b6e12dd60be b5cc7ba0e245edae
+a2489ac0acabcdba 4c6113f35abfe30d 69332bb6b05dd143 0fe9a6aac0aae856
+f0391ac308140750 85f8b784439edd1b cf55fdfa0142424f 7a9e0a92142af397
+9c3d608d2ce99b9f 63f9b3d487471f75 d2c43ffbd137487d d9d9a8931d429922
+61e67fb1c531bc40 500711fb83b2aa84 c308ad061be63969 8f3f2dfdb72864d9
+50f0888a961261bc a7c0dbb78b9bdfb8 024a51e3488d87aa ef8fd703a859e538
+886f0de88a16ac90 d2c596622e34e2e8 d9685f918b6be86a b5e3bd73194a21c9
+a4db53fe0c88e027 d8fb0621592ba8a8 748267ce6ebedfa7 5144e2de1c1b39fb
+158095f9fea12772 216a718e4729e583 b1516d8bddf13736 946073aa71e72f9a
+a068dd6c3e6d2c7d 6bc66711b94bd75a d558dcdd77a19500 96bb3922a482fd03
+b8ed9ba53dec0083 a8b2192848cef509 2d50ff687623a2ad dcba7d5e9b15759d
+bb535b6c1aba01cf b857bcadc6506f0f 3e73dd649bc83a05 faa60cbed656f545
+732e30a838f95c78 79d63077c18584e1 91e2f844d44ffd63 c9223d61e3813685
+6dfef610bd812da0 b8e18ff2465a0fe9 f4658af94ed948b1 3b4e710af03d3620
--- /dev/null
+39690870b765ddf5 a0b7092773ec1911 637e8a80307a865a 24e3012fbacc0fd4
+31d12a44b38cc685 335c858714026187 e8f641933291cbe0 b678d78944b17d7d
+a605dec011b8681e 113701c007455315 6ee11530a4b63b8f e886637b524de273
+3d039591230cd90c 1ebab61e3a5762e4 6b4e6067c6c4b280 f371a3d8bb683924
+2dd3e381b41a3624 396c2c557d180993 4a901d8091731a43 a32da32ec9fa860f
+fc4ad09022b944c6 54980d2f928773b5 bbbe048a21db3f67 167ea7f2b1562460
+14accdc24455f5d1 b0f7171d29caa43d eb1ce32513078b49 5ac09c9b6793497b
+b593570cf8aa2d1f 7549e5d54fa5a339 b4281c90d75a9d01 86b7322129b90b1d
+f6a39892c60a613d 55e4a46ec07b69b6 af96255617c77951 958a15b71dc48075
+562a236aa3250089 09cf75993cd58aa8 1658750985fa593e f6c0400ba07bf119
+c7380b1d61751a43 90a398b6205a6895 a857a463ec931fc2 62d89b069d6cb3ac
+9bb4e5272f35ca61 2d8346b654277081 86c9422a37332b99 55bfba7080454cb5
+972397839b546521 9ec6024d08a46ec4 b29a15249653f413 fda1c99e82c144e7
+bcd9e17c19c2c3d4 3c4792f91ea4d848 7567392af43a5134 80975959e50cca55
+dc89ab0a19a313b1 b7e6adbd7a147728 1bd128b2c0f867cc d13877248e584488
+2f48b878e536d520 8716f11b75051033 e9a30de9afbba663 05e1ba265686b29c
+3186fb3ca1952936 fabd2ea931e0d74e 4d849cb685bffc38 c9e29559de6aaf2e
+b4017c543eb9d597 32b421c3a5cb5781 bb60f1a953f07d79 37b3651305e1d46e
+15569321721e3104 94c2ec16c843b3b4 d9831809065bda8f 4e5a17e80123312c
+065c03ace623af55 89ce361c913bda35 5a031e42c54eaba2 4af3f6848e6c4932
+427ae2a09d25808b df0288d4c245ea29 73c261cb29a6afb1 3c6058a3a19f1167
+3a198f86a2511138 37cda27f2304a1e3 d75c8bb88e6c67a0 06cc63dac90017b8
+65dc0268efc53e2c b75cc6f1008b3483 9cc80b26a019440c 0d34132bc4690519
+131de15434b730b3 a2492f6ef6471cf1 c5568463a3387102 135eb1a8635f0a63
+e33176914b40cc24 94002c0e19c38a0d 97c0ca5632261519 193030f33acec681
+25d33c5af26a9f97 b1b181a00e4e9144 a2d4811d7654f9b9 58cce126e030a7fe
+c045a0bcb82ed405 09643f3f5736b652 116a4008eda65fa1 895ec82390c2713b
+4303bb6e7b4b4164 29d8abbc497b9890 7224d065b3dc5a01 7907bbf7079e08b7
+70afd059a31a3093 3580ef49b5c48b0a ce675697d6b10419 92db622460923769
+54980aa03dcfcb5a dea36b0b2138ae34 9d5e270f0d83640b e9885cc9371c6490
+c1f39959c9a192e5 84dff9cb2d8c2297 b117b9d7627ac5b2 d29335558718a5a7
+c34564b0c0a1105f 0a00e0084aca185c 5a54741e4b4053a4 31713678f5951d3f
+e47e0719a082017a b73b892ef3c77ecb 170bf386ab36c898 76bc8ae67b0cb82e
+e42793d9d7435172 043e8ca3a8e1a831 97891121932a0ab2 ef46789eab0bedf5
+a5707a4b10035bd3 31b01e298370e112 443a48d96ca95038 32e3495dd2e57137
+4c1f57b6b9a0a074 aa29736c488fe1d8 23662abd3a379ca4 3007de317392d332
+a6826ace381af4c8 2c31f7c781788c70 5c4e6f06b1488850 aae55b6872731570
+444db49ac9a53e96 35816c1c537d2430 f922124317592b36 a68685859ef334b2
+782a5072a661c55c 3929497557231947 4db4e33dffdc5e88 aba83b6b8d468753
+c88ba898db116cf0 415db41c17d34646 2bbac4a44207d0c9 3a4b71c8d00d47b9
+69c690abb371c0bb e1a367a3046643c4 66c867e341805eb4 35f8316358f69e6a
+4976bb54abd90aa9 63b52bdfc93ba27c 833bf5ccb4a2ca5b aba12d70016acb87
+5582416ba1a82246 cae8489647b36990 f9128e350407cb61 4c926e492bb6d780
+21e73cb54641317f f282b9436462183b 9375a5d32879355a 96215b31ace09c93
+779240260eb8b974 fe049407229b808b 7818142c3a071cc5 561f56593e760534
+6c63817feb0b836a bb786077bc7a7e35 11275c160ba9017c 57774e9503048c29
+b959f5c9e354a8e1 37cd72c873ad1978 f69324dc282504e0 a221fb1b740004a6
+3aa7a2d33e00bd0d a29962b8f30233c7 8317f22ce7d068f1 6c1722994225e800
+491e05723201d81b e63e10d05502e1ff 54580492d7dc5682 ebf09e85773b4e61
--- /dev/null
+042c24a9415fedeb 4932f34ec4d30562 112740e60221697f fecb24da0888d714
+56cd7924e9669db0 1511ebc3abf6ec2c 291146fdc90eccc3 a270bca938332d1a
+09019cecc35f8c7f 8fc419622185d5b7 34865c2dd4a634d0 81b098ea311a0291
+69c973b643c062cc 7e31d73876731dac f830955a7f73b9bc c9d6b6ac4168f747
+885d3a3c01ca4aef a20ef5b55fb176ae 90939c12002ba932 4752aa2a1df78f3a
+6834fee50b5165a4 ae0bcaac06bcc6a9 9e94a69e81e65207 f52ac11088ecba90
+1612ce8ba67788cb b69d137479f3a7ff 2513fb8320ca946d dca952d63a67a5a0
+ab295249c76169a5 e09915bb7dfbf2c8 76c897463c2b9a97 3e5906c410d7a04f
+aa0d2813c48cc5bb f733c4a706139a19 90fa9b1e78a98658 364250837b34f812
+0746624ad67c2fd8 c5d92c3a0ff300c0 94988cb077fa6554 7e55940357aff182
+66cdf511e74069e4 a85797564800d377 ace053fea919bbc6 4869355f0618813e
+603c1e5b552d624d 37924d64b83471c6 186ef763e9f319ca 41009133360d45cc
+fb3c8667d3abf1ea 7ce4393683ec9ebf 88b3cd3c3d30a6bf 66d831fe235cb7e9
+5ae14321fdb76ea5 9345ddc21d4f6c5d 7f5105a67c9cdd68 18f07223ee97518f
+a666e526a0f48967 7b004705770e5f2b 68aed90a1e69c54b d0a6901c766b3477
+c1da346c95217f5b 8a4475b2d6c0a7b2 708a4f519eecd1a6 7b6a3765003c1efa
+308479acb7584b4d 389aa0f3200578c2 836ab4ab53268679 3ba9c078a1ec5877
+55c6dfd5b7edf416 84a3465cab3d0de8 0e7b83c16e7953c7 bc7a313b2dbb68b2
+04ec7669730ab3ec af610c9158230323 a86a4b8ab0172a8f 7e92825f8c7f1362
+cb4ca4a4ed1973c1 d620120a638ef88e ae78c11f90b05608 09591293a3db5d54
+09ce3c38817d1c91 7eab8050e8c69aa6 c8f33178b01a9e6c d31db60b15fb7445
+a4149264d984fb86 aa5eb6a77f700e7f 5890e1abc2c715a4 5b23192bd2794ada
+65be8835f2db9563 b32d64b65957224d ce30726a6368af7a 3e016b7712a4671d
+f346173411ef9311 9b071aa19767c644 74dd317174c1047c e60155967982e661
+be441c9363a1cfc3 3c7ca7ce6a620cb1 3879d75c92e322c5 0c9c0c6a041492eb
+5ada1b267fa0138b 63a3efd8a2c3f933 0ce805f551606523 0e2b9c89a2ac3bb0
+c231f0f8a55265cd 143c22db873fa900 68027a3e21275431 922fec6aa8e5f544
+a3389f8cdb051eb8 49c5250d27d63d8f 398dc2a172e8016f adb223d47b9dd55b
+c01230400995b3cf a51b16c903eb8b4e 4a9704e748006cd1 710925b75000ccd5
+724f3cd81bc68c93 64e36bfc97284227 4dfaaa2d85816298 c51b656092522c89
+5b9b1b19399a1fb2 8b4534952d51c6eb 16ce12a16838c64e be942c90a06890c3
+246c1800c0f56338 34932744b8b54783 64d7272f80c97d5a 0e19a37e6b182812
+a0604b5c353274a1 39da2948397ed142 86f902b5429b7ff5 f4c84abb3fa7e1a8
+05974c89aa07c906 109a73c7b1b05829 67a2fff137b289ca 0afa3b07c221750a
+7cc960b6a679b66a a37373585f8459a7 e3725bc718382fa0 3bd433afac481be5
+a09b6d2075dbbc9c 4cbb92bc915090d5 03a5accafcc2a360 142765fa2599a55d
+c05a6a2d5300f863 bfe7db0574a102d7 6c1773a095f3828b eab7b0b945b19d0c
+288294b6ecfa551f ba26fb58ba8ff394 99abac74b9909955 92cce5a2ec8625bc
+e26c4360875b65c1 d1831a1854303ce7 80198551015c2c62 f9aafb70b1a15834
+d467a642b180bf99 393b22774e0b3706 421a7ae2cf41281b ae15891e429f7431
+4ba63b02e0a661c2 891ea947b7571cc4 7ed749d70b059520 3dd7574afdd6aedf
+8cbe55fa5d495362 dd534c37b926ebda 468a48cb701c0565 a81994c4afc59922
+3ac963677c966321 1d7b8698d533673e 8356c4bb6f77b6ca d027395270625f0a
+80d5b5a881e61c95 53c165f9ca2b309b a7b21cb516392955 617f9884a75bc797
+f1098d226f821985 077669753018841a 9f290170252771d1 4ba8fb5bcdfb33aa
+a17b6032d3540a08 b85846212ab0c404 30a209a7244420b5 a81357ff669a4944
+291aebb50ecc3ea8 962236d2c4f8cc03 54074827d0a37ebc a11292a9d41a7f06
+d97c37c2541593af 33ab431935cb4522 370651a784cc5529 ccca9296518bf872
+39690870b765ddf5 a0b7092773ec1911 637e8a80307a865a 24e3012fbacc0fd4
+31d12a44b38cc685 335c858714026187 e8f641933291cbe0 b678d78944b17d7d
+a605dec011b8681e 113701c007455315 6ee11530a4b63b8f e886637b524de273
+3d039591230cd90c 1ebab61e3a5762e4 6b4e6067c6c4b280 f371a3d8bb683924
+2dd3e381b41a3624 396c2c557d180993 4a901d8091731a43 a32da32ec9fa860f
+fc4ad09022b944c6 54980d2f928773b5 bbbe048a21db3f67 167ea7f2b1562460
+14accdc24455f5d1 b0f7171d29caa43d eb1ce32513078b49 5ac09c9b6793497b
+b593570cf8aa2d1f 7549e5d54fa5a339 b4281c90d75a9d01 86b7322129b90b1d
+f6a39892c60a613d 55e4a46ec07b69b6 af96255617c77951 958a15b71dc48075
+562a236aa3250089 09cf75993cd58aa8 1658750985fa593e f6c0400ba07bf119
+c7380b1d61751a43 90a398b6205a6895 a857a463ec931fc2 62d89b069d6cb3ac
+9bb4e5272f35ca61 2d8346b654277081 86c9422a37332b99 55bfba7080454cb5
+972397839b546521 9ec6024d08a46ec4 b29a15249653f413 fda1c99e82c144e7
+bcd9e17c19c2c3d4 3c4792f91ea4d848 7567392af43a5134 80975959e50cca55
+dc89ab0a19a313b1 b7e6adbd7a147728 1bd128b2c0f867cc d13877248e584488
+2f48b878e536d520 8716f11b75051033 e9a30de9afbba663 05e1ba265686b29c
+3186fb3ca1952936 fabd2ea931e0d74e 4d849cb685bffc38 c9e29559de6aaf2e
+b4017c543eb9d597 32b421c3a5cb5781 bb60f1a953f07d79 37b3651305e1d46e
+15569321721e3104 94c2ec16c843b3b4 d9831809065bda8f 4e5a17e80123312c
+065c03ace623af55 89ce361c913bda35 5a031e42c54eaba2 4af3f6848e6c4932
+427ae2a09d25808b df0288d4c245ea29 73c261cb29a6afb1 3c6058a3a19f1167
+3a198f86a2511138 37cda27f2304a1e3 d75c8bb88e6c67a0 06cc63dac90017b8
+65dc0268efc53e2c b75cc6f1008b3483 9cc80b26a019440c 0d34132bc4690519
+131de15434b730b3 a2492f6ef6471cf1 c5568463a3387102 135eb1a8635f0a63
+e33176914b40cc24 94002c0e19c38a0d 97c0ca5632261519 193030f33acec681
+25d33c5af26a9f97 b1b181a00e4e9144 a2d4811d7654f9b9 58cce126e030a7fe
+c045a0bcb82ed405 09643f3f5736b652 116a4008eda65fa1 895ec82390c2713b
+4303bb6e7b4b4164 29d8abbc497b9890 7224d065b3dc5a01 7907bbf7079e08b7
+70afd059a31a3093 3580ef49b5c48b0a ce675697d6b10419 92db622460923769
+54980aa03dcfcb5a dea36b0b2138ae34 9d5e270f0d83640b e9885cc9371c6490
+c1f39959c9a192e5 84dff9cb2d8c2297 b117b9d7627ac5b2 d29335558718a5a7
+c34564b0c0a1105f 0a00e0084aca185c 5a54741e4b4053a4 31713678f5951d3f
+e47e0719a082017a b73b892ef3c77ecb 170bf386ab36c898 76bc8ae67b0cb82e
+e42793d9d7435172 043e8ca3a8e1a831 97891121932a0ab2 ef46789eab0bedf5
+a5707a4b10035bd3 31b01e298370e112 443a48d96ca95038 32e3495dd2e57137
+4c1f57b6b9a0a074 aa29736c488fe1d8 23662abd3a379ca4 3007de317392d332
+a6826ace381af4c8 2c31f7c781788c70 5c4e6f06b1488850 aae55b6872731570
+444db49ac9a53e96 35816c1c537d2430 f922124317592b36 a68685859ef334b2
+782a5072a661c55c 3929497557231947 4db4e33dffdc5e88 aba83b6b8d468753
+c88ba898db116cf0 415db41c17d34646 2bbac4a44207d0c9 3a4b71c8d00d47b9
+69c690abb371c0bb e1a367a3046643c4 66c867e341805eb4 35f8316358f69e6a
+4976bb54abd90aa9 63b52bdfc93ba27c 833bf5ccb4a2ca5b aba12d70016acb87
+5582416ba1a82246 cae8489647b36990 f9128e350407cb61 4c926e492bb6d780
+21e73cb54641317f f282b9436462183b 9375a5d32879355a 96215b31ace09c93
+779240260eb8b974 fe049407229b808b 7818142c3a071cc5 561f56593e760534
+6c63817feb0b836a bb786077bc7a7e35 11275c160ba9017c 57774e9503048c29
+b959f5c9e354a8e1 37cd72c873ad1978 f69324dc282504e0 a221fb1b740004a6
+3aa7a2d33e00bd0d a29962b8f30233c7 8317f22ce7d068f1 6c1722994225e800
+491e05723201d81b e63e10d05502e1ff 54580492d7dc5682 ebf09e85773b4e61
+d4ed29fb6eefc627 9c24822ebb0fe9b6 9246931ed0467352 b7e69e79f47cf6ea
+f36e9099a67947e9 7c78ade6c5b36316 336c025f16e7335b d81a3158d5afc87e
--- /dev/null
+b24174a5b00dbf52 0cb9e3783d482e03 ca3166d40d082a7b ab664845b617add9
+8c07c6a3c3204f81 2035683a1d4f10ac 1de764706cce96d7 5832a462a8b1b82c
+f471cbf808a26508 d9faa543f2cd9803 77d6f79436793806 4b6dd388c5297569
+63b12ca594b306ab 3f0ebbb6ed47601a ec1074a2b0d1b417 17f8c695f174ef73
+4052077e53dc9f47 316b6608b7edb54e a3631a36bb8d842c af27367c15c18ddb
+a7afe62aa5721333 84cb872555948a16 5f204c2cb4503c9d 8ace5f5217194a67
+ebd2a72f99562f98 b2b773b6965c071b f11deed395bc153e d6967492d88d5ef3
+2d05e008b7958a2f 36b9db06ccdc52a6 26417966b19c5079 a9892ba426a0362f
+b18e7ec07ffdc0c5 dbe264deec41bc83 a573599a25a8909b 2476682336cec9a3
+96201a000a9c1be7 92d9988fbc03c248 55c1b242ae27a127 cd36415cfb0d98cc
+bb9bd83af5988d74 3773acea4201ac93 5e7ccc46e92d8e84 a9d70cc626965429
+450980e0782ee11c d91169ce94bf89c1 4ec10b900eb4b771 29a859039ad1253e
+5657b261e9855bc4 b0f504c478d58f4a 388215a071516810 9526c2dac555007c
+66e10b79eb92471a cc9a640805bd947e ea45b66a2c02d5b7 c9029945b581666d
+470cd2654eb51c33 04ac52cb11382b86 28553b63742c41b2 93467b754df8f52a
+7b9a5ef2359bf340 25a9318df92b1471 ec529e895814999c 551356ecc9ca9456
+41067b16ac04b416 9cc2f8a3b9a00504 7ac1aa4df27ff284 c7ab19a800629b5a
+85b06834623ac018 d2e4ca1ca197d7b4 58c185be0ba9b470 3811f8628d13b690
+602544bd69afae21 5f5bdb51315cb570 d48d8b55120d5056 0e59594c8b5603fb
+cc7e484eaf591070 865fadd495c4d67b fc67cf1cb94acd50 c8970a226c0bc0ff
+a186bdc51dd235ac 8d085f348374c88c 6206e14723310430 6916e30635f0ab1b
+956644e02a4ee2bc c3246088d3d570a6 17a63150b32bd50d aa555dd6bb8b6d34
+c0cba83a41c23b48 b39708d7578d33c5 a60aa28430cb10ba 264d158abff301a0
+0732bd9553919043 6ad02f89315ce921 499c04305d81cfb7 997aba4b2d65639a
+34901b67972c9a23 55b5a10e91f955e0 a95ff33a21fa4a8b 8e018ea6e43f3446
+2daf95a29dcc719c 2b7eeae503504970 06f6ac53d28fcbf9 0845b02a8846c58d
+6494c0c603283476 af121767a9600c83 a9e92b8d7b19c268 0b1948044b807c9e
+a7ec94be30cf3aea 676d16159fa3bc97 c055ed0a439af5c2 f085bc0680a5ded6
+820843c3d3f65138 e5ace48c7a0c1103 7161674826084fd9 ba3113223f18564a
+9b8dd98472d1837a b85b66e2c2638a4a 8d9dd6c361ba6b86 629fed9b6e76dc75
+b258908b750117e8 a4763a1c0c0bbe5e 2616c5d55b607203 71f06d63893061fa
+6b3c76a600179b52 f0c319f47a10189a 0f566a7292c40cd9 980c0112f265660c
+3b4f60736a969345 4a7b861f834d35b8 38f8a647771630bc bc1f23f6aa887cb6
+cbd582cc2240cdba 864167506a43c434 c27ead754484d232 a83bc40c22183068
+16030a20765a5470 217e5b2c90846344 cd8bc2c498b770e8 3cd1959dc152bccb
+4aceab36abf7f361 8c1247f5db201310 c0a1e574fa547c39 8cc5a44ac23685b6
+4d07b8f6614016c4 271b71c650a8b520 a5afa08ba04ee516 46b8a7fb652d3af5
+7a4010558f856fac c9911e09b332c587 0edb61e8e850bb19 49ae5755c1fba2cc
+472073029fd6542b cda71b7952bcf811 608f2a88291a04f2 664bb1112e27b123
+5b16c19203214e79 145a318c5110152d a36bb21aca738011 85d6b8b1f6a344b3
+3b3e550fb5dc29bc d19846e84074bbc8 f7580cd347b52f12 a7d1616c55a2cd1f
+5c4aa86702dd530f a05a641302a16127 468e85522e567570 b65fc3f834d85a20
+973a0eb2b210d581 2cfdfb881cc3aa06 ab4cb77bba7cdc6b cee53c020b3343b9
+bd9a8298ad2055ee 1a6070849140a862 88721815c7973477 3f4097cf4741cc96
+35a30c8100b20733 d3980b350393faac 4cd0e66e4737c681 dbbcc8d7953fa774
+54c422ad870e278b 1121c33c8273370e 5b686a6aab17fca3 b67a3040d6491241
+bf5e3072fbdc1e42 2413fa5b4e9ee91e b3c936e21a5c7856 942f44a55670a688
+a69e91a9a80bf409 4c301df705334dac b0cd929473829f34 f37947d22b55c062
+f4ccf703ee3c1cc0 ba7316dd658e6b6e 0815f8fc9a70b1bb a325ec32e2930916
--- /dev/null
+f7517c1258a61e19 36f15b11dbbb33a7 f7733cccb2d9493c bf29945c751e2519
+347aa3894541cc2f 1010d59044787254 7238c2fdea5764ba 0d098030962a0ec6
+bb816b077ff4ec2e f1e6b4ab45b21dc9 9ea433b4b8f4cb36 a41d1497a06bdc43
+cb79aa0f739e6286 afa063b908138fe8 37330e48a47a097e fadc3aacbaa059b3
+20b2b81dad5a9c27 b24a66d74b3aab48 e6e355aaf18074da 3e9be2418cc14338
+8153df649572036a bca2096c85839e03 4d34fca6b9530b07 e80534479a3bb6b7
+b09922fb4058a20b 2585a74c45c14ffe 076bf8d40cf5c922 e14a3d34325b5909
+729c870b36bcc179 64590e51ccde66b1 425acfafbc5cecd1 0fb168005c04c656
+54b7574150f18c23 62f18136a09cf120 29ba371e008029b4 b631021a252e756e
+3bc40e41030a3a2a 52205a917ef4b0a6 6a8279a8b67309a2 d35460085bbe18f2
+21bb72409f004a89 4ba1ae2a31141389 fb963db3f0c0da0a 179fa30926da2d81
+7aa6fff02bf65671 6aa87f7273b74774 1cbab3acfc112d39 42c193dc32a31a2a
+0425854206b51807 c960d93d6e361a5f 29a6f15a417fd01d 25e264c322c86963
+69ff5397edc52d6d 388bbad6206729ba 14d7855df4424ae9 c48ad11a19aaa2f8
+fbbe50bb6ac12083 85e80c740c916ab5 40504758f7879b0d 0b5b36c0053e564e
+15017e563966ef01 62966b0a6a330a40 79c9d01a89b43893 e38c4064a247b1f9
+8627eaab80a1603a 43c01ffc5d63dca4 daea501379caaff7 7bbf0c238b091318
+548168f4033b83a2 d2c6026ad2973ba4 3c01914b27dc2488 05c762d980e7b427
+252b222de59698ba ad02936e1135704c f80f531c13fb9828 d1199762794b6976
+2bfa3134bca20ad4 f799ce0b5f275866 54d981598172e191 b4b556457b27c1cd
+e17b2a9a47524664 39693622c68df260 8ca84b86bc553ccc ab9d9c842387b876
+4c946917e26409da 1c92122273ab6124 784d8b1475287a34 92e2a90d770bdd11
+6bf0fc0460c56a07 d86db686983a052d 7e01392c5b34f8db 41d339808d2a9aef
+44c845a6b67688ab 74fb1218e7af9d17 2de406be0a32cb40 710fc33098b82a21
+aa719124ea3d12a2 8e87043afe9b56cd c58534bb38e49751 2cb939cc3cb4d7d3
+adfb2c9f4db11100 d76a77bb2cfad308 f3171ad047841100 9b11e964d1721a12
+25a90a285073445b 9e389f72b46aacf0 8ec5db33f7e038d4 cb4c8ff023a5d8bb
+fd543bed672ed389 27807b285b0c3635 a1bf554729ea5955 95c1a1718122821c
+446e72ba7c5c95f3 cab365b27ce4a283 c745386f260320f5 6815a9704f4c2718
+d89f60754bd65434 a65063665b723033 ad8e2213b1562ec9 296a370b0c8d5497
+691718bffa1f65e2 6b3709b7a632945b 592fbea90588b0be f3877630212dfe76
+792b40a0b4e17316 1aa641119faf7890 5a7c3e59e3686a0b 1654e48ab9c22d18
+bca456d553dab343 6ee677ab7ab9ece7 416b7a90921a8742 a9269742616bf225
+72a2c8fabbafccd1 441e87c9ab64593a e50a5c9564834a08 851462afa41a3db5
+86d49835cbb8a5cf 5950b85abe5d1a64 f8c82129ac488000 474e5386b3429ade
+528345582a818501 0dc39d0da6873d29 bebf3954a56902ac 623ed9577103164a
+839b89be158ca639 c1ef483902a3a1ab 1513cceb62def158 d0078593321effa0
+57b0a17c854956a7 3c48d55c3b1511c4 b43316c95c18fb78 4452dc4d2c904d30
+206f17b4644a7553 44462a034c3d55f0 4de42843cad248e2 56c2616a98d61024
+b1d9547c86b37625 484c3373e0b786b1 220c7ec1a3e75715 277c014ac81ffc7a
+80135b90a9d65dfb dcb03050756adc26 949b1644bba4eff1 33becb67fba996c4
+958dc49c5824b882 4433aecbe468dbfb 3d46289f65b65282 04be31a8a22b828e
+a30766ce086e380a 6a94ec119c3ac900 5d2b8be47af0fa2e 7c008b06c7ca9827
+b7e6a247a7571795 4726e4d96ec82b7e bd469f9c646612c2 a785ec3ef1cb5cd5
+a76f7d006418b19f b3c8254a38132098 4d03f62244c72a55 aa19f60a63ee0b90
+0ba56287235d1d48 0e752ac905a57d3c 99b7c3210e103c50 fec53e430926cc10
+8f0240ce4e3a5116 645b5be79f03ac0d 378b00fda6206c5c 5cbc551851243e8e
+ac7c7b28aa13592f f38065d6f8b73a66 812aa415ce441624 76008288afaf1a02
+b24174a5b00dbf52 0cb9e3783d482e03 ca3166d40d082a7b ab664845b617add9
+8c07c6a3c3204f81 2035683a1d4f10ac 1de764706cce96d7 5832a462a8b1b82c
+f471cbf808a26508 d9faa543f2cd9803 77d6f79436793806 4b6dd388c5297569
+63b12ca594b306ab 3f0ebbb6ed47601a ec1074a2b0d1b417 17f8c695f174ef73
+4052077e53dc9f47 316b6608b7edb54e a3631a36bb8d842c af27367c15c18ddb
+a7afe62aa5721333 84cb872555948a16 5f204c2cb4503c9d 8ace5f5217194a67
+ebd2a72f99562f98 b2b773b6965c071b f11deed395bc153e d6967492d88d5ef3
+2d05e008b7958a2f 36b9db06ccdc52a6 26417966b19c5079 a9892ba426a0362f
+b18e7ec07ffdc0c5 dbe264deec41bc83 a573599a25a8909b 2476682336cec9a3
+96201a000a9c1be7 92d9988fbc03c248 55c1b242ae27a127 cd36415cfb0d98cc
+bb9bd83af5988d74 3773acea4201ac93 5e7ccc46e92d8e84 a9d70cc626965429
+450980e0782ee11c d91169ce94bf89c1 4ec10b900eb4b771 29a859039ad1253e
+5657b261e9855bc4 b0f504c478d58f4a 388215a071516810 9526c2dac555007c
+66e10b79eb92471a cc9a640805bd947e ea45b66a2c02d5b7 c9029945b581666d
+470cd2654eb51c33 04ac52cb11382b86 28553b63742c41b2 93467b754df8f52a
+7b9a5ef2359bf340 25a9318df92b1471 ec529e895814999c 551356ecc9ca9456
+41067b16ac04b416 9cc2f8a3b9a00504 7ac1aa4df27ff284 c7ab19a800629b5a
+85b06834623ac018 d2e4ca1ca197d7b4 58c185be0ba9b470 3811f8628d13b690
+602544bd69afae21 5f5bdb51315cb570 d48d8b55120d5056 0e59594c8b5603fb
+cc7e484eaf591070 865fadd495c4d67b fc67cf1cb94acd50 c8970a226c0bc0ff
+a186bdc51dd235ac 8d085f348374c88c 6206e14723310430 6916e30635f0ab1b
+956644e02a4ee2bc c3246088d3d570a6 17a63150b32bd50d aa555dd6bb8b6d34
+c0cba83a41c23b48 b39708d7578d33c5 a60aa28430cb10ba 264d158abff301a0
+0732bd9553919043 6ad02f89315ce921 499c04305d81cfb7 997aba4b2d65639a
+34901b67972c9a23 55b5a10e91f955e0 a95ff33a21fa4a8b 8e018ea6e43f3446
+2daf95a29dcc719c 2b7eeae503504970 06f6ac53d28fcbf9 0845b02a8846c58d
+6494c0c603283476 af121767a9600c83 a9e92b8d7b19c268 0b1948044b807c9e
+a7ec94be30cf3aea 676d16159fa3bc97 c055ed0a439af5c2 f085bc0680a5ded6
+820843c3d3f65138 e5ace48c7a0c1103 7161674826084fd9 ba3113223f18564a
+9b8dd98472d1837a b85b66e2c2638a4a 8d9dd6c361ba6b86 629fed9b6e76dc75
+b258908b750117e8 a4763a1c0c0bbe5e 2616c5d55b607203 71f06d63893061fa
+6b3c76a600179b52 f0c319f47a10189a 0f566a7292c40cd9 980c0112f265660c
+3b4f60736a969345 4a7b861f834d35b8 38f8a647771630bc bc1f23f6aa887cb6
+cbd582cc2240cdba 864167506a43c434 c27ead754484d232 a83bc40c22183068
+16030a20765a5470 217e5b2c90846344 cd8bc2c498b770e8 3cd1959dc152bccb
+4aceab36abf7f361 8c1247f5db201310 c0a1e574fa547c39 8cc5a44ac23685b6
+4d07b8f6614016c4 271b71c650a8b520 a5afa08ba04ee516 46b8a7fb652d3af5
+7a4010558f856fac c9911e09b332c587 0edb61e8e850bb19 49ae5755c1fba2cc
+472073029fd6542b cda71b7952bcf811 608f2a88291a04f2 664bb1112e27b123
+5b16c19203214e79 145a318c5110152d a36bb21aca738011 85d6b8b1f6a344b3
+3b3e550fb5dc29bc d19846e84074bbc8 f7580cd347b52f12 a7d1616c55a2cd1f
+5c4aa86702dd530f a05a641302a16127 468e85522e567570 b65fc3f834d85a20
+973a0eb2b210d581 2cfdfb881cc3aa06 ab4cb77bba7cdc6b cee53c020b3343b9
+bd9a8298ad2055ee 1a6070849140a862 88721815c7973477 3f4097cf4741cc96
+35a30c8100b20733 d3980b350393faac 4cd0e66e4737c681 dbbcc8d7953fa774
+54c422ad870e278b 1121c33c8273370e 5b686a6aab17fca3 b67a3040d6491241
+bf5e3072fbdc1e42 2413fa5b4e9ee91e b3c936e21a5c7856 942f44a55670a688
+a69e91a9a80bf409 4c301df705334dac b0cd929473829f34 f37947d22b55c062
+f4ccf703ee3c1cc0 ba7316dd658e6b6e 0815f8fc9a70b1bb a325ec32e2930916
+88a8fd05cd6da066 d2bab105299b3ee6 6605bd5a803760af 56a6033cb9d3b924
+0a064d6c06ceab73 e59cfca9ff640225 5a326aef1e9cb678 bf36929dafe29a58
--- /dev/null
+4ee24d9e0858b36d c755a9389f4fdbf4 38db8fbfddd2e2a4 1fbfe7313693e87b
+2bd86a2a5c952868 40a2e477f4aac12f 28319d892c30fe9a 120a09713369a17d
+5ec459c7e5dcd402 f9049bf6ff0f7d07 a7f18d4c1e3e0429 bf6d501eedd33e11
+4423a5c469273809 6101ec79233f20c5 8a6ea7e855c4e608 da7c9ee086eeafe2
+96f3214bd0b9264a e18069342ab493bb ee267401fedae19d 5f9224a11d911505
+cb3200c65f17c91f 88fbe25621402c93 9f071c48d6bc6acd 207c8c215e2ff23a
+b5fad94f2ce61003 c99de15195b36ade 08864043caea49d4 ea1d550978c49455
+b06afb4ba4f0c178 d30f953d47f02583 70fe8e686802085f dcb25598de439cee
+a186f848ae2e4acf 526e03755d0a89a9 41a08c5610c96dfb 3f47c693e7e899e1
+dd38dfd9126f3d05 751234abb82d2bba 4d347823b97293ae 2b58fd3c71d22167
+97da1ca453d600c5 a9a6b36ca23b9450 894a894a42c40b38 871f1e9e84b40a04
+112cc9a4b6e7b8de 59cae5d8389687db b1ea078f3cc93dc5 d0788a671530d9ff
+de5f2cb6a558ab38 e038d59ed1ef1fee 381afb6de0a77e13 33fc5b0fe3ea2dcd
+b84fb33795449ac6 dc322f4e5e09b2a4 62d3750ba426c042 71903cfe9a3f0222
+1b69e474f24b7db6 08492c01aac3f2fa 472a2469b6a8a949 a67c567d139d6f40
+b00df1aac1e6456f faa646e0debd7990 7905f28076f78ecb 3dd1a6493a40f3d1
+f8d89c71ad15d221 62264d0aa73581af 7a77eea43b856370 182348034810e60a
+902604b724e09ea4 638aab039982a64e f02c9c21259a381b fd3bf298efe4285c
+b538f79be01ccee1 a4a903a80132942a c6bcd4425bd197ef 014e7dbeffdfdd5a
+ad00da2a5e8de4ff f1e8e97f23f3f4be 38970ac09cb99d25 2cf2736059cfde17
+7ea6b36ea329b9dc 541c3dce61fac504 908857184c936c1a 1c4ac0c8dde9a66b
+4f3aaadeab2dbeb2 f2e6422a49a6b9c2 23df25a347207172 53da6dcfc0a82555
+3a1d2884e01a9706 0886fc30a1ad50e5 2c46f6f9b87274ad 6369fce4fdf3ff6a
+5d62d4ac82cbcece 902e4de4214b71a2 ca547c536380dca2 6f63f2be71b01eac
+68f42ad1399d3904 04aa5539a5995254 836fe6cf59c490b1 3cac01c69e50cdc0
+eba1c2f9978f4223 aa38da33639abe93 3b40f6e2751515ef ac9896465041d392
+2a4b043897083f7c c6daf1fd87b970bb 6d1d5e48b599fe6c d2afba5fce17e4bd
+4b0217e879fae34f c227ec132d6f7141 a48d14ded5772916 4a1d2b0bef89a162
+44ee114ab4e10864 8b7e80a7dd502b0d bd0c38af1d85af69 66bfb8e54237000a
+3f18c48efeb93ed6 2b41a9b341361d0d 7ae75d63a3a34dce e329996ab0630553
+f38bc0da14841916 2a31d386745c818e 2691411a7927e498 22aae9ea918bf49d
+6809290b57c1ba5e c212f135ac0b8ee9 45c0510cfed4db5a 84b617ba1525e996
+486728e1db87b6e9 9cc9a7ec4399b063 d3943fe4eb1933e9 0365a4916ca8d67d
+064df7d5b8dfc51e 337247cac3cffaed c5523276cdcb82b1 30d8e1c3fb6d7d69
--- /dev/null
+f255ce47334283b8 622be7ce76d7354e 3c4fe3f6c44f6bb2 5c9864ee0baeb576
+5950d88f438263ce 8b5a7a4c0fc4c95f 10c477a7521f9bb4 58b8aa55d2e43bdc
+86b72f0930ee428b 4c5a9c7116310f2a a5cb03ac1603c811 959ea9012d69cbce
+40b37cd890999cc7 4ff375c66f048b24 0363343cb7959988 56d560f4c712938c
+79466864d20b0be9 5419c9ea6a8e7203 a1986d10b6066912 42cef630941b1164
+58a41c83b7dc5b06 a97c840b116f2ce9 cfa87a1c1aa8c4fa c137de8498e8749b
+3638404271539b24 7183a32e7e4413b6 400e0f295788084e ea93b4a765334100
+5672d908c62b64b1 1b48414b505f3036 ee56cc4da88fef27 b2da974c9dd38c15
+0090b5b8a29bd7c5 975a8a959549044b 4daed52a7fa68335 308f40c9b768c582
+1f78cf068a694978 964f597408d09759 a19578624c64dc18 eab23082e599ec48
+8dfe016e4ba58977 e15b715c61249631 0219b9b4775cb51c 5df03b934f7473aa
+58a57c602cf17c59 93d30f52d753ac56 baca1a994742bc50 435e179a262b3c8e
+ece1513955c593e7 508b945f6e95cc42 68cbd45b2504082f b8b23d8906946a74
+ac2fb676bdbc39df 76b9b8450f49d283 c622784565b76b96 084dfc099ec2279e
+5bc13492561b4439 e32324b0050c5fe6 451974bf0d72750a c58bac046d218ac3
+97f65532acc78002 46ed1c8094fc8073 06bf88e2816ad13b 06f2898ca87c486a
+124b618156a090b1 058722abae389ab5 612ca2c2766ddef9 8202a6ab1097b392
+404ea151788528b0 7544325f851b4dea a2495138f929bbb4 026042b0a8cd3cb0
+a7d061927a717d48 77e0d9a409d6b125 361c99090afdf922 a776acada2b6a845
+22134b089d4b4280 20c83061a87816c6 a59263e636b5b2ec bca6a64e29600948
+d5b0b45600b8d473 a65b450b766d0251 b6915898bc3c1c2c 53b9679121f1f06c
+fb9604de0051ff4b 093939c907ab18c2 988646a90481bb99 f4153611c138be34
+be163b3abac44354 a774e9cb54fb2990 3367c78d27546749 9d22e83a11ca9b84
+45be9df3cb612069 222a8715a495d115 b4bc2457ab731ae7 ec1bd8ec9722ca98
+0958180ac2bd6789 8f4a72a675106d66 981b2e923c0ba40e 3234655d00b25d64
+62591c9c9c7a5349 1489d57a77b2510d 08b95b9c61c1784b a752f4a73023742e
+cb985dfb37808b16 d6c283cd4a06c5a3 ac401855e1dabe63 f9668bf7a661946b
+18230a1a5a7c19da 66ed08151e77a624 f579d4e44abe023a 1cd33459fcc3f1a6
+589426634d062d0a 75a387a0b7b8d802 a66b2106e0126450 0915b97307c85ecf
+331bcac35e4aa243 c837876d858afa8b 510c342708b38093 b2cd35d1ba68da05
+44794d172c6ca885 0a7f847b56998d8e 0b0a17144fb6f443 e3679767ca91b80a
+6caa8bb0e22bbac0 1c0eae1604b8a243 911672b3748c7f18 c531e3783d522039
+130057198d6f0989 e99641ab718da123 710bdb67b3b75ec6 6ba9cf459fe06c7c
+4f7959dd7281ff15 5940b09fb14aa55c d40b963ca3312c05 b36a5207c989428c
+16e5d288adb18a66 f74617ca39db8aa6 12d706dfec884c45 7aecd1aab598195b
+4ac971529fb7a883 492235e62112064a 0f6ff5bf4f1619a0 d03b96b511200996
+6b2df7c2f300b6f2 95df7fa2c453e194 9df6405309df7575 c7656c245edca9f6
--- /dev/null
+b8e17544c0493c20 0f8b15c8973a25be 28ad58442b916c80 74439e2d12cb2a46
+23065658c80017f8 475419c9a7fadc98 8888ade32b540aa7 7539c49f10b4a0ff
+e6a21271192a3908 e0583dc8788301c3 1777d116b5759b5f 189cfaba11cbd976
+067810bf939f9157 9440fa86fac692d1 25811329701381b9 7175317adc60bbc7
+585fc07f65a92b67 978684c225b96043 9c147c06d11d0423 896257bf8fc89e3f
+e8021ac3a6c81192 b3f96da3b2500245 41d92759bbf77ae3 6a1c9b1b1ab01b0b
+7f2b9917a579fc26 5d05d4360ac547b8 d2ac68998181c1a5 e3c4284b51b16e3b
+a69989b431c86bfc 91c62dd804f2678e e6e71fd3ca84e963 6ce728c0ec80b752
+807f09eb732b8c9c c2a15b84a303be1c 0087391c4d36a55f 36bcb8347365e9ce
+33980380fb628ff0 bc1a6a0fc19c89aa c71304473ebaba77 2eaa95ee37a28e66
+65d6345647f72eea f429113096a8322b 3f4ba18fe73c056a 7dbe746512a022af
+bc59b39422aed579 a8c0c738f5be2d22 bbd467cf34ca7576 8200984739ebe97f
+31a87f620a3ee13b 378739cb0c71ad2f 44b20eaaa1a4c61b 9ce88f1f84312eb5
+0b34080d83074f16 624a7ab7ca236787 f7112a455a9dc0bc b8d6fc4d3e52ab9a
+2373a5338bace0c5 28b62a4beabc2562 199bbc1bf98839ed 771beaa68262e8cc
+7ac51c9de4615fd3 4dbec61d653ca374 c4524308c7987b7f 772b16fee02557f3
+2abb8c721992bead 8a5dbb838183791b 9ac61f507c1dc7c5 1dd505ac61622b0c
+b36f7f987b5ad75e d1922c2bc187eea6 61dd12794df5c460 d7477669213e733e
+4d9553fe9850f1a9 388cc582f137433d 9ca52f074b5320c8 9b763c97f64d4b9b
+8f7772ca6d70adb7 d818fa47367b6a91 a3418777fc0b67c3 0fcf4b9d550792e8
+dc5e4fa8304f3176 98e7a303b83195d6 a49ba51b20fc8f1a 549094d62abf79ae
+05742686e35945a0 aaf7881760b55279 341d12599fdef65b 8b512690dc84b204
+507822754dec900f 30085bc872e25859 5ef525d141a71ae5 4f8ad19afc893b18
+44761156a04646bc c57bc203d05dcbe0 15dba9993a381525 204aa9797f94406d
+9ba1ac96b6004054 59ad578a414542a5 98bf81698ea22bb8 8c6656b2db791529
+8a083cbe7f309a5a 517cbedbb8ff9a53 cfa4c5bda3a98438 07c0604c25f29c2a
+135a1bc015467206 e2d4ae0b6422373c 251e0c39e3276c77 82b5ca1969cbd731
+af6ccc058324c783 0ff97946a89c5d75 c8629d745c8bc8a0 549a7993088ca048
+4139e012eaca0915 8b249488a2b8a07a 57253d4ad30ba8a2 8b7bd3828214942d
+2b90dbebc017688c 366c2ed818996933 4f81452ebd08a3a2 4a09813a2c98f3c9
+c2e23aac4785ace9 90e66866c4846892 e9558d1121a993bd dbe0540d7791f7f0
+ae6a994e1c65014d a6c0eb7c4882bac5 10b9637a637ef8fc 1a42d6150fb437b6
+81601f859ffaf9c0 cb89a514098c91e5 3e13f1bee032c819 060b82692d4cfc60
+f27c8d746c3c879a 1b1749c35aaa695e da372b7a41272c95 98d3306472686704
+1b09c684f55a3118 e64ebdc028abb8c8 d6ca6ace566d2b2c 7c15ba3ee301b867
+c84a7ab75c3c1434 c3e551206911f5fa 7a870c513a289768 867ef120c308fb2d
+f255ce47334283b8 622be7ce76d7354e 3c4fe3f6c44f6bb2 5c9864ee0baeb576
+5950d88f438263ce 8b5a7a4c0fc4c95f 10c477a7521f9bb4 58b8aa55d2e43bdc
+86b72f0930ee428b 4c5a9c7116310f2a a5cb03ac1603c811 959ea9012d69cbce
+40b37cd890999cc7 4ff375c66f048b24 0363343cb7959988 56d560f4c712938c
+79466864d20b0be9 5419c9ea6a8e7203 a1986d10b6066912 42cef630941b1164
+58a41c83b7dc5b06 a97c840b116f2ce9 cfa87a1c1aa8c4fa c137de8498e8749b
+3638404271539b24 7183a32e7e4413b6 400e0f295788084e ea93b4a765334100
+5672d908c62b64b1 1b48414b505f3036 ee56cc4da88fef27 b2da974c9dd38c15
+0090b5b8a29bd7c5 975a8a959549044b 4daed52a7fa68335 308f40c9b768c582
+1f78cf068a694978 964f597408d09759 a19578624c64dc18 eab23082e599ec48
+8dfe016e4ba58977 e15b715c61249631 0219b9b4775cb51c 5df03b934f7473aa
+58a57c602cf17c59 93d30f52d753ac56 baca1a994742bc50 435e179a262b3c8e
+ece1513955c593e7 508b945f6e95cc42 68cbd45b2504082f b8b23d8906946a74
+ac2fb676bdbc39df 76b9b8450f49d283 c622784565b76b96 084dfc099ec2279e
+5bc13492561b4439 e32324b0050c5fe6 451974bf0d72750a c58bac046d218ac3
+97f65532acc78002 46ed1c8094fc8073 06bf88e2816ad13b 06f2898ca87c486a
+124b618156a090b1 058722abae389ab5 612ca2c2766ddef9 8202a6ab1097b392
+404ea151788528b0 7544325f851b4dea a2495138f929bbb4 026042b0a8cd3cb0
+a7d061927a717d48 77e0d9a409d6b125 361c99090afdf922 a776acada2b6a845
+22134b089d4b4280 20c83061a87816c6 a59263e636b5b2ec bca6a64e29600948
+d5b0b45600b8d473 a65b450b766d0251 b6915898bc3c1c2c 53b9679121f1f06c
+fb9604de0051ff4b 093939c907ab18c2 988646a90481bb99 f4153611c138be34
+be163b3abac44354 a774e9cb54fb2990 3367c78d27546749 9d22e83a11ca9b84
+45be9df3cb612069 222a8715a495d115 b4bc2457ab731ae7 ec1bd8ec9722ca98
+0958180ac2bd6789 8f4a72a675106d66 981b2e923c0ba40e 3234655d00b25d64
+62591c9c9c7a5349 1489d57a77b2510d 08b95b9c61c1784b a752f4a73023742e
+cb985dfb37808b16 d6c283cd4a06c5a3 ac401855e1dabe63 f9668bf7a661946b
+18230a1a5a7c19da 66ed08151e77a624 f579d4e44abe023a 1cd33459fcc3f1a6
+589426634d062d0a 75a387a0b7b8d802 a66b2106e0126450 0915b97307c85ecf
+331bcac35e4aa243 c837876d858afa8b 510c342708b38093 b2cd35d1ba68da05
+44794d172c6ca885 0a7f847b56998d8e 0b0a17144fb6f443 e3679767ca91b80a
+6caa8bb0e22bbac0 1c0eae1604b8a243 911672b3748c7f18 c531e3783d522039
+130057198d6f0989 e99641ab718da123 710bdb67b3b75ec6 6ba9cf459fe06c7c
+4f7959dd7281ff15 5940b09fb14aa55c d40b963ca3312c05 b36a5207c989428c
+16e5d288adb18a66 f74617ca39db8aa6 12d706dfec884c45 7aecd1aab598195b
+4ac971529fb7a883 492235e62112064a 0f6ff5bf4f1619a0 d03b96b511200996
+6b2df7c2f300b6f2 95df7fa2c453e194 9df6405309df7575 c7656c245edca9f6
+d63a7f9914381c80 93835899cf0c9305 6f03c56a1b64382a b764a8da2e4c5061
+0624f2a4af5e82ab 4b0f15e6cac2d552 caef57f3b78ae455 1260ac71b007279f
--- /dev/null
+5219c4cc17c35a82 8f3e21b2ab749680 5c99ee041fca0158 a3314f07d053f364
+c887a6825958a625 965d4885c2cb355e 83a3c1bbb15446f8 91d2d24f145632cf
+06a5ee1a278cd306 4a79ad53193853e4 cea654448a4297ce a3c9e87561629680
+f588953b85807429 2ed31c20ddd983e8 05d07bb9cfadd823 c7900b604286c018
+4738ca04e0da8289 540e329605efaa59 60aac0fd0760006c 1f1993426cc7bea2
+2bcbb3cc02e099b8 28e82f94045dfacb 1d9fb315582b20d1 b41476fc43ac4680
+647259fe9b513712 23446c82e0bbaea1 32913e2b96ea1195 0c450f25854ee4fa
+4921193c8f1c66d6 1b8265c7072b046f 0c532141d51d9919 c80733c1bd3c5a6d
+77ccb3a1938c95c1 e4e866d1d65c7829 7b3b32ca3c4143e6 a215c609a36a1b13
+baa17981d42b7ff4 c715ac806dc49156 0032a5a2bb30e476 a266c6e4a4a065d9
+698db08132608136 082689b1b648b490 63c98324706a4387 6507fc690893900f
+8166e1d52adcc448 48d864b8ba0933b3 2daa63435f110659 15c5d5d879edcc13
+6fa8515b0260b953 6c316120b4904921 805521c0232da126 e2a9c5323976abc7
+3b5ab892e59b01a1 94b6446c1b73217f bba855ac887afa58 a8f15a768ef968d7
+75267e050150c7a8 237c1024f9421c21 0d97907b2a144736 e3b58e01c48947b1
+c62655e380256491 cebe400f52493d90 33a29d6c9ae80b33 e8c38584b30a31a3
+7b15e85f5e82b731 57408a5399a95719 0cba905f1713c9ac a53aa32923cacb82
+69436a56bc029321 89c7139d8463d0dc 540621875e9a7dfe f020e7e83696c761
+2bc2a7de7148d707 5c31f257766301fa 5a06e00582dce15c 6fb3195af43078d7
+9b110b5dc0789be3 a32132737feb247d f8d2216f272c3d5b a700c52ed7e3a279
+5ccfe3072cd1d1b5 33939ac58a065a8a 9fe85441ed291d43 869e25307737a515
+5a095c5056a20432 6f944a9fc8f7035c 931a61033cc2db6e cec08aae0045a654
+2080c1a7bbd69990 2a2ecbe3a1f9aa95 fc6222c6c6ab7bf9 6edb3450e029b0ce
+104dbbfa0a49b804 4ee1bb63b33bcfaa 8a6a450194cc577d 490a549b6c42d681
+6f444aae8b8a4f62 affd17664e957e2b a245a864bab8d28e 82cab9fac3bcd707
+aac19a5ee58a3925 dc7059ba1b9e7a79 8ec987e1924342c5 4e5d935a6699b6d9
+aa78e4738b0cec6c 57d8228c86881a14 a3b57065bbe5653b d92b5bd5a9888b1b
+1e9b017eca1a788c bc3a283a9f7b00d3 f55b138ca26c33cd 2ca3ba632a073559
+6162aa6c9d10968f 53305d35cec4395c a0489ff631a3ef66 1264a22acb535dcc
+1313cd6917bfe3b5 b8fc3b8016ca0dfb 151623c92f95701d cc4140459b52eb79
+6fda60fb42965105 2d2c16b550fa035c c1374c87a4390777 13769c728b766bc7
+5a609b70bbc14af8 4a3c70519c3211ac ad58bf7c14c15f1a a86fcc1df55580a2
+f9bbbc31b6b0eaab 379481ce9966f7fa 6487c611ba5b3e8f 8307fa35cd5248c8
+ab351b63abc4ba00 5871a97751f01e51 43302c757a65e411 af7b26f22076c7a1
+cf7e2b0055e80d71 16ca2b3056bf8754 bcfa9095d0ce9971 5cc4512f10125c5a
+500dabb7c11f5b04 08377900621be851 b7a3602576650b84 191749f30ac635a9
+e2212400769de8e1 915f26ba198af8e5 3dacb598711738da 8c583a388e027a59
--- /dev/null
+e6f634f0a3771ed7 89d6842321e147b6 010ada7b6b0b1059 49f90aebecca062c
+494743ad3be35a23 c9baa0e4cb83e65c 9eb8bbc42433f0ac 671ed9544a37c0cd
+704d1c24343aca7b ebb538c7051186bc 624a9a98f536874c 3a15e145732a591e
+ce600c78028426bb 8a7af22757296eb9 68b5e3553721db6b d507a5be5742f45a
+a3e134383499400b dac0c8607fad647f 41a2b547a631f971 224c93570141c844
+662f96d9a3a32b6d b1c93f2a2b82e6b3 70b7d91eb9f9b8d5 51c8c2f3cea6c271
+1379969467abf704 1848bb05e619a7b6 3cc2f9dac97c0545 7911470ec7b4cd38
+0528d695604b6f04 2394524c5c77415c 3ca15fa64a9e16b2 40ed12cff0a48af7
+2743916c469593b8 9d8510bfec58a053 2948d80d32a11fce 265acbe6c2175150
+7fd72366eb5edd65 0344268757a715f2 7b28beb4cf80347d cfca34bb92a04695
+5aa39590c2397a22 3acb42b94b938329 cb6a9c4253137531 c54d2100966b9a8c
+96110a412ad2dc44 80fab04d05b93087 ae8e4a1616526a48 f38caa920c6f495c
+a9e4887765516300 10c46c375de52aa5 ec23cce9bcce6663 f1678b9f4325d1a9
+61d551a02b046320 f52272382da8d565 563a4cac7419830b 6c5f95629b344172
+7cccb4892ba765b2 1222114707687236 1a0a31aa7c504039 76042da5486d287d
+143083646a90c6f1 ca4037868e847895 2829fd4c7e841878 94f28ccd58170cf1
+07fe74af5a0ccfc8 49a71eea48600801 00310259faa59c47 7c7002bd93385b8d
+a14e57891585253a e0caa66bc3a33f05 2512788828916f0a c3c9c4fa6e31ac40
+88bc6a47f29386e4 67fea414edfa9194 d30ce0770d3acb1c 1162312acc64ff27
+93a2ac4e990726d1 739e467a4ba82211 69137ad1069eed51 12eff648f2353cca
+4b4f8469cd29d05f 2684236aa3ab3b01 9e6635ab53ac456d 2c9d83152554655f
+8d6b4f75e2387067 7f492a2bba53913b 535a0b54113193b4 122a5331585edcc4
+2c9361a08c173f73 e4182f85b15dfc6f 795269c88a19c4fb 7d7d33aea8144000
+827c57e73afe87c6 d9b646b1b1be5606 72c858531d835bc3 da21b1407db74a9d
+6b729f5bb6ca1ad0 86f3c2461d78a29a 21238b0434594058 bcdb125ee56f3b60
+6d8c7a17ca5c3d6f 876a3061ba5b65b9 7f033d3889aa7430 2d1ea268531354a7
+07756eb60e621ac9 59e5ab5875790e64 77d5c91a3c06593b 976010f054ac6b4d
+54d452e5302e8e33 2ca6457cf2527ddf cc3b5462c7171105 f9e24c8d299ca348
+ce9db678e041a135 893e16ac9ccb2bac cc202f7bf7b3db1c 8c5d567fe3e3c233
+024c75d369d7cc10 93b2c2ec9094d020 a8782abfbfb89ff1 99517b0a4bb81c74
+55a64d9c07897877 422d6acceefa16ea 242e0cec8b5ef20c 85e82e2dcac3a303
+0b211a600b520b7d 66b58ac317b0f655 18f20ef26ab5b7d8 aa729210a92b12ff
+115b43540509156c c247b4bcb34c313b 3a38228d4bacb7e1 e934fd40cb42322b
+6e618670e17a725c b37cb20210e00067 8393de6a5d40786c be019daef867f2a0
+b8f1827f48c0c043 05357b82bab80cc1 44a6997228a846d9 cb49e32b865858a7
+601f55cb8127da0b ea4437f017502ac8 709e428309f6a252 c69042c973ba104a
+5219c4cc17c35a82 8f3e21b2ab749680 5c99ee041fca0158 a3314f07d053f364
+c887a6825958a625 965d4885c2cb355e 83a3c1bbb15446f8 91d2d24f145632cf
+06a5ee1a278cd306 4a79ad53193853e4 cea654448a4297ce a3c9e87561629680
+f588953b85807429 2ed31c20ddd983e8 05d07bb9cfadd823 c7900b604286c018
+4738ca04e0da8289 540e329605efaa59 60aac0fd0760006c 1f1993426cc7bea2
+2bcbb3cc02e099b8 28e82f94045dfacb 1d9fb315582b20d1 b41476fc43ac4680
+647259fe9b513712 23446c82e0bbaea1 32913e2b96ea1195 0c450f25854ee4fa
+4921193c8f1c66d6 1b8265c7072b046f 0c532141d51d9919 c80733c1bd3c5a6d
+77ccb3a1938c95c1 e4e866d1d65c7829 7b3b32ca3c4143e6 a215c609a36a1b13
+baa17981d42b7ff4 c715ac806dc49156 0032a5a2bb30e476 a266c6e4a4a065d9
+698db08132608136 082689b1b648b490 63c98324706a4387 6507fc690893900f
+8166e1d52adcc448 48d864b8ba0933b3 2daa63435f110659 15c5d5d879edcc13
+6fa8515b0260b953 6c316120b4904921 805521c0232da126 e2a9c5323976abc7
+3b5ab892e59b01a1 94b6446c1b73217f bba855ac887afa58 a8f15a768ef968d7
+75267e050150c7a8 237c1024f9421c21 0d97907b2a144736 e3b58e01c48947b1
+c62655e380256491 cebe400f52493d90 33a29d6c9ae80b33 e8c38584b30a31a3
+7b15e85f5e82b731 57408a5399a95719 0cba905f1713c9ac a53aa32923cacb82
+69436a56bc029321 89c7139d8463d0dc 540621875e9a7dfe f020e7e83696c761
+2bc2a7de7148d707 5c31f257766301fa 5a06e00582dce15c 6fb3195af43078d7
+9b110b5dc0789be3 a32132737feb247d f8d2216f272c3d5b a700c52ed7e3a279
+5ccfe3072cd1d1b5 33939ac58a065a8a 9fe85441ed291d43 869e25307737a515
+5a095c5056a20432 6f944a9fc8f7035c 931a61033cc2db6e cec08aae0045a654
+2080c1a7bbd69990 2a2ecbe3a1f9aa95 fc6222c6c6ab7bf9 6edb3450e029b0ce
+104dbbfa0a49b804 4ee1bb63b33bcfaa 8a6a450194cc577d 490a549b6c42d681
+6f444aae8b8a4f62 affd17664e957e2b a245a864bab8d28e 82cab9fac3bcd707
+aac19a5ee58a3925 dc7059ba1b9e7a79 8ec987e1924342c5 4e5d935a6699b6d9
+aa78e4738b0cec6c 57d8228c86881a14 a3b57065bbe5653b d92b5bd5a9888b1b
+1e9b017eca1a788c bc3a283a9f7b00d3 f55b138ca26c33cd 2ca3ba632a073559
+6162aa6c9d10968f 53305d35cec4395c a0489ff631a3ef66 1264a22acb535dcc
+1313cd6917bfe3b5 b8fc3b8016ca0dfb 151623c92f95701d cc4140459b52eb79
+6fda60fb42965105 2d2c16b550fa035c c1374c87a4390777 13769c728b766bc7
+5a609b70bbc14af8 4a3c70519c3211ac ad58bf7c14c15f1a a86fcc1df55580a2
+f9bbbc31b6b0eaab 379481ce9966f7fa 6487c611ba5b3e8f 8307fa35cd5248c8
+ab351b63abc4ba00 5871a97751f01e51 43302c757a65e411 af7b26f22076c7a1
+cf7e2b0055e80d71 16ca2b3056bf8754 bcfa9095d0ce9971 5cc4512f10125c5a
+500dabb7c11f5b04 08377900621be851 b7a3602576650b84 191749f30ac635a9
+e2212400769de8e1 915f26ba198af8e5 3dacb598711738da 8c583a388e027a59
+7ca0c2cbbf4fbf28 de8c479d4473c339 d96b89c34a4e5fcb cf7728bdfb43b945
+d6bf055cb7b375e3 271ed131f1ba31f8 3fef533a239878a7 1074578b891265d1
--- /dev/null
+/* ml-kem-test.c
+
+ Copyright (C) 2025 Red Hat, Inc.
+
+ This file is part of GNU Nettle.
+
+ GNU Nettle is free software: you can redistribute it and/or
+ modify it under the terms of either:
+
+ * the GNU Lesser General Public License as published by the Free
+ Software Foundation; either version 3 of the License, or (at your
+ option) any later version.
+
+ or
+
+ * the GNU General Public License as published by the Free
+ Software Foundation; either version 2 of the License, or (at your
+ option) any later version.
+
+ or both in parallel, as here.
+
+ GNU Nettle is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received copies of the GNU General Public License and
+ the GNU Lesser General Public License along with this program. If
+ not, see http://www.gnu.org/licenses/.
+*/
+
+#include "testutils.h"
+
+#include "knuth-lfib.h"
+#include "ml-kem-internal.h"
+
+static void
+random_from_seed (struct tstring *seed, size_t n, uint8_t *dst)
+{
+ ASSERT (n <= seed->length);
+ memcpy (dst, seed->data, n);
+}
+
+static void
+test_ml_kem_generate_keypair (const struct ml_kem_params *params,
+ const struct tstring *seed,
+ const struct tstring *pk,
+ const struct tstring *sk)
+{
+ uint8_t *pub;
+ uint8_t *key;
+ uint16_t *scratch;
+
+ ASSERT (pk->length == params->public_key_size);
+ ASSERT (sk->length == params->private_key_size);
+
+ pub = xalloc (params->public_key_size);
+ key = xalloc (params->private_key_size);
+ scratch = xalloc (ml_kem_generate_keypair_itch (params) * sizeof(uint16_t));
+
+ ml_kem_generate_keypair (params, pub, key, seed->data, scratch);
+
+ ASSERT (MEMEQ (pk->length, pk->data, pub));
+ ASSERT (MEMEQ (sk->length, sk->data, key));
+ free (pub);
+ free (key);
+ free (scratch);
+}
+
+static void
+test_ml_kem_encap (const struct ml_kem_params *params,
+ const struct tstring *pk,
+ const struct tstring *seed,
+ const struct tstring *ciphertext,
+ const struct tstring *secret)
+{
+ uint8_t *ciphertext2;
+ uint8_t secret2[32];
+ uint16_t *scratch;
+
+ ASSERT (pk->length == params->public_key_size);
+ ASSERT (seed->length == 32);
+ ASSERT (ciphertext->length == params->ciphertext_size);
+ ASSERT (secret->length == 32);
+
+ ciphertext2 = xalloc (params->ciphertext_size);
+ scratch = xalloc (ml_kem_encap_itch (params) * sizeof(uint16_t));
+
+ mark_bytes_undefined (seed->length, seed->data);
+
+ ml_kem_encap (params, pk->data, secret2, ciphertext2,
+ (void *)seed, (nettle_random_func *)random_from_seed,
+ scratch);
+
+ mark_bytes_defined (params->ciphertext_size, ciphertext2);
+ mark_bytes_defined (sizeof(secret2), secret2);
+
+ ASSERT (MEMEQ (ciphertext->length, ciphertext->data, ciphertext2));
+ ASSERT (MEMEQ (secret->length, secret->data, secret2));
+
+ free (ciphertext2);
+ free (scratch);
+}
+
+static void
+test_ml_kem_decap (const struct ml_kem_params *params,
+ const struct tstring *sk,
+ const struct tstring *ciphertext,
+ const struct tstring *secret)
+{
+ uint8_t secret2[32];
+ uint16_t *scratch;
+
+ ASSERT (sk->length == params->private_key_size);
+ ASSERT (ciphertext->length == params->ciphertext_size);
+ ASSERT (secret->length == 32);
+
+ scratch = xalloc (ml_kem_decap_itch (params) * sizeof(uint16_t));
+
+ mark_bytes_undefined (params->inner_private_key_size, sk->data);
+
+ ml_kem_decap (params, sk->data, secret2, ciphertext->data, scratch);
+
+ mark_bytes_defined (sizeof(secret2), secret2);
+
+ ASSERT (MEMEQ (secret->length, secret->data, secret2));
+
+ free (scratch);
+}
+
+static void
+test_ml_kem_encap_decap (const struct ml_kem_params *params,
+ const struct tstring *pk,
+ const struct tstring *sk,
+ const struct tstring *seed,
+ const struct tstring *ciphertext,
+ const struct tstring *secret)
+{
+ test_ml_kem_encap (params, pk, seed, ciphertext, secret);
+ test_ml_kem_decap (params, sk, ciphertext, secret);
+}
+
+static void
+test_ml_kem_pairwise (const struct ml_kem_params *params)
+{
+ struct knuth_lfib_ctx lfib;
+ uint8_t *pub;
+ uint8_t *key;
+ uint8_t *ciphertext;
+ uint8_t seed[64];
+ uint8_t secret[32];
+ uint8_t secret2[32];
+ uint16_t *scratch;
+
+ knuth_lfib_init(&lfib, 1111);
+
+ pub = xalloc (params->public_key_size);
+ key = xalloc (params->private_key_size);
+ ciphertext = xalloc (params->ciphertext_size);
+
+ scratch = xalloc (ml_kem_generate_keypair_itch (params) * sizeof(uint16_t));
+ knuth_lfib_random (&lfib, sizeof (seed), seed);
+ ml_kem_generate_keypair (params, pub, key, seed, scratch);
+ free (scratch);
+
+ scratch = xalloc (ml_kem_encap_itch (params) * sizeof(uint16_t));
+ ml_kem_encap (params, pub, secret, ciphertext,
+ &lfib, (nettle_random_func *) knuth_lfib_random,
+ scratch);
+ free (scratch);
+
+ scratch = xalloc (ml_kem_decap_itch (params) * sizeof(uint16_t));
+ ml_kem_decap (params, key, secret2, ciphertext, scratch);
+ free (scratch);
+
+ ASSERT (MEMEQ (32, secret2, secret));
+
+ free (pub);
+ free (key);
+ free (ciphertext);
+}
+
+void
+test_main (void)
+{
+ /* Test vectors from: https://github.com/usnistgov/ACVP-Server/tree/d98cad66639bf9d0822129c4bcae7a169fcf9ca6/gen-val/json-files/ML-KEM-keyGen-FIPS203 */
+
+ /* tcId: 26 */
+ test_ml_kem_generate_keypair (nettle_get_ml_kem_768_params (),
+ SHEX ("A2B4BCA315A6EA4600B4A316E09A2578AA1E8BCE919C8DF3A96C71C843F5B38B"
+ "D6BF055CB7B375E3271ED131F1BA31F83FEF533A239878A71074578B891265D1"),
+ read_hex_file ("ml-kem-768-keygen-tc26.pk", ML_KEM_768_PUBLIC_KEY_SIZE),
+ read_hex_file ("ml-kem-768-keygen-tc26.sk", ML_KEM_768_PRIVATE_KEY_SIZE));
+
+ /* tcId: 51 */
+ test_ml_kem_generate_keypair (nettle_get_ml_kem_1024_params (),
+ SHEX ("2B5330C4F23BFDFD5C31F050BA3B38235324BF032372FC12D04DD08920F0BD59"
+ "0A064D6C06CEAB73E59CFCA9FF6402255A326AEF1E9CB678BF36929DAFE29A58"),
+ read_hex_file ("ml-kem-1024-keygen-tc51.pk", ML_KEM_1024_PUBLIC_KEY_SIZE),
+ read_hex_file ("ml-kem-1024-keygen-tc51.sk", ML_KEM_1024_PRIVATE_KEY_SIZE));
+
+ /* Test vectors from: https://github.com/usnistgov/ACVP-Server/tree/d98cad66639bf9d0822129c4bcae7a169fcf9ca6/gen-val/json-files/ML-KEM-encapDecap-FIPS203 */
+
+ /* tcId: 26 */
+ test_ml_kem_encap_decap (nettle_get_ml_kem_768_params (),
+ read_hex_file ("ml-kem-768-encapdecap-tc26.pk", ML_KEM_768_PUBLIC_KEY_SIZE),
+ read_hex_file ("ml-kem-768-encapdecap-tc26.sk", ML_KEM_768_PRIVATE_KEY_SIZE),
+ SHEX ("5BD922AF345AB90F297D0A82EA39527A648E4977AB56242E2AC0ED9A2CC66F10"),
+ read_hex_file ("ml-kem-768-encapdecap-tc26.ct", ML_KEM_768_CIPHERTEXT_SIZE),
+ SHEX ("B2425299020BCF563B8EBE0512F0479941335A75A32B8D10BFF60E5548B64672"));
+
+ /* tcId: 51 */
+ test_ml_kem_encap_decap (nettle_get_ml_kem_1024_params (),
+ read_hex_file ("ml-kem-1024-encapdecap-tc51.pk", ML_KEM_1024_PUBLIC_KEY_SIZE),
+ read_hex_file ("ml-kem-1024-encapdecap-tc51.sk", ML_KEM_1024_PRIVATE_KEY_SIZE),
+ SHEX ("8199CF923CE12126920108569C11CBF97CF03F44AF5CFA7D550E9B2AC7431982"),
+ read_hex_file ("ml-kem-1024-encapdecap-tc51.ct", ML_KEM_1024_CIPHERTEXT_SIZE),
+ SHEX ("5D537CD0EF7B58F0FE95370473B96878F138ECC259ADFBF77EBD7328B822D9D9"));
+
+ test_ml_kem_pairwise (nettle_get_ml_kem_768_params ());
+ test_ml_kem_pairwise (nettle_get_ml_kem_1024_params ());
+}
--- /dev/null
+#! /bin/sh
+
+srcdir=`dirname $0`
+. "${srcdir}/sc-valgrind.sh"
+
+with_valgrind ./ml-kem-test