Skip to content

Commit

Permalink
CBMC: Add spec + proof for gen_matrix
Browse files Browse the repository at this point in the history
All loops in gen_matrix() are unrolled by CBMC. The loop
handling residual polynomials after x4-batched entry
generation is replaced by conditional generation of a
single polynomial: For K=2 and K=4, batching gives the
full matrix, while for K=3, only one polynomial remains.

Signed-off-by: Hanno Becker <[email protected]>
  • Loading branch information
hanno-becker committed Nov 8, 2024
1 parent c5b619d commit 6833bbf
Show file tree
Hide file tree
Showing 5 changed files with 102 additions and 3 deletions.
54 changes: 54 additions & 0 deletions cbmc/proofs/gen_matrix/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
# SPDX-License-Identifier: Apache-2.0

include ../Makefile_params.common

HARNESS_ENTRY = harness
HARNESS_FILE = gen_matrix_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 = gen_matrix

DEFINES +=
INCLUDES +=

REMOVE_FUNCTION_BODY +=
UNWINDSET += $(MLKEM_NAMESPACE)gen_matrix.0:4 $(MLKEM_NAMESPACE)gen_matrix.1:4 $(MLKEM_NAMESPACE)gen_matrix.2:4

PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c
PROJECT_SOURCES += $(SRCDIR)/mlkem/indcpa.c

CHECK_FUNCTION_CONTRACTS=$(MLKEM_NAMESPACE)gen_matrix
USE_FUNCTION_CONTRACTS=gen_matrix_entry gen_matrix_entry_x4
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)gen_matrix

# 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
3 changes: 3 additions & 0 deletions cbmc/proofs/gen_matrix/cbmc-proof.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# SPDX-License-Identifier: Apache-2.0

# This file marks this directory as containing a CBMC proof.
30 changes: 30 additions & 0 deletions cbmc/proofs/gen_matrix/gen_matrix_harness.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: MIT-0

/*
* Insert copyright notice
*/

/**
* @file gen_matrix_harness.c
* @brief Implements the proof harness for gen_matrix function.
*/

/*
* Insert project header files that
* - include the declaration of the function
* - include the types needed to declare function arguments
*/
#include <stdint.h>
#include "indcpa.h"

/**
* @brief Starting point for formal analysis
*
*/
void harness(void) {
polyvec *a;
uint8_t *seed;
int transposed;
gen_matrix(a, seed, transposed);
}
7 changes: 5 additions & 2 deletions mlkem/indcpa.c
Original file line number Diff line number Diff line change
Expand Up @@ -304,8 +304,8 @@ void gen_matrix(polyvec *a, const uint8_t seed[MLKEM_SYMBYTES],
gen_matrix_entry_x4(&a[0].vec[0] + i, seedxy);
}

// For left over vector, we use single keccak.
for (; i < MLKEM_K * MLKEM_K; i++) {
// For left over polynomial, we use single keccak.
if (i < MLKEM_K * MLKEM_K) {
uint8_t x, y;
x = i / MLKEM_K;
y = i % MLKEM_K;
Expand All @@ -319,8 +319,11 @@ void gen_matrix(polyvec *a, const uint8_t seed[MLKEM_SYMBYTES],
}

gen_matrix_entry(&a[0].vec[0] + i, seed0);
i++;
}

ASSERT(i == MLKEM_K * MLKEM_K, "gen_matrix: failed to generate whole matrix");

#if defined(MLKEM_USE_NATIVE_NTT_CUSTOM_ORDER)
// The public matrix is generated in NTT domain. If the native backend
// uses a custom order in NTT domain, permute A accordingly.
Expand Down
11 changes: 10 additions & 1 deletion mlkem/indcpa.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,20 @@
#define INDCPA_H

#include <stdint.h>
#include "cbmc.h"
#include "params.h"
#include "polyvec.h"

// clang-format off
#define gen_matrix MLKEM_NAMESPACE(gen_matrix)
void gen_matrix(polyvec *a, const uint8_t seed[MLKEM_SYMBYTES], int transposed);
void gen_matrix(polyvec *a, const uint8_t seed[MLKEM_SYMBYTES], int transposed)
REQUIRES(IS_FRESH(a, sizeof(polyvec) * MLKEM_K))
REQUIRES(IS_FRESH(seed, MLKEM_SYMBYTES))
REQUIRES(transposed == 0 || transposed == 1)
ASSIGNS(OBJECT_UPTO(a, sizeof(polyvec) * MLKEM_K))
ENSURES(FORALL(int, x, 0, MLKEM_K - 1, FORALL(int, y, 0, MLKEM_K - 1,
ARRAY_IN_BOUNDS(int, i, 0, MLKEM_N - 1, a[x].vec[y].coeffs, 0, (MLKEM_Q - 1)))))
; // clang-format on

#define indcpa_keypair_derand MLKEM_NAMESPACE(indcpa_keypair_derand)
void indcpa_keypair_derand(uint8_t pk[MLKEM_INDCPA_PUBLICKEYBYTES],
Expand Down

0 comments on commit 6833bbf

Please sign in to comment.