diff --git a/cbmc/proofs/poly_frommsg/Makefile b/cbmc/proofs/poly_frommsg/Makefile new file mode 100644 index 000000000..d1953ab84 --- /dev/null +++ b/cbmc/proofs/poly_frommsg/Makefile @@ -0,0 +1,54 @@ +# SPDX-License-Identifier: Apache-2.0 + +include ../Makefile_params.common + +HARNESS_ENTRY = harness +HARNESS_FILE = poly_frommsg_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 = poly_frommsg + +DEFINES += +INCLUDES += + +REMOVE_FUNCTION_BODY += +UNWINDSET += + +PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c +PROJECT_SOURCES += $(SRCDIR)/mlkem/poly.c + +CHECK_FUNCTION_CONTRACTS=$(MLKEM_NAMESPACE)poly_frommsg +USE_FUNCTION_CONTRACTS=$(MLKEM_NAMESPACE)cmov_int16 +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)poly_frommsg + +# 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 = 8 + +# 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/poly_frommsg/cbmc-proof.txt b/cbmc/proofs/poly_frommsg/cbmc-proof.txt new file mode 100644 index 000000000..3d1913ebf --- /dev/null +++ b/cbmc/proofs/poly_frommsg/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/poly_frommsg/poly_frommsg_harness.c b/cbmc/proofs/poly_frommsg/poly_frommsg_harness.c new file mode 100644 index 000000000..473601196 --- /dev/null +++ b/cbmc/proofs/poly_frommsg/poly_frommsg_harness.c @@ -0,0 +1,30 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: MIT-0 + +/* + * Insert copyright notice + */ + +/** + * @file poly_frommsg_harness.c + * @brief Implements the proof harness for poly_frommsg 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) { + poly *a; + uint8_t *msg; + + /* Contracts for this function are in poly.h */ + poly_frommsg(a, msg); +} diff --git a/mlkem/poly.c b/mlkem/poly.c index 37db950dd..e62536196 100644 --- a/mlkem/poly.c +++ b/mlkem/poly.c @@ -274,28 +274,25 @@ void poly_frombytes(poly *r, const uint8_t a[MLKEM_POLYBYTES]) { } #endif /* MLKEM_USE_NATIVE_POLY_FROMBYTES */ -/************************************************* - * Name: poly_frommsg - * - * Description: Convert 32-byte message to polynomial - * - * Arguments: - poly *r: pointer to output polynomial - * - const uint8_t *msg: pointer to input message - **************************************************/ void poly_frommsg(poly *r, const uint8_t msg[MLKEM_INDCPA_MSGBYTES]) { - unsigned int i, j; - #if (MLKEM_INDCPA_MSGBYTES != MLKEM_N / 8) #error "MLKEM_INDCPA_MSGBYTES must be equal to MLKEM_N/8 bytes!" #endif - for (i = 0; i < MLKEM_N / 8; i++) { - for (j = 0; j < 8; j++) { - r->coeffs[8 * i + j] = 0; - cmov_int16(r->coeffs + 8 * i + j, ((MLKEM_Q + 1) / 2), (msg[i] >> j) & 1); + for (int i = 0; i < MLKEM_N / 8; i++) // clang-format off + ASSIGNS(i, OBJECT_WHOLE(r)) + INVARIANT(i >= 0 && i <= MLKEM_N / 8) + INVARIANT(ARRAY_IN_BOUNDS(int, k, 0, (8 * i - 1), r->coeffs, 0, (MLKEM_Q - 1))) + { // clang-format on + for (int j = 0; j < 8; j++) // clang-format off + ASSIGNS(j, OBJECT_WHOLE(r)) + INVARIANT(i >= 0 && i < MLKEM_N / 8 && j >= 0 && j <= 8) + INVARIANT(ARRAY_IN_BOUNDS(int, k, 0, (8 * i + j - 1), r->coeffs, 0, (MLKEM_Q - 1))) + { // clang-format on + r->coeffs[8 * i + j] = 0; + cmov_int16(&r->coeffs[8 * i + j], HALF_Q, (msg[i] >> j) & 1); + } } - } - POLY_BOUND_MSG(r, MLKEM_Q, "poly_frommsg output"); } diff --git a/mlkem/poly.h b/mlkem/poly.h index a27710f30..d6bebeee1 100644 --- a/mlkem/poly.h +++ b/mlkem/poly.h @@ -213,8 +213,23 @@ ASSIGNS(OBJECT_UPTO(r, sizeof(poly))) ENSURES(ARRAY_IN_BOUNDS(int, k, 0, (MLKEM_N - 1), r->coeffs, 0, 4095)); // clang-format on + #define poly_frommsg MLKEM_NAMESPACE(poly_frommsg) -void poly_frommsg(poly *r, const uint8_t msg[MLKEM_INDCPA_MSGBYTES]); +/************************************************* + * Name: poly_frommsg + * + * Description: Convert 32-byte message to polynomial + * + * Arguments: - poly *r: pointer to output polynomial + * - const uint8_t *msg: pointer to input message + **************************************************/ +void poly_frommsg(poly *r, const uint8_t msg[MLKEM_INDCPA_MSGBYTES]) + // clang-format off +REQUIRES(IS_FRESH(msg, MLKEM_INDCPA_MSGBYTES)) +REQUIRES(IS_FRESH(r, sizeof(poly))) +ASSIGNS(OBJECT_WHOLE(r)) +ENSURES(ARRAY_IN_BOUNDS(int, k, 0, (MLKEM_N - 1), r->coeffs, 0, (MLKEM_Q - 1))); +// clang-format on #define poly_tomsg MLKEM_NAMESPACE(poly_tomsg) diff --git a/mlkem/verify.h b/mlkem/verify.h index 2f20f8ea3..7a56d5651 100644 --- a/mlkem/verify.h +++ b/mlkem/verify.h @@ -29,7 +29,8 @@ void cmov_int16(int16_t *r, const int16_t v, const uint16_t b) // clang-format off REQUIRES(b == 0 || b == 1) REQUIRES(IS_FRESH(r, sizeof(int16_t))) -ASSIGNS(OBJECT_WHOLE(r)) +ASSIGNS(OBJECT_UPTO(r, sizeof(int16_t))) ENSURES(*r == (b ? v : OLD(*r))); // clang-format on + #endif