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