diff --git a/cbmc/proofs/crypto_kem_enc_derand/Makefile b/cbmc/proofs/crypto_kem_enc_derand/Makefile index b63e0715e..305955442 100644 --- a/cbmc/proofs/crypto_kem_enc_derand/Makefile +++ b/cbmc/proofs/crypto_kem_enc_derand/Makefile @@ -19,7 +19,7 @@ PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c PROJECT_SOURCES += $(SRCDIR)/mlkem/kem.c CHECK_FUNCTION_CONTRACTS=$(MLKEM_NAMESPACE)enc_derand -USE_FUNCTION_CONTRACTS=$(FIPS202_NAMESPACE)sha3_256 $(FIPS202_NAMESPACE)sha3_512 $(MLKEM_NAMESPACE)indcpa_enc $(MLKEM_NAMESPACE)polyvec_frombytes $(MLKEM_NAMESPACE)polyvec_reduce $(MLKEM_NAMESPACE)polyvec_tobytes pk_cmp_polyvec +USE_FUNCTION_CONTRACTS=$(FIPS202_NAMESPACE)sha3_256 $(FIPS202_NAMESPACE)sha3_512 $(MLKEM_NAMESPACE)indcpa_enc $(MLKEM_NAMESPACE)polyvec_frombytes $(MLKEM_NAMESPACE)polyvec_reduce $(MLKEM_NAMESPACE)polyvec_tobytes memcmp APPLY_LOOP_CONTRACTS=on USE_DYNAMIC_FRAMES=1 diff --git a/cbmc/proofs/crypto_kem_keypair/Makefile b/cbmc/proofs/crypto_kem_keypair/Makefile new file mode 100644 index 000000000..5849cd101 --- /dev/null +++ b/cbmc/proofs/crypto_kem_keypair/Makefile @@ -0,0 +1,54 @@ +# SPDX-License-Identifier: Apache-2.0 + +include ../Makefile_params.common + +HARNESS_ENTRY = harness +HARNESS_FILE = crypto_kem_keypair_harness + +# This should be a unique identifier for this proof, and will appear on the +# Litani dashboard. It can be human-readable and contain spaces if you wish. +PROOF_UID = crypto_kem_keypair + +DEFINES += +INCLUDES += + +REMOVE_FUNCTION_BODY += +UNWINDSET += + +PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c +PROJECT_SOURCES += $(SRCDIR)/mlkem/kem.c + +CHECK_FUNCTION_CONTRACTS=$(MLKEM_NAMESPACE)keypair +USE_FUNCTION_CONTRACTS=$(MLKEM_NAMESPACE)keypair_derand randombytes +APPLY_LOOP_CONTRACTS=on +USE_DYNAMIC_FRAMES=1 + +# Disable any setting of EXTERNAL_SAT_SOLVER, and choose SMT backend instead +EXTERNAL_SAT_SOLVER= +CBMCFLAGS=--smt2 + +FUNCTION_NAME = $(MLKEM_NAMESPACE)keypair + +# If this proof is found to consume huge amounts of RAM, you can set the +# EXPENSIVE variable. With new enough versions of the proof tools, this will +# restrict the number of EXPENSIVE CBMC jobs running at once. See the +# documentation in Makefile.common under the "Job Pools" heading for details. +# EXPENSIVE = true + +# This function is large enough to need... +CBMC_OBJECT_BITS = 10 + +# If you require access to a file-local ("static") function or object to conduct +# your proof, set the following (and do not include the original source file +# ("mlkem/poly.c") in PROJECT_SOURCES). +# REWRITTEN_SOURCES = $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i +# include ../Makefile.common +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_SOURCE = $(SRCDIR)/mlkem/poly.c +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_FUNCTIONS = foo bar +# $(PROOFDIR)/<__SOURCE_FILE_BASENAME__>.i_OBJECTS = baz +# Care is required with variables on the left-hand side: REWRITTEN_SOURCES must +# be set before including Makefile.common, but any use of variables on the +# left-hand side requires those variables to be defined. Hence, _SOURCE, +# _FUNCTIONS, _OBJECTS is set after including Makefile.common. + +include ../Makefile.common diff --git a/cbmc/proofs/crypto_kem_keypair/cbmc-proof.txt b/cbmc/proofs/crypto_kem_keypair/cbmc-proof.txt new file mode 100644 index 000000000..3d1913ebf --- /dev/null +++ b/cbmc/proofs/crypto_kem_keypair/cbmc-proof.txt @@ -0,0 +1,3 @@ +# SPDX-License-Identifier: Apache-2.0 + +# This file marks this directory as containing a CBMC proof. diff --git a/cbmc/proofs/crypto_kem_keypair/crypto_kem_keypair_harness.c b/cbmc/proofs/crypto_kem_keypair/crypto_kem_keypair_harness.c new file mode 100644 index 000000000..013756c84 --- /dev/null +++ b/cbmc/proofs/crypto_kem_keypair/crypto_kem_keypair_harness.c @@ -0,0 +1,27 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: MIT-0 + +/* + * Insert copyright notice + */ + +/** + * @file crypto_kem_keypair_harness.c + * @brief Implements the proof harness for crypto_kem_keypair function. + */ + +/* + * Insert project header files that + * - include the declaration of the function + * - include the types needed to declare function arguments + */ +#include + +/** + * @brief Starting point for formal analysis + * + */ +void harness(void) { + uint8_t *a, *b; + crypto_kem_keypair(a, b); +} diff --git a/mlkem/kem.c b/mlkem/kem.c index 09b06bd42..d470cbbcf 100644 --- a/mlkem/kem.c +++ b/mlkem/kem.c @@ -9,17 +9,13 @@ #include "symmetric.h" #include "verify.h" -// This helper function is only to prevent CBMC from inlining -// `memcmp`, and is expected to be inlined by the compiler. -static int pk_cmp_polyvec( - const uint8_t pk[MLKEM_PUBLICKEYBYTES], - const uint8_t pv[MLKEM_POLYVECBYTES]) // clang-format off - REQUIRES(IS_FRESH(pk, MLKEM_PUBLICKEYBYTES)) - REQUIRES(IS_FRESH(pv, MLKEM_POLYVECBYTES)) +#if defined(CBMC) +// Redeclaration with contract needed for CBMC only +int memcmp(const void *str1, const void *str2, size_t n) // clang-format off + REQUIRES(IS_FRESH(str1, n)) + REQUIRES(IS_FRESH(str2, n)); // clang-format on -{ - return memcmp(pk, pv, MLKEM_POLYVECBYTES); -} +#endif /************************************************* * Name: check_pk @@ -40,7 +36,7 @@ static int check_pk(const uint8_t pk[MLKEM_PUBLICKEYBYTES]) { polyvec_reduce(&p); polyvec_tobytes(p_reencoded, &p); // Data is public, so a variable-time memcmp() is OK - if (pk_cmp_polyvec(pk, p_reencoded)) { + if (memcmp(pk, p_reencoded, MLKEM_POLYVECBYTES)) { return -1; } return 0; @@ -99,19 +95,6 @@ int crypto_kem_keypair_derand(uint8_t *pk, uint8_t *sk, const uint8_t *coins) { return 0; } -/************************************************* - * Name: crypto_kem_keypair - * - * Description: Generates public and private key - * for CCA-secure ML-KEM key encapsulation mechanism - * - * Arguments: - uint8_t *pk: pointer to output public key - * (an already allocated array of MLKEM_PUBLICKEYBYTES bytes) - * - uint8_t *sk: pointer to output private key - * (an already allocated array of MLKEM_SECRETKEYBYTES bytes) - * - * Returns 0 (success) - **************************************************/ int crypto_kem_keypair(uint8_t *pk, uint8_t *sk) { uint8_t coins[2 * MLKEM_SYMBYTES] ALIGN; randombytes(coins, 2 * MLKEM_SYMBYTES); diff --git a/mlkem/kem.h b/mlkem/kem.h index 472d094f6..869932f26 100644 --- a/mlkem/kem.h +++ b/mlkem/kem.h @@ -30,7 +30,25 @@ int crypto_kem_keypair_derand(uint8_t *pk, uint8_t *sk, // clang-format on #define crypto_kem_keypair MLKEM_NAMESPACE(keypair) -int crypto_kem_keypair(uint8_t *pk, uint8_t *sk); +/************************************************* + * Name: crypto_kem_keypair + * + * Description: Generates public and private key + * for CCA-secure ML-KEM key encapsulation mechanism + * + * Arguments: - uint8_t *pk: pointer to output public key + * (an already allocated array of MLKEM_PUBLICKEYBYTES bytes) + * - uint8_t *sk: pointer to output private key + * (an already allocated array of MLKEM_SECRETKEYBYTES bytes) + * + * Returns 0 (success) + **************************************************/ +int crypto_kem_keypair(uint8_t *pk, uint8_t *sk) // clang-format off + REQUIRES(IS_FRESH(pk, MLKEM_PUBLICKEYBYTES)) + REQUIRES(IS_FRESH(sk, MLKEM_SECRETKEYBYTES)) + ASSIGNS(OBJECT_WHOLE(pk)) + ASSIGNS(OBJECT_WHOLE(sk)); +// clang-format on #define crypto_kem_enc_derand MLKEM_NAMESPACE(enc_derand) /*************************************************