Skip to content

Commit

Permalink
CBMC proofs for type-safety of reduce.c (#232)
Browse files Browse the repository at this point in the history
* Add CBMC proof for `montgomery_reduce()`

Signed-off-by: Rod Chapman <[email protected]>

* Add proof of fqmul()

In particular, this proof shows that for any parameters a and b,
the pre-condition of montgomery_reduce() is satisfied.

Signed-off-by: Rod Chapman <[email protected]>

* Add CBMC proof for `barrett_reduce()`

Signed-off-by: Rod Chapman <[email protected]>

---------

Signed-off-by: Rod Chapman <[email protected]>
  • Loading branch information
rod-chapman authored Oct 16, 2024
1 parent baec037 commit 09b50fe
Show file tree
Hide file tree
Showing 11 changed files with 327 additions and 22 deletions.
54 changes: 54 additions & 0 deletions cbmc/proofs/barrett_reduce/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 = barrett_reduce_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 = barrett_reduce

DEFINES +=
INCLUDES +=

REMOVE_FUNCTION_BODY +=
UNWINDSET +=

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

CHECK_FUNCTION_CONTRACTS=$(KYBER_NAMESPACE)barrett_reduce
USE_FUNCTION_CONTRACTS=
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 = $(KYBER_NAMESPACE)barrett_reduce

# 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
29 changes: 29 additions & 0 deletions cbmc/proofs/barrett_reduce/barrett_reduce_harness.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: MIT-0 AND Apache-2.0

/*
* Insert copyright notice
*/

/**
* @file barrett_reduce_harness.c
* @brief Implements the proof harness for barrett_reduce function.
*/
#include "reduce.h"

/*
* Insert project header files that
* - include the declaration of the function
* - include the types needed to declare function arguments
*/

/**
* @brief Starting point for formal analysis
*
*/
void harness(void) {
int16_t a;
int16_t r;

r = barrett_reduce(a);
}
3 changes: 3 additions & 0 deletions cbmc/proofs/barrett_reduce/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.
54 changes: 54 additions & 0 deletions cbmc/proofs/fqmul/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 = fqmul_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 = fqmul

DEFINES +=
INCLUDES +=

REMOVE_FUNCTION_BODY +=
UNWINDSET +=

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

CHECK_FUNCTION_CONTRACTS=fqmul
USE_FUNCTION_CONTRACTS=$(KYBER_NAMESPACE)montgomery_reduce
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 = fqmul

# 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/fqmul/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.
28 changes: 28 additions & 0 deletions cbmc/proofs/fqmul/fqmul_harness.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: MIT-0 AND Apache-2.0

/*
* Insert copyright notice
*/

/**
* @file montgomery_reduce_harness.c
* @brief Implements the proof harness for montgomery_reduce function.
*/
#include "reduce.h"

/*
* Insert project header files that
* - include the declaration of the function
* - include the types needed to declare function arguments
*/

/**
* @brief Starting point for formal analysis
*
*/
void harness(void) {
int16_t a, b, r;

r = fqmul(a, b);
}
54 changes: 54 additions & 0 deletions cbmc/proofs/montgomery_reduce/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 = montgomery_reduce_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 = montgomery_reduce

DEFINES +=
INCLUDES +=

REMOVE_FUNCTION_BODY +=
UNWINDSET +=

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

CHECK_FUNCTION_CONTRACTS=$(KYBER_NAMESPACE)montgomery_reduce
USE_FUNCTION_CONTRACTS=
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 = $(KYBER_NAMESPACE)montgomery_reduce

# 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/montgomery_reduce/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.
29 changes: 29 additions & 0 deletions cbmc/proofs/montgomery_reduce/montgomery_reduce_harness.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: MIT-0 AND Apache-2.0

/*
* Insert copyright notice
*/

/**
* @file montgomery_reduce_harness.c
* @brief Implements the proof harness for montgomery_reduce function.
*/
#include "reduce.h"

/*
* Insert project header files that
* - include the declaration of the function
* - include the types needed to declare function arguments
*/

/**
* @brief Starting point for formal analysis
*
*/
void harness(void) {
int32_t a;
int16_t r;

r = montgomery_reduce(a);
}
77 changes: 60 additions & 17 deletions mlkem/reduce.c
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,35 @@
#include <stdint.h>
#include "params.h"

// QINV == -3327 converted to uint16_t == -3327 + 65536 == 62209
static const uint32_t QINV = 62209; // q^-1 mod 2^16

/*************************************************
* Name: cast_uint16_to_int16
*
* Description: Cast uint16 value to int16
*
* Returns:
* input x in 0 .. 32767: returns value unchanged
* input x in 32768 .. 65535: returns (x - 65536)
**************************************************/
#ifdef CBMC
#pragma CPROVER check push
#pragma CPROVER check disable "conversion"
#endif
static inline int16_t cast_uint16_to_int16(uint16_t x) {
// PORTABILITY: This relies on uint16_t -> int16_t
// being implemented as the inverse of int16_t -> uint16_t,
// which is implementation-defined (C99 6.3.1.3 (3))
//
// CBMC (correctly) fails to prove this conversion is OK,
// so we have to suppress that check here
return (int16_t)x;
}
#ifdef CBMC
#pragma CPROVER check pop
#endif

/*************************************************
* Name: montgomery_reduce
*
Expand Down Expand Up @@ -41,36 +70,50 @@ int16_t montgomery_reduce(int32_t a) {
// Replace C -> C * q in the above and estimate
// q / 2^17 < 0.0254.

uint16_t u;
int16_t t;
// Compute a*q^{-1} mod 2^16 in unsigned representatives
u = (uint16_t)a * QINV;
// Compute a*q^{-1} mod 2^16 in unsigned representatives
const uint16_t a_reduced = a & UINT16_MAX;
const uint16_t a_inverted = (a_reduced * QINV) & UINT16_MAX;

// Lift to signed canonical representative mod 2^16.
// PORTABILITY: This relies on uint16_t -> int16_t
// being implemented as the inverse of int16_t -> uint16_t,
// which is not mandated by the standard.
t = (int16_t)u;
// By construction, the LHS is divisible by 2^16
t = (a - (int32_t)t * KYBER_Q) >> 16;
return t;
const int16_t t = cast_uint16_to_int16(a_inverted);

int32_t r = a - ((int32_t)t * KYBER_Q);

// PORTABILITY: Right-shift on a signed integer is, strictly-speaking,
// implementation-defined for negative left argument. Here,
// we assume it's sign-preserving "arithmetic" shift right. (C99 6.5.7 (5))
r = r >> 16;

return (int16_t)r;
}

// To divide by KYBER_Q using Barrett multiplication, the "magic number"
// multiplier is round_to_nearest(2**26/KYBER_Q)
#define BPOWER 26
static const int32_t barrett_multiplier =
((1 << BPOWER) + KYBER_Q / 2) / KYBER_Q;

/*************************************************
* Name: barrett_reduce
*
* Description: Barrett reduction; given a 16-bit integer a, computes
* centered representative congruent to a mod q in
*{-(q-1)/2,...,(q-1)/2}
* {-(q-1)/2,...,(q-1)/2}
*
* Arguments: - int16_t a: input integer to be reduced
*
* Returns: integer in {-(q-1)/2,...,(q-1)/2} congruent to a modulo q.
**************************************************/
int16_t barrett_reduce(int16_t a) {
int16_t t;
const int16_t v = ((1 << 26) + KYBER_Q / 2) / KYBER_Q;
// Compute round_to_nearest(a/KYBER_Q) using the multiplier
// above and shift by BPOWER places.
//
// PORTABILITY: Right-shift on a signed integer is, strictly-speaking,
// implementation-defined for negative left argument. Here,
// we assume it's sign-preserving "arithmetic" shift right. (C99 6.5.7 (5))
const int32_t t = (barrett_multiplier * a + (1 << (BPOWER - 1))) >> BPOWER;

t = ((int32_t)v * a + (1 << 25)) >> 26;
t *= KYBER_Q;
return a - t;
// t is in -10 .. +10, so we need 32-bit math to
// evaluate t * KYBER_Q and the subsequent subtraction
return (int16_t)(a - t * KYBER_Q);
}
Loading

0 comments on commit 09b50fe

Please sign in to comment.