xref: /openbsd-src/regress/lib/libcrypto/mlkem/mlkem_unittest.c (revision d4ed7533f1cea04e9ae67cd6d4498e68b342f0ec)
1*d4ed7533Stb /*	$OpenBSD: mlkem_unittest.c,v 1.3 2024/12/14 19:16:24 tb Exp $ */
2*d4ed7533Stb /*
3*d4ed7533Stb  * Copyright (c) 2024, Google Inc.
475c083a0Sbeck  * Copyright (c) 2024, Bob Beck <beck@obtuse.com>
575c083a0Sbeck  *
675c083a0Sbeck  * Permission to use, copy, modify, and/or distribute this software for any
775c083a0Sbeck  * purpose with or without fee is hereby granted, provided that the above
875c083a0Sbeck  * copyright notice and this permission notice appear in all copies.
975c083a0Sbeck  *
1075c083a0Sbeck  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
1175c083a0Sbeck  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1275c083a0Sbeck  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
1375c083a0Sbeck  * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1475c083a0Sbeck  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
1575c083a0Sbeck  * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
16*d4ed7533Stb  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17*d4ed7533Stb  */
1875c083a0Sbeck 
19*d4ed7533Stb #include <stdint.h>
2075c083a0Sbeck #include <stdio.h>
21*d4ed7533Stb #include <stdlib.h>
2275c083a0Sbeck #include <string.h>
2375c083a0Sbeck 
24*d4ed7533Stb #include <openssl/bytestring.h>
25*d4ed7533Stb #include <openssl/mlkem.h>
26*d4ed7533Stb 
2775c083a0Sbeck #include "mlkem_internal.h"
2875c083a0Sbeck #include "mlkem_tests_util.h"
2975c083a0Sbeck 
3075c083a0Sbeck static int
3175c083a0Sbeck encode_public_key(const struct MLKEM768_public_key *pub, uint8_t **out_buf,
3275c083a0Sbeck     size_t *out_len)
3375c083a0Sbeck {
3475c083a0Sbeck 	CBB cbb;
3575c083a0Sbeck 	if (!CBB_init(&cbb, MLKEM768_PUBLIC_KEY_BYTES))
3675c083a0Sbeck 		return 0;
3775c083a0Sbeck 	if (!MLKEM768_marshal_public_key(&cbb, pub))
3875c083a0Sbeck 		return 0;
3975c083a0Sbeck 	if (!CBB_finish(&cbb, out_buf, out_len))
4075c083a0Sbeck 		return 0;
4175c083a0Sbeck 	CBB_cleanup(&cbb);
4275c083a0Sbeck 	return 1;
4375c083a0Sbeck }
4475c083a0Sbeck 
4575c083a0Sbeck static int
4675c083a0Sbeck encode_private_key(const struct MLKEM768_private_key *priv, uint8_t **out_buf,
4775c083a0Sbeck     size_t *out_len)
4875c083a0Sbeck {
4975c083a0Sbeck 	CBB cbb;
5075c083a0Sbeck 	if (!CBB_init(&cbb, MLKEM768_PUBLIC_KEY_BYTES))
5175c083a0Sbeck 		return 0;
5275c083a0Sbeck 	if (!MLKEM768_marshal_private_key(&cbb, priv))
5375c083a0Sbeck 		return 0;
5475c083a0Sbeck 	if (!CBB_finish(&cbb, out_buf, out_len))
5575c083a0Sbeck 		return 0;
5675c083a0Sbeck 	CBB_cleanup(&cbb);
5775c083a0Sbeck 	return 1;
5875c083a0Sbeck }
5975c083a0Sbeck 
6008c63c71Sbeck static void
6108c63c71Sbeck MlKem768UnitTest()
6275c083a0Sbeck {
6375c083a0Sbeck 	struct MLKEM768_private_key *priv, *priv2;
6475c083a0Sbeck 	struct MLKEM768_public_key *pub, *pub2;
6575c083a0Sbeck 	uint8_t encoded_public_key[MLKEM768_PUBLIC_KEY_BYTES];
6675c083a0Sbeck 	uint8_t ciphertext[MLKEM768_CIPHERTEXT_BYTES];
6775c083a0Sbeck 	uint8_t shared_secret1[MLKEM_SHARED_SECRET_BYTES];
6875c083a0Sbeck 	uint8_t shared_secret2[MLKEM_SHARED_SECRET_BYTES];
6975c083a0Sbeck 	uint8_t first_two_bytes[2];
7075c083a0Sbeck 	uint8_t *encoded_private_key = NULL, *tmp_buf = NULL;
7175c083a0Sbeck 	size_t encoded_private_key_len, tmp_buf_len;
7275c083a0Sbeck 	CBS cbs;
7375c083a0Sbeck 
7475c083a0Sbeck 	fprintf(stderr, "ML-KEM 768...\n");
7575c083a0Sbeck 
7675c083a0Sbeck 	MALLOC(priv, sizeof(struct MLKEM768_private_key));
7775c083a0Sbeck 	MLKEM768_generate_key(encoded_public_key, NULL, priv);
7875c083a0Sbeck 
7975c083a0Sbeck 	memcpy(first_two_bytes, encoded_public_key, sizeof(first_two_bytes));
8075c083a0Sbeck 	memset(encoded_public_key, 0xff, sizeof(first_two_bytes));
8175c083a0Sbeck 	CBS_init(&cbs, encoded_public_key,
8275c083a0Sbeck 	    sizeof(encoded_public_key));
8375c083a0Sbeck 	MALLOC(pub, sizeof(struct MLKEM768_public_key));
8475c083a0Sbeck 	/*  Parsing should fail because the first coefficient is >= kPrime; */
8575c083a0Sbeck 	TEST(MLKEM768_parse_public_key(pub, &cbs),
8675c083a0Sbeck 	    "Kyber_parse_public_key should have failed");
8775c083a0Sbeck 
8875c083a0Sbeck 	memcpy(encoded_public_key, first_two_bytes, sizeof(first_two_bytes));
8975c083a0Sbeck 	CBS_init(&cbs, encoded_public_key, sizeof(encoded_public_key));
9075c083a0Sbeck 	TEST(!MLKEM768_parse_public_key(pub, &cbs),
9175c083a0Sbeck 	    "MLKEM768_parse_public_key");
9275c083a0Sbeck 	TEST(CBS_len(&cbs) != 0u, "CBS_len must be 0");
9375c083a0Sbeck 
9475c083a0Sbeck 	TEST(!encode_public_key(pub, &tmp_buf, &tmp_buf_len),
9575c083a0Sbeck 	    "encode_public_key");
9675c083a0Sbeck 	TEST(sizeof(encoded_public_key) != tmp_buf_len,
9775c083a0Sbeck 	    "encoded public key lengths differ");
9875c083a0Sbeck 	TEST_DATAEQ(tmp_buf, encoded_public_key, tmp_buf_len,
9975c083a0Sbeck 	    "encoded public keys");
10075c083a0Sbeck 	free(tmp_buf);
10175c083a0Sbeck 	tmp_buf = NULL;
10275c083a0Sbeck 
10375c083a0Sbeck 	MALLOC(pub2, sizeof(struct MLKEM768_public_key));
10475c083a0Sbeck 	MLKEM768_public_from_private(pub2, priv);
10575c083a0Sbeck 	TEST(!encode_public_key(pub2, &tmp_buf, &tmp_buf_len),
10675c083a0Sbeck 	    "encode_public_key");
10775c083a0Sbeck 	TEST(sizeof(encoded_public_key) != tmp_buf_len,
10875c083a0Sbeck 	    "encoded public key lengths differ");
10975c083a0Sbeck 	TEST_DATAEQ(tmp_buf, encoded_public_key, tmp_buf_len,
11075c083a0Sbeck 	    "encoded pubic keys");
11175c083a0Sbeck 	free(tmp_buf);
11275c083a0Sbeck 	tmp_buf = NULL;
11375c083a0Sbeck 
11475c083a0Sbeck 	TEST(!encode_private_key(priv, &encoded_private_key,
11575c083a0Sbeck 	    &encoded_private_key_len), "encode_private_key");
11675c083a0Sbeck 
11775c083a0Sbeck 	memcpy(first_two_bytes, encoded_private_key, sizeof(first_two_bytes));
11875c083a0Sbeck 	memset(encoded_private_key, 0xff, sizeof(first_two_bytes));
11975c083a0Sbeck 	CBS_init(&cbs, encoded_private_key, encoded_private_key_len);
12075c083a0Sbeck 	MALLOC(priv2, sizeof(struct MLKEM768_private_key));
12175c083a0Sbeck 	/*  Parsing should fail because the first coefficient is >= kPrime. */
12275c083a0Sbeck 	TEST(MLKEM768_parse_private_key(priv2, &cbs), "Should not have parsed");
12375c083a0Sbeck 
12475c083a0Sbeck 	memcpy(encoded_private_key, first_two_bytes, sizeof(first_two_bytes));
12575c083a0Sbeck 	CBS_init(&cbs, encoded_private_key, encoded_private_key_len);
12675c083a0Sbeck 	TEST(!MLKEM768_parse_private_key(priv2, &cbs),
12775c083a0Sbeck 	    "MLKEM768_parse_private_key");
12875c083a0Sbeck 	TEST(!encode_private_key(priv2, &tmp_buf, &tmp_buf_len),
12975c083a0Sbeck 	    "encode_private_key");
13075c083a0Sbeck 	TEST(encoded_private_key_len != tmp_buf_len,
13175c083a0Sbeck 	    "encoded private key lengths differ");
13275c083a0Sbeck 	TEST_DATAEQ(tmp_buf, encoded_private_key, encoded_private_key_len,
13375c083a0Sbeck 	    "encoded private keys");
13475c083a0Sbeck 	free(tmp_buf);
13575c083a0Sbeck 	tmp_buf = NULL;
13675c083a0Sbeck 
13775c083a0Sbeck 	MLKEM768_encap(ciphertext, shared_secret1, pub);
13875c083a0Sbeck 	MLKEM768_decap(shared_secret2, ciphertext, MLKEM768_CIPHERTEXT_BYTES,
13975c083a0Sbeck 	    priv);
14075c083a0Sbeck 	TEST_DATAEQ(shared_secret1, shared_secret2, MLKEM_SHARED_SECRET_BYTES,
14175c083a0Sbeck 	    "shared secrets with priv");
14275c083a0Sbeck 	MLKEM768_decap(shared_secret2, ciphertext, MLKEM768_CIPHERTEXT_BYTES,
14375c083a0Sbeck 	    priv2);
14475c083a0Sbeck 	TEST_DATAEQ(shared_secret1, shared_secret2, MLKEM_SHARED_SECRET_BYTES,
14575c083a0Sbeck 	    "shared secrets with priv2");
14675c083a0Sbeck 
14775c083a0Sbeck 	free(encoded_private_key);
14875c083a0Sbeck 	free(pub);
14975c083a0Sbeck 	free(pub2);
15075c083a0Sbeck 	free(priv);
15175c083a0Sbeck 	free(priv2);
15275c083a0Sbeck 
15308c63c71Sbeck }
15408c63c71Sbeck 
15508c63c71Sbeck static int
15608c63c71Sbeck encode_1024public_key(const struct MLKEM1024_public_key *pub, uint8_t **out_buf,
15708c63c71Sbeck     size_t *out_len)
15808c63c71Sbeck {
15908c63c71Sbeck 	CBB cbb;
16008c63c71Sbeck 	if (!CBB_init(&cbb, MLKEM1024_PUBLIC_KEY_BYTES))
16108c63c71Sbeck 		return 0;
16208c63c71Sbeck 	if (!MLKEM1024_marshal_public_key(&cbb, pub))
16308c63c71Sbeck 		return 0;
16408c63c71Sbeck 	if (!CBB_finish(&cbb, out_buf, out_len))
16508c63c71Sbeck 		return 0;
16608c63c71Sbeck 	CBB_cleanup(&cbb);
16708c63c71Sbeck 	return 1;
16808c63c71Sbeck }
16908c63c71Sbeck 
17008c63c71Sbeck static int
17108c63c71Sbeck encode_1024private_key(const struct MLKEM1024_private_key *priv, uint8_t **out_buf,
17208c63c71Sbeck     size_t *out_len)
17308c63c71Sbeck {
17408c63c71Sbeck 	CBB cbb;
17508c63c71Sbeck 	if (!CBB_init(&cbb, MLKEM1024_PUBLIC_KEY_BYTES))
17608c63c71Sbeck 		return 0;
17708c63c71Sbeck 	if (!MLKEM1024_marshal_private_key(&cbb, priv))
17808c63c71Sbeck 		return 0;
17908c63c71Sbeck 	if (!CBB_finish(&cbb, out_buf, out_len))
18008c63c71Sbeck 		return 0;
18108c63c71Sbeck 	CBB_cleanup(&cbb);
18208c63c71Sbeck 	return 1;
18308c63c71Sbeck }
18408c63c71Sbeck 
18508c63c71Sbeck static void
18608c63c71Sbeck MlKem1024UnitTest()
18708c63c71Sbeck {
18808c63c71Sbeck 	struct MLKEM1024_private_key *priv, *priv2;
18908c63c71Sbeck 	struct MLKEM1024_public_key *pub, *pub2;
19008c63c71Sbeck 	uint8_t encoded_public_key[MLKEM1024_PUBLIC_KEY_BYTES];
19108c63c71Sbeck 	uint8_t ciphertext[MLKEM1024_CIPHERTEXT_BYTES];
19208c63c71Sbeck 	uint8_t shared_secret1[MLKEM_SHARED_SECRET_BYTES];
19308c63c71Sbeck 	uint8_t shared_secret2[MLKEM_SHARED_SECRET_BYTES];
19408c63c71Sbeck 	uint8_t first_two_bytes[2];
19508c63c71Sbeck 	uint8_t *encoded_private_key = NULL, *tmp_buf = NULL;
19608c63c71Sbeck 	size_t encoded_private_key_len, tmp_buf_len;
19708c63c71Sbeck 	CBS cbs;
19808c63c71Sbeck 
19908c63c71Sbeck 	fprintf(stderr, "ML-KEM 1024...\n");
20008c63c71Sbeck 
20108c63c71Sbeck 	MALLOC(priv, sizeof(struct MLKEM1024_private_key));
20208c63c71Sbeck 	MLKEM1024_generate_key(encoded_public_key, NULL, priv);
20308c63c71Sbeck 
20408c63c71Sbeck 	memcpy(first_two_bytes, encoded_public_key, sizeof(first_two_bytes));
20508c63c71Sbeck 	memset(encoded_public_key, 0xff, sizeof(first_two_bytes));
20608c63c71Sbeck 	CBS_init(&cbs, encoded_public_key,
20708c63c71Sbeck 	    sizeof(encoded_public_key));
20808c63c71Sbeck 	MALLOC(pub, sizeof(struct MLKEM1024_public_key));
20908c63c71Sbeck 	/*  Parsing should fail because the first coefficient is >= kPrime; */
21008c63c71Sbeck 	TEST(MLKEM1024_parse_public_key(pub, &cbs),
21108c63c71Sbeck 	    "Kyber_parse_public_key should have failed");
21208c63c71Sbeck 
21308c63c71Sbeck 	memcpy(encoded_public_key, first_two_bytes, sizeof(first_two_bytes));
21408c63c71Sbeck 	CBS_init(&cbs, encoded_public_key, sizeof(encoded_public_key));
21508c63c71Sbeck 	TEST(!MLKEM1024_parse_public_key(pub, &cbs),
21608c63c71Sbeck 	    "MLKEM1024_parse_public_key");
21708c63c71Sbeck 	TEST(CBS_len(&cbs) != 0u, "CBS_len must be 0");
21808c63c71Sbeck 
21908c63c71Sbeck 	TEST(!encode_1024public_key(pub, &tmp_buf, &tmp_buf_len),
22008c63c71Sbeck 	    "encode_1024public_key");
22108c63c71Sbeck 	TEST(sizeof(encoded_public_key) != tmp_buf_len,
22208c63c71Sbeck 	    "encoded public key lengths differ");
22308c63c71Sbeck 	TEST_DATAEQ(tmp_buf, encoded_public_key, tmp_buf_len,
22408c63c71Sbeck 	    "encoded public keys");
22508c63c71Sbeck 	free(tmp_buf);
22608c63c71Sbeck 	tmp_buf = NULL;
22708c63c71Sbeck 
22808c63c71Sbeck 	MALLOC(pub2, sizeof(struct MLKEM1024_public_key));
22908c63c71Sbeck 	MLKEM1024_public_from_private(pub2, priv);
23008c63c71Sbeck 	TEST(!encode_1024public_key(pub2, &tmp_buf, &tmp_buf_len),
23108c63c71Sbeck 	    "encode_public_key");
23208c63c71Sbeck 	TEST(sizeof(encoded_public_key) != tmp_buf_len,
23308c63c71Sbeck 	    "encoded public key lengths differ");
23408c63c71Sbeck 	TEST_DATAEQ(tmp_buf, encoded_public_key, tmp_buf_len,
23508c63c71Sbeck 	    "encoded pubic keys");
23608c63c71Sbeck 	free(tmp_buf);
23708c63c71Sbeck 	tmp_buf = NULL;
23808c63c71Sbeck 
23908c63c71Sbeck 	TEST(!encode_1024private_key(priv, &encoded_private_key,
24008c63c71Sbeck 	    &encoded_private_key_len), "encode_1024private_key");
24108c63c71Sbeck 
24208c63c71Sbeck 	memcpy(first_two_bytes, encoded_private_key, sizeof(first_two_bytes));
24308c63c71Sbeck 	memset(encoded_private_key, 0xff, sizeof(first_two_bytes));
24408c63c71Sbeck 	CBS_init(&cbs, encoded_private_key, encoded_private_key_len);
24508c63c71Sbeck 	MALLOC(priv2, sizeof(struct MLKEM1024_private_key));
24608c63c71Sbeck 	/*  Parsing should fail because the first coefficient is >= kPrime. */
24708c63c71Sbeck 	TEST(MLKEM1024_parse_private_key(priv2, &cbs), "Should not have parsed");
24808c63c71Sbeck 
24908c63c71Sbeck 	memcpy(encoded_private_key, first_two_bytes, sizeof(first_two_bytes));
25008c63c71Sbeck 	CBS_init(&cbs, encoded_private_key, encoded_private_key_len);
25108c63c71Sbeck 	TEST(!MLKEM1024_parse_private_key(priv2, &cbs),
25208c63c71Sbeck 	    "MLKEM1024_parse_private_key");
25308c63c71Sbeck 	TEST(!encode_1024private_key(priv2, &tmp_buf, &tmp_buf_len),
25408c63c71Sbeck 	    "encode_private_key");
25508c63c71Sbeck 	TEST(encoded_private_key_len != tmp_buf_len,
25608c63c71Sbeck 	    "encoded private key lengths differ");
25708c63c71Sbeck 	TEST_DATAEQ(tmp_buf, encoded_private_key, encoded_private_key_len,
25808c63c71Sbeck 	    "encoded private keys");
25908c63c71Sbeck 	free(tmp_buf);
26008c63c71Sbeck 	tmp_buf = NULL;
26108c63c71Sbeck 
26208c63c71Sbeck 	MLKEM1024_encap(ciphertext, shared_secret1, pub);
26308c63c71Sbeck 	MLKEM1024_decap(shared_secret2, ciphertext, MLKEM1024_CIPHERTEXT_BYTES,
26408c63c71Sbeck 	    priv);
26508c63c71Sbeck 	TEST_DATAEQ(shared_secret1, shared_secret2, MLKEM_SHARED_SECRET_BYTES,
26608c63c71Sbeck 	    "shared secrets with priv");
26708c63c71Sbeck 	MLKEM1024_decap(shared_secret2, ciphertext, MLKEM1024_CIPHERTEXT_BYTES,
26808c63c71Sbeck 	    priv2);
26908c63c71Sbeck 	TEST_DATAEQ(shared_secret1, shared_secret2, MLKEM_SHARED_SECRET_BYTES,
27008c63c71Sbeck 	    "shared secrets with priv2");
27108c63c71Sbeck 
27208c63c71Sbeck 	free(encoded_private_key);
27308c63c71Sbeck 	free(pub);
27408c63c71Sbeck 	free(pub2);
27508c63c71Sbeck 	free(priv);
27608c63c71Sbeck 	free(priv2);
27708c63c71Sbeck }
27808c63c71Sbeck 
27908c63c71Sbeck int
28008c63c71Sbeck main(int argc, char **argv)
28108c63c71Sbeck {
28208c63c71Sbeck 	MlKem768UnitTest();
28308c63c71Sbeck 	MlKem1024UnitTest();
28408c63c71Sbeck 
28575c083a0Sbeck 	exit(failure);
28675c083a0Sbeck }
287