diff --git a/.clang-format b/.clang-format index ef5ba2b21..7e80c9ac5 100644 --- a/.clang-format +++ b/.clang-format @@ -1,8 +1,6 @@ # SPDX-License-Identifier: Apache-2.0 # -# clang-format style file for MLKEM-C -# -# This is based on the style for for AWS-LC +# clang-format style file for mlkem-native # BasedOnStyle: Google MaxEmptyLinesToKeep: 3 @@ -17,4 +15,8 @@ IncludeBlocks: Preserve # Designate CBMC contracts/macros that appear in .h files # as "attributes" so they don't get increasingly indented line after line -AttributeMacros: ['REQUIRES', 'ENSURES', 'ASSIGNS', 'INVARIANT'] +BreakBeforeBraces: Allman +WhitespaceSensitiveMacros: ['__contract__', '__loop__' ] +Macros: + - __contract__(x)={} void foo() + - __loop__(x)={} diff --git a/cbmc/proofs/barrett_reduce/barrett_reduce_harness.c b/cbmc/proofs/barrett_reduce/barrett_reduce_harness.c index dd6c2cd9d..6115527b5 100644 --- a/cbmc/proofs/barrett_reduce/barrett_reduce_harness.c +++ b/cbmc/proofs/barrett_reduce/barrett_reduce_harness.c @@ -22,7 +22,8 @@ * @brief Starting point for formal analysis * */ -void harness(void) { +void harness(void) +{ int16_t a; int16_t r; diff --git a/cbmc/proofs/basemul_cached/basemul_cached_harness.c b/cbmc/proofs/basemul_cached/basemul_cached_harness.c index 2b57b1800..2b8a098e6 100644 --- a/cbmc/proofs/basemul_cached/basemul_cached_harness.c +++ b/cbmc/proofs/basemul_cached/basemul_cached_harness.c @@ -23,7 +23,8 @@ * @brief Starting point for formal analysis * */ -void harness(void) { +void harness(void) +{ int16_t *a, *b, *r, b_cached; basemul_cached(r, a, b, b_cached); diff --git a/cbmc/proofs/cmov/cmov_harness.c b/cbmc/proofs/cmov/cmov_harness.c index 1f262e51d..d60c4a501 100644 --- a/cbmc/proofs/cmov/cmov_harness.c +++ b/cbmc/proofs/cmov/cmov_harness.c @@ -22,7 +22,8 @@ * @brief Starting point for formal analysis * */ -void harness(void) { +void harness(void) +{ uint8_t *x, *y; size_t len; uint8_t b; diff --git a/cbmc/proofs/cmov_int16/cmov_int16_harness.c b/cbmc/proofs/cmov_int16/cmov_int16_harness.c index 04fdb9519..e8f64c481 100644 --- a/cbmc/proofs/cmov_int16/cmov_int16_harness.c +++ b/cbmc/proofs/cmov_int16/cmov_int16_harness.c @@ -22,7 +22,8 @@ * @brief Starting point for formal analysis * */ -void harness(void) { +void harness(void) +{ uint16_t b; int16_t *r, v; diff --git a/cbmc/proofs/crypto_kem_dec/crypto_kem_dec_harness.c b/cbmc/proofs/crypto_kem_dec/crypto_kem_dec_harness.c index cf8aa2935..49a341116 100644 --- a/cbmc/proofs/crypto_kem_dec/crypto_kem_dec_harness.c +++ b/cbmc/proofs/crypto_kem_dec/crypto_kem_dec_harness.c @@ -22,7 +22,8 @@ * @brief Starting point for formal analysis * */ -void harness(void) { +void harness(void) +{ uint8_t *a, *b, *c; crypto_kem_dec(a, b, c); } diff --git a/cbmc/proofs/crypto_kem_enc/crypto_kem_enc_harness.c b/cbmc/proofs/crypto_kem_enc/crypto_kem_enc_harness.c index 4e72df026..0df10e7dc 100644 --- a/cbmc/proofs/crypto_kem_enc/crypto_kem_enc_harness.c +++ b/cbmc/proofs/crypto_kem_enc/crypto_kem_enc_harness.c @@ -22,7 +22,8 @@ * @brief Starting point for formal analysis * */ -void harness(void) { +void harness(void) +{ uint8_t *a, *b, *c; crypto_kem_enc(a, b, c); } diff --git a/cbmc/proofs/crypto_kem_enc_derand/crypto_kem_enc_derand_harness.c b/cbmc/proofs/crypto_kem_enc_derand/crypto_kem_enc_derand_harness.c index f870ff9c9..053d125d9 100644 --- a/cbmc/proofs/crypto_kem_enc_derand/crypto_kem_enc_derand_harness.c +++ b/cbmc/proofs/crypto_kem_enc_derand/crypto_kem_enc_derand_harness.c @@ -22,7 +22,8 @@ * @brief Starting point for formal analysis * */ -void harness(void) { +void harness(void) +{ uint8_t *a, *b, *c, *d; crypto_kem_enc_derand(a, b, c, d); } diff --git a/cbmc/proofs/crypto_kem_keypair/crypto_kem_keypair_harness.c b/cbmc/proofs/crypto_kem_keypair/crypto_kem_keypair_harness.c index 1a89d38aa..af14284b1 100644 --- a/cbmc/proofs/crypto_kem_keypair/crypto_kem_keypair_harness.c +++ b/cbmc/proofs/crypto_kem_keypair/crypto_kem_keypair_harness.c @@ -22,7 +22,8 @@ * @brief Starting point for formal analysis * */ -void harness(void) { +void harness(void) +{ uint8_t *a, *b; crypto_kem_keypair(a, b); } diff --git a/cbmc/proofs/crypto_kem_keypair_derand/crypto_kem_keypair_derand_harness.c b/cbmc/proofs/crypto_kem_keypair_derand/crypto_kem_keypair_derand_harness.c index 808c20d54..bda9e34c6 100644 --- a/cbmc/proofs/crypto_kem_keypair_derand/crypto_kem_keypair_derand_harness.c +++ b/cbmc/proofs/crypto_kem_keypair_derand/crypto_kem_keypair_derand_harness.c @@ -22,7 +22,8 @@ * @brief Starting point for formal analysis * */ -void harness(void) { +void harness(void) +{ uint8_t *a, *b, *c; crypto_kem_keypair_derand(a, b, c); } diff --git a/cbmc/proofs/fqmul/fqmul_harness.c b/cbmc/proofs/fqmul/fqmul_harness.c index 2b86ebb26..745934f08 100644 --- a/cbmc/proofs/fqmul/fqmul_harness.c +++ b/cbmc/proofs/fqmul/fqmul_harness.c @@ -22,7 +22,8 @@ * @brief Starting point for formal analysis * */ -void harness(void) { +void harness(void) +{ int16_t a, b, r; r = fqmul(a, b); diff --git a/cbmc/proofs/gen_matrix/gen_matrix_harness.c b/cbmc/proofs/gen_matrix/gen_matrix_harness.c index 23940104c..b5c731701 100644 --- a/cbmc/proofs/gen_matrix/gen_matrix_harness.c +++ b/cbmc/proofs/gen_matrix/gen_matrix_harness.c @@ -23,7 +23,8 @@ * @brief Starting point for formal analysis * */ -void harness(void) { +void harness(void) +{ polyvec *a; uint8_t *seed; int transposed; diff --git a/cbmc/proofs/gen_matrix_entry/gen_matrix_entry_harness.c b/cbmc/proofs/gen_matrix_entry/gen_matrix_entry_harness.c index 7e0e95448..f3643b649 100644 --- a/cbmc/proofs/gen_matrix_entry/gen_matrix_entry_harness.c +++ b/cbmc/proofs/gen_matrix_entry/gen_matrix_entry_harness.c @@ -26,7 +26,8 @@ void gen_matrix_entry(poly *entry, uint8_t seed[MLKEM_SYMBYTES + 16]); * @brief Starting point for formal analysis * */ -void harness(void) { +void harness(void) +{ poly *out; uint8_t *seed; gen_matrix_entry(out, seed); diff --git a/cbmc/proofs/gen_matrix_entry_x4/gen_matrix_entry_x4_harness.c b/cbmc/proofs/gen_matrix_entry_x4/gen_matrix_entry_x4_harness.c index 59fd8579e..bf2de05d8 100644 --- a/cbmc/proofs/gen_matrix_entry_x4/gen_matrix_entry_x4_harness.c +++ b/cbmc/proofs/gen_matrix_entry_x4/gen_matrix_entry_x4_harness.c @@ -26,7 +26,8 @@ void gen_matrix_entry_x4(poly vec[4], uint8_t *seed[4]); * @brief Starting point for formal analysis * */ -void harness(void) { +void harness(void) +{ poly out[4]; uint8_t *seed[4]; gen_matrix_entry_x4(out, seed); diff --git a/cbmc/proofs/indcpa_dec/indcpa_dec_harness.c b/cbmc/proofs/indcpa_dec/indcpa_dec_harness.c index d3817b8cc..f2c8a7ff0 100644 --- a/cbmc/proofs/indcpa_dec/indcpa_dec_harness.c +++ b/cbmc/proofs/indcpa_dec/indcpa_dec_harness.c @@ -23,7 +23,8 @@ * @brief Starting point for formal analysis * */ -void harness(void) { +void harness(void) +{ uint8_t *m, *c, *sk; indcpa_dec(m, c, sk); } diff --git a/cbmc/proofs/indcpa_enc/indcpa_enc_harness.c b/cbmc/proofs/indcpa_enc/indcpa_enc_harness.c index 5c27ad71d..f0cbbb7a9 100644 --- a/cbmc/proofs/indcpa_enc/indcpa_enc_harness.c +++ b/cbmc/proofs/indcpa_enc/indcpa_enc_harness.c @@ -23,7 +23,8 @@ * @brief Starting point for formal analysis * */ -void harness(void) { +void harness(void) +{ uint8_t *a, *b, *c, *d; indcpa_enc(a, b, c, d); } diff --git a/cbmc/proofs/indcpa_keypair_derand/indcpa_keypair_derand_harness.c b/cbmc/proofs/indcpa_keypair_derand/indcpa_keypair_derand_harness.c index 2a0bad193..dfe61214f 100644 --- a/cbmc/proofs/indcpa_keypair_derand/indcpa_keypair_derand_harness.c +++ b/cbmc/proofs/indcpa_keypair_derand/indcpa_keypair_derand_harness.c @@ -22,7 +22,8 @@ * @brief Starting point for formal analysis * */ -void harness(void) { +void harness(void) +{ uint8_t *a, *b, *c; indcpa_keypair_derand(a, b, c); } diff --git a/cbmc/proofs/invntt_layer/invntt_layer_harness.c b/cbmc/proofs/invntt_layer/invntt_layer_harness.c index acff6bf9d..d247b9e65 100644 --- a/cbmc/proofs/invntt_layer/invntt_layer_harness.c +++ b/cbmc/proofs/invntt_layer/invntt_layer_harness.c @@ -23,7 +23,8 @@ void invntt_layer(int16_t *p, int len, int layer); * @brief Starting point for formal analysis * */ -void harness(void) { +void harness(void) +{ int16_t *a; int len, layer; invntt_layer(a, len, layer); diff --git a/cbmc/proofs/matvec_mul/matvec_mul_harness.c b/cbmc/proofs/matvec_mul/matvec_mul_harness.c index 99ffed232..f667d3de7 100644 --- a/cbmc/proofs/matvec_mul/matvec_mul_harness.c +++ b/cbmc/proofs/matvec_mul/matvec_mul_harness.c @@ -26,7 +26,8 @@ void matvec_mul(polyvec *out, polyvec const *a, polyvec const *v, * @brief Starting point for formal analysis * */ -void harness(void) { +void harness(void) +{ polyvec *out, *a, *v; polyvec_mulcache *vc; matvec_mul(out, a, v, vc); diff --git a/cbmc/proofs/montgomery_reduce/montgomery_reduce_harness.c b/cbmc/proofs/montgomery_reduce/montgomery_reduce_harness.c index 804f98d6c..d6a1e4519 100644 --- a/cbmc/proofs/montgomery_reduce/montgomery_reduce_harness.c +++ b/cbmc/proofs/montgomery_reduce/montgomery_reduce_harness.c @@ -22,7 +22,8 @@ * @brief Starting point for formal analysis * */ -void harness(void) { +void harness(void) +{ int32_t a; int16_t r; diff --git a/cbmc/proofs/ntt_butterfly_block/ntt_butterfly_block_harness.c b/cbmc/proofs/ntt_butterfly_block/ntt_butterfly_block_harness.c index b9668979f..adea1d75b 100644 --- a/cbmc/proofs/ntt_butterfly_block/ntt_butterfly_block_harness.c +++ b/cbmc/proofs/ntt_butterfly_block/ntt_butterfly_block_harness.c @@ -18,7 +18,8 @@ void ntt_butterfly_block(int16_t *r, int16_t root, int start, int len, * @brief Starting point for formal analysis * */ -void harness(void) { +void harness(void) +{ int16_t *r, root; int start, stride, bound; ntt_butterfly_block(r, root, start, stride, bound); diff --git a/cbmc/proofs/ntt_layer/ntt_layer_harness.c b/cbmc/proofs/ntt_layer/ntt_layer_harness.c index f66149c2d..4ba7c6a3b 100644 --- a/cbmc/proofs/ntt_layer/ntt_layer_harness.c +++ b/cbmc/proofs/ntt_layer/ntt_layer_harness.c @@ -23,7 +23,8 @@ void ntt_layer(int16_t *p, int len, int layer); * @brief Starting point for formal analysis * */ -void harness(void) { +void harness(void) +{ int16_t *a; int len, layer; ntt_layer(a, len, layer); diff --git a/cbmc/proofs/poly_add/poly_add_harness.c b/cbmc/proofs/poly_add/poly_add_harness.c index 95188ed92..4527da0b7 100644 --- a/cbmc/proofs/poly_add/poly_add_harness.c +++ b/cbmc/proofs/poly_add/poly_add_harness.c @@ -22,7 +22,8 @@ * @brief Starting point for formal analysis * */ -void harness(void) { +void harness(void) +{ poly *r, *b; poly_add(r, b); } diff --git a/cbmc/proofs/poly_basemul_montgomery_cached/poly_basemul_montgomery_cached_harness.c b/cbmc/proofs/poly_basemul_montgomery_cached/poly_basemul_montgomery_cached_harness.c index e7acd0b12..cf2c6e310 100644 --- a/cbmc/proofs/poly_basemul_montgomery_cached/poly_basemul_montgomery_cached_harness.c +++ b/cbmc/proofs/poly_basemul_montgomery_cached/poly_basemul_montgomery_cached_harness.c @@ -22,7 +22,8 @@ * @brief Starting point for formal analysis * */ -void harness(void) { +void harness(void) +{ poly *r, *a, *b; poly_mulcache *b_cached; diff --git a/cbmc/proofs/poly_cbd_eta1/poly_cbd_eta1_harness.c b/cbmc/proofs/poly_cbd_eta1/poly_cbd_eta1_harness.c index 5db63d002..8e582f75b 100644 --- a/cbmc/proofs/poly_cbd_eta1/poly_cbd_eta1_harness.c +++ b/cbmc/proofs/poly_cbd_eta1/poly_cbd_eta1_harness.c @@ -22,7 +22,8 @@ * @brief Starting point for formal analysis * */ -void harness(void) { +void harness(void) +{ uint8_t *buf; poly *a; diff --git a/cbmc/proofs/poly_cbd_eta2/poly_cbd_eta2_harness.c b/cbmc/proofs/poly_cbd_eta2/poly_cbd_eta2_harness.c index 72970e2aa..93a1ace30 100644 --- a/cbmc/proofs/poly_cbd_eta2/poly_cbd_eta2_harness.c +++ b/cbmc/proofs/poly_cbd_eta2/poly_cbd_eta2_harness.c @@ -22,7 +22,8 @@ * @brief Starting point for formal analysis * */ -void harness(void) { +void harness(void) +{ uint8_t *buf; poly *a; diff --git a/cbmc/proofs/poly_compress_du/poly_compress_du_harness.c b/cbmc/proofs/poly_compress_du/poly_compress_du_harness.c index 8bdfebe85..b00cd73e6 100644 --- a/cbmc/proofs/poly_compress_du/poly_compress_du_harness.c +++ b/cbmc/proofs/poly_compress_du/poly_compress_du_harness.c @@ -22,7 +22,8 @@ * @brief Starting point for formal analysis * */ -void harness(void) { +void harness(void) +{ poly *r; uint8_t *a; diff --git a/cbmc/proofs/poly_compress_dv/poly_compress_dv_harness.c b/cbmc/proofs/poly_compress_dv/poly_compress_dv_harness.c index 9c07c4081..449a2860e 100644 --- a/cbmc/proofs/poly_compress_dv/poly_compress_dv_harness.c +++ b/cbmc/proofs/poly_compress_dv/poly_compress_dv_harness.c @@ -22,7 +22,8 @@ * @brief Starting point for formal analysis * */ -void harness(void) { +void harness(void) +{ poly *r; uint8_t *a; diff --git a/cbmc/proofs/poly_decompress_du/poly_decompress_du_harness.c b/cbmc/proofs/poly_decompress_du/poly_decompress_du_harness.c index 03c8112a0..a885ea092 100644 --- a/cbmc/proofs/poly_decompress_du/poly_decompress_du_harness.c +++ b/cbmc/proofs/poly_decompress_du/poly_decompress_du_harness.c @@ -22,7 +22,8 @@ * @brief Starting point for formal analysis * */ -void harness(void) { +void harness(void) +{ poly *r; uint8_t *a; diff --git a/cbmc/proofs/poly_decompress_dv/poly_decompress_dv_harness.c b/cbmc/proofs/poly_decompress_dv/poly_decompress_dv_harness.c index 3834b242e..007581265 100644 --- a/cbmc/proofs/poly_decompress_dv/poly_decompress_dv_harness.c +++ b/cbmc/proofs/poly_decompress_dv/poly_decompress_dv_harness.c @@ -22,7 +22,8 @@ * @brief Starting point for formal analysis * */ -void harness(void) { +void harness(void) +{ poly *r; uint8_t *a; diff --git a/cbmc/proofs/poly_frombytes/poly_frombytes_harness.c b/cbmc/proofs/poly_frombytes/poly_frombytes_harness.c index 709c66665..246afc3f9 100644 --- a/cbmc/proofs/poly_frombytes/poly_frombytes_harness.c +++ b/cbmc/proofs/poly_frombytes/poly_frombytes_harness.c @@ -22,7 +22,8 @@ * @brief Starting point for formal analysis * */ -void harness(void) { +void harness(void) +{ poly *a; uint8_t *r; diff --git a/cbmc/proofs/poly_frommsg/poly_frommsg_harness.c b/cbmc/proofs/poly_frommsg/poly_frommsg_harness.c index 98704bc9c..1001c7cc8 100644 --- a/cbmc/proofs/poly_frommsg/poly_frommsg_harness.c +++ b/cbmc/proofs/poly_frommsg/poly_frommsg_harness.c @@ -22,7 +22,8 @@ * @brief Starting point for formal analysis * */ -void harness(void) { +void harness(void) +{ poly *a; uint8_t *msg; diff --git a/cbmc/proofs/poly_getnoise_eta1122_4x/poly_getnoise_eta1122_4x_harness.c b/cbmc/proofs/poly_getnoise_eta1122_4x/poly_getnoise_eta1122_4x_harness.c index 921b61721..50e187da0 100644 --- a/cbmc/proofs/poly_getnoise_eta1122_4x/poly_getnoise_eta1122_4x_harness.c +++ b/cbmc/proofs/poly_getnoise_eta1122_4x/poly_getnoise_eta1122_4x_harness.c @@ -22,7 +22,8 @@ * @brief Starting point for formal analysis * */ -void harness(void) { +void harness(void) +{ uint8_t *seed; poly *r0, *r1, *r2, *r3; uint8_t nonce0, nonce1, nonce2, nonce3; diff --git a/cbmc/proofs/poly_getnoise_eta1_4x/poly_getnoise_eta1_4x_harness.c b/cbmc/proofs/poly_getnoise_eta1_4x/poly_getnoise_eta1_4x_harness.c index f4493e1f9..62bf4c30c 100644 --- a/cbmc/proofs/poly_getnoise_eta1_4x/poly_getnoise_eta1_4x_harness.c +++ b/cbmc/proofs/poly_getnoise_eta1_4x/poly_getnoise_eta1_4x_harness.c @@ -22,7 +22,8 @@ * @brief Starting point for formal analysis * */ -void harness(void) { +void harness(void) +{ uint8_t *seed; poly *r0, *r1, *r2, *r3; uint8_t nonce0, nonce1, nonce2, nonce3; diff --git a/cbmc/proofs/poly_getnoise_eta2/poly_getnoise_eta2_harness.c b/cbmc/proofs/poly_getnoise_eta2/poly_getnoise_eta2_harness.c index 792c9d3c4..c2dfc7ccf 100644 --- a/cbmc/proofs/poly_getnoise_eta2/poly_getnoise_eta2_harness.c +++ b/cbmc/proofs/poly_getnoise_eta2/poly_getnoise_eta2_harness.c @@ -22,7 +22,8 @@ * @brief Starting point for formal analysis * */ -void harness(void) { +void harness(void) +{ uint8_t *seed; poly *r; uint8_t nonce; diff --git a/cbmc/proofs/poly_invntt_tomont/poly_invntt_tomont_harness.c b/cbmc/proofs/poly_invntt_tomont/poly_invntt_tomont_harness.c index 4aecf5f05..ca4bbd8fb 100644 --- a/cbmc/proofs/poly_invntt_tomont/poly_invntt_tomont_harness.c +++ b/cbmc/proofs/poly_invntt_tomont/poly_invntt_tomont_harness.c @@ -22,7 +22,8 @@ * @brief Starting point for formal analysis * */ -void harness(void) { +void harness(void) +{ poly *p; poly_invntt_tomont(p); } diff --git a/cbmc/proofs/poly_mulcache_compute/poly_mulcache_compute_harness.c b/cbmc/proofs/poly_mulcache_compute/poly_mulcache_compute_harness.c index c449db444..406e43e5b 100644 --- a/cbmc/proofs/poly_mulcache_compute/poly_mulcache_compute_harness.c +++ b/cbmc/proofs/poly_mulcache_compute/poly_mulcache_compute_harness.c @@ -23,7 +23,8 @@ * @brief Starting point for formal analysis * */ -void harness(void) { +void harness(void) +{ poly_mulcache *x; poly *a; diff --git a/cbmc/proofs/poly_ntt/poly_ntt_harness.c b/cbmc/proofs/poly_ntt/poly_ntt_harness.c index a5d6bf972..ab3a8a35b 100644 --- a/cbmc/proofs/poly_ntt/poly_ntt_harness.c +++ b/cbmc/proofs/poly_ntt/poly_ntt_harness.c @@ -22,7 +22,8 @@ * @brief Starting point for formal analysis * */ -void harness(void) { +void harness(void) +{ poly *a; poly_ntt(a); } diff --git a/cbmc/proofs/poly_reduce/poly_reduce_harness.c b/cbmc/proofs/poly_reduce/poly_reduce_harness.c index 4925073ef..2666e1a1a 100644 --- a/cbmc/proofs/poly_reduce/poly_reduce_harness.c +++ b/cbmc/proofs/poly_reduce/poly_reduce_harness.c @@ -22,7 +22,8 @@ * @brief Starting point for formal analysis * */ -void harness(void) { +void harness(void) +{ poly *a; /* Contracts for this function are in poly.h */ diff --git a/cbmc/proofs/poly_sub/poly_sub_harness.c b/cbmc/proofs/poly_sub/poly_sub_harness.c index 1bf1f46cb..e93ccd405 100644 --- a/cbmc/proofs/poly_sub/poly_sub_harness.c +++ b/cbmc/proofs/poly_sub/poly_sub_harness.c @@ -22,7 +22,8 @@ * @brief Starting point for formal analysis * */ -void harness(void) { +void harness(void) +{ poly *r, *b; poly_sub(r, b); } diff --git a/cbmc/proofs/poly_tobytes/poly_tobytes_harness.c b/cbmc/proofs/poly_tobytes/poly_tobytes_harness.c index d5c85e376..34d80e6d5 100644 --- a/cbmc/proofs/poly_tobytes/poly_tobytes_harness.c +++ b/cbmc/proofs/poly_tobytes/poly_tobytes_harness.c @@ -22,7 +22,8 @@ * @brief Starting point for formal analysis * */ -void harness(void) { +void harness(void) +{ poly *a; uint8_t *r; diff --git a/cbmc/proofs/poly_tomont/poly_tomont_harness.c b/cbmc/proofs/poly_tomont/poly_tomont_harness.c index c0b174326..9d22115bc 100644 --- a/cbmc/proofs/poly_tomont/poly_tomont_harness.c +++ b/cbmc/proofs/poly_tomont/poly_tomont_harness.c @@ -22,7 +22,8 @@ * @brief Starting point for formal analysis * */ -void harness(void) { +void harness(void) +{ poly *a; poly_tomont(a); diff --git a/cbmc/proofs/poly_tomsg/poly_tomsg_harness.c b/cbmc/proofs/poly_tomsg/poly_tomsg_harness.c index d7aacef5d..5f6222734 100644 --- a/cbmc/proofs/poly_tomsg/poly_tomsg_harness.c +++ b/cbmc/proofs/poly_tomsg/poly_tomsg_harness.c @@ -22,7 +22,8 @@ * @brief Starting point for formal analysis * */ -void harness(void) { +void harness(void) +{ poly *a; uint8_t *msg; diff --git a/cbmc/proofs/polyvec_add/polyvec_add_harness.c b/cbmc/proofs/polyvec_add/polyvec_add_harness.c index bade46b4d..247c7577d 100644 --- a/cbmc/proofs/polyvec_add/polyvec_add_harness.c +++ b/cbmc/proofs/polyvec_add/polyvec_add_harness.c @@ -22,7 +22,8 @@ * @brief Starting point for formal analysis * */ -void harness(void) { +void harness(void) +{ polyvec *r, *b; polyvec_add(r, b); } diff --git a/cbmc/proofs/polyvec_basemul_acc_montgomery_cached/polyvec_basemul_acc_montgomery_cached_harness.c b/cbmc/proofs/polyvec_basemul_acc_montgomery_cached/polyvec_basemul_acc_montgomery_cached_harness.c index cd850858a..8edc7d3d2 100644 --- a/cbmc/proofs/polyvec_basemul_acc_montgomery_cached/polyvec_basemul_acc_montgomery_cached_harness.c +++ b/cbmc/proofs/polyvec_basemul_acc_montgomery_cached/polyvec_basemul_acc_montgomery_cached_harness.c @@ -22,7 +22,8 @@ * @brief Starting point for formal analysis * */ -void harness(void) { +void harness(void) +{ poly *r; polyvec *a, *b; polyvec_mulcache *b_cached; diff --git a/cbmc/proofs/polyvec_compress_du/polyvec_compress_du_harness.c b/cbmc/proofs/polyvec_compress_du/polyvec_compress_du_harness.c index 26f0ffef1..9526ff28e 100644 --- a/cbmc/proofs/polyvec_compress_du/polyvec_compress_du_harness.c +++ b/cbmc/proofs/polyvec_compress_du/polyvec_compress_du_harness.c @@ -23,7 +23,8 @@ * @brief Starting point for formal analysis * */ -void harness(void) { +void harness(void) +{ polyvec *r; uint8_t *a; diff --git a/cbmc/proofs/polyvec_decompress_du/polyvec_decompress_du_harness.c b/cbmc/proofs/polyvec_decompress_du/polyvec_decompress_du_harness.c index 3a763d533..cd95e33bd 100644 --- a/cbmc/proofs/polyvec_decompress_du/polyvec_decompress_du_harness.c +++ b/cbmc/proofs/polyvec_decompress_du/polyvec_decompress_du_harness.c @@ -23,7 +23,8 @@ * @brief Starting point for formal analysis * */ -void harness(void) { +void harness(void) +{ polyvec *a; uint8_t *r; diff --git a/cbmc/proofs/polyvec_frombytes/polyvec_frombytes_harness.c b/cbmc/proofs/polyvec_frombytes/polyvec_frombytes_harness.c index 3ca0e7bdd..929c3a855 100644 --- a/cbmc/proofs/polyvec_frombytes/polyvec_frombytes_harness.c +++ b/cbmc/proofs/polyvec_frombytes/polyvec_frombytes_harness.c @@ -22,7 +22,8 @@ * @brief Starting point for formal analysis * */ -void harness(void) { +void harness(void) +{ polyvec *a; uint8_t *r; polyvec_frombytes(a, r); diff --git a/cbmc/proofs/polyvec_invntt_tomont/polyvec_invntt_tomont_harness.c b/cbmc/proofs/polyvec_invntt_tomont/polyvec_invntt_tomont_harness.c index 8a33a07e6..ffb0e9547 100644 --- a/cbmc/proofs/polyvec_invntt_tomont/polyvec_invntt_tomont_harness.c +++ b/cbmc/proofs/polyvec_invntt_tomont/polyvec_invntt_tomont_harness.c @@ -22,7 +22,8 @@ * @brief Starting point for formal analysis * */ -void harness(void) { +void harness(void) +{ polyvec *r; polyvec_invntt_tomont(r); } diff --git a/cbmc/proofs/polyvec_mulcache_compute/polyvec_mulcache_compute_harness.c b/cbmc/proofs/polyvec_mulcache_compute/polyvec_mulcache_compute_harness.c index 2146e7476..76721f97a 100644 --- a/cbmc/proofs/polyvec_mulcache_compute/polyvec_mulcache_compute_harness.c +++ b/cbmc/proofs/polyvec_mulcache_compute/polyvec_mulcache_compute_harness.c @@ -22,7 +22,8 @@ * @brief Starting point for formal analysis * */ -void harness(void) { +void harness(void) +{ polyvec_mulcache *x; polyvec *a; diff --git a/cbmc/proofs/polyvec_ntt/polyvec_ntt_harness.c b/cbmc/proofs/polyvec_ntt/polyvec_ntt_harness.c index c462c4547..abf371183 100644 --- a/cbmc/proofs/polyvec_ntt/polyvec_ntt_harness.c +++ b/cbmc/proofs/polyvec_ntt/polyvec_ntt_harness.c @@ -23,7 +23,8 @@ * @brief Starting point for formal analysis * */ -void harness(void) { +void harness(void) +{ polyvec *r; polyvec_ntt(r); } diff --git a/cbmc/proofs/polyvec_reduce/polyvec_reduce_harness.c b/cbmc/proofs/polyvec_reduce/polyvec_reduce_harness.c index c6c5b5566..2fe018f35 100644 --- a/cbmc/proofs/polyvec_reduce/polyvec_reduce_harness.c +++ b/cbmc/proofs/polyvec_reduce/polyvec_reduce_harness.c @@ -22,7 +22,8 @@ * @brief Starting point for formal analysis * */ -void harness(void) { +void harness(void) +{ polyvec *a; polyvec_reduce(a); } diff --git a/cbmc/proofs/polyvec_tobytes/polyvec_tobytes_harness.c b/cbmc/proofs/polyvec_tobytes/polyvec_tobytes_harness.c index db10c30e7..c57dd5b12 100644 --- a/cbmc/proofs/polyvec_tobytes/polyvec_tobytes_harness.c +++ b/cbmc/proofs/polyvec_tobytes/polyvec_tobytes_harness.c @@ -22,7 +22,8 @@ * @brief Starting point for formal analysis * */ -void harness(void) { +void harness(void) +{ polyvec *a; uint8_t *r; polyvec_tobytes(r, a); diff --git a/cbmc/proofs/polyvec_tomont/polyvec_tomont_harness.c b/cbmc/proofs/polyvec_tomont/polyvec_tomont_harness.c index af87d25c5..e9a18fc24 100644 --- a/cbmc/proofs/polyvec_tomont/polyvec_tomont_harness.c +++ b/cbmc/proofs/polyvec_tomont/polyvec_tomont_harness.c @@ -22,7 +22,8 @@ * @brief Starting point for formal analysis * */ -void harness(void) { +void harness(void) +{ polyvec *a; polyvec_tomont(a); } diff --git a/cbmc/proofs/proof_guide.md b/cbmc/proofs/proof_guide.md index 4262f0a17..dae27aba8 100644 --- a/cbmc/proofs/proof_guide.md +++ b/cbmc/proofs/proof_guide.md @@ -31,16 +31,16 @@ Notes: 2. The counter variable should be a constant within the loop body. In the example above, do _not_ modify (or take the address of) `i` in the body of the loop. 3. `int` is the best type for the counter variable. `unsigned` integer types complicate matters with their modulo N semantics. Avoid `size_t` since its large range (possibly unsigned 64 bit) can slow proofs down. -CBMC requires basic assigns, loop-invariant, and decreases contracts _in exactly that order_. Note that the contracts appear _before_ the opening `{` of the loop body, so we also need to tell `clang-format` not to reformat these lines. The basic pattern is thus: +CBMC requires basic assigns, loop-invariant, and decreases contracts _in exactly that order_. In mlkem-native, we +further enclose the entire loop annotations in a `__loop__` macro. Note that the contracts appear _before_ the opening. ``` for (int i = 0; i < C; i++) - // clang-format off -ASSIGNS(i) // plus whatever else S does -INVARIANT(i >= 0) -INVARIANT(i <= C) -DECREASES(C - i) -// clang-format on +__loop__( + assigns(i) // plus whatever else S does + invariant(i >= 0) + invariant(i <= C) + decreases(C - i)) { S; } @@ -54,13 +54,12 @@ A common pattern - doing something to every element of an array. An example woul ``` void zero_array_ts (uint8_t *dst, int len) - // clang-format off -REQUIRES(IS_FRESH(dst, len)) -ASSIGNS(OBJECT_WHOLE(dst)); -// clang-format on +__contract__( + requires(memory_no_alias(dst, len)) + assigns(object_whole(dst))); ``` -The `IS_FRESH(dst,len)` in the precondition means that the pointer value `dst` is not `NULL` and is pointing to at least `len` bytes of data. The `ASSIGNS` contract (in this case) means that when the function returns, it promises to have updated the whole object pointed to by dst - in this case `len` bytes of data. +The `memory_no_alias(dst,len)` in the precondition means that the pointer value `dst` is not `NULL` and is pointing to at least `len` bytes of data. The `assigns` contract (in this case) means that when the function returns, it promises to have updated the whole object pointed to by dst - in this case `len` bytes of data. The body: @@ -68,18 +67,17 @@ The body: void zero_array_ts (uint8_t *dst, int len) { for (int i = 0; i < len; i++) - // clang-format off - ASSIGNS(i, OBJECT_WHOLE(dst)) - INVARIANT(i >= 0 && i <= len) - DECREASES(len - i) - // clang-format on + __loop__( + assigns(i, object_whole(dst)) + invariant(i >= 0 && i <= len) + decreases(len - i)) { dst[i] = 0; } } ``` The only real "type safety proofs" here are that -1. dst is pointing at exactly "len" bytes - this is given by the IS_FRESH() part of the precondition. +1. dst is pointing at exactly "len" bytes - this is given by the memory_no_alias() part of the precondition. 2. The assignment to `dst[i]` does not have a buffer overflow. This requires a proof that `i >= 0 && i < len` which is trivially discharged given the loop invariant AND the fact that the loop _hasn't_ terminated (so we know `i < len` too). ### Correctness proof of zero_array @@ -90,14 +88,13 @@ The function specification is extended: ``` void zero_array_correct (uint8_t *dst, int len) - // clang-format off -REQUIRES(IS_FRESH(dst, len)) -ASSIGNS(OBJECT_WHOLE(dst)) -ENSURES(FORALL { int k; (0 <= k && k < len) ==> dst[k] == 0 }); -// clang-format on +__contract__( + requires(memory_no_alias(dst, len)) + assigns(object_whole(dst)) + ensures(forall { int k; (0 <= k && k < len) ==> dst[k] == 0 })); ``` -Note the required order of the contracts is always REQUIRES, ASSIGNS, ENSURES. +Note the required order of the contracts is always requires, assigns, ensures. The body is the same, but with a stronger loop invariant. The invariant says that "after j loop iterations, we've zeroed the first j elements of the array", so: @@ -105,12 +102,11 @@ The body is the same, but with a stronger loop invariant. The invariant says tha void zero_array_correct (uint8_t *dst, int len) { for (int i = 0; i < len; i++) - // clang-format off - ASSIGNS(i, OBJECT_WHOLE(dst)) - INVARIANT(i >= 0 && i <= len) - INVARIANT(FORALL { int j; (0 <= j && j <= i - 1) ==> dst[j] == 0 } ) - DECREASES(len - i) - // clang-format on + __loop__( + assigns(i, object_whole(dst)) + invariant(i >= 0 && i <= len) + invariant(forall { int j; (0 <= j && j <= i - 1) ==> dst[j] == 0 } ) + decreases(len - i)) { dst[i] = 0; } @@ -118,22 +114,22 @@ void zero_array_correct (uint8_t *dst, int len) ``` Rules of thumb: -1. Don't overload your program variables with quantified variables inside your FORALL contracts. It get confusing if you do. +1. Don't overload your program variables with quantified variables inside your forall contracts. It get confusing if you do. 2. The type of the quanitified variable is _signed_ "int". This is important. 3. The path in the program from the loop-invariant, through the final loop exit test, to the implicit `return` statement is "nothing" or a "null statement". The proof needs to establish that (on the final iteration), the loop invariant _and_ the loop exit condidtion imply the post-condition. Imagine having to do that if there's some really complex code _after_ the loop body. -This pattern also brings up another important trick - the use of "null ranges" in FORALL expressions. Consider the loop invariant above. We need to prove that it's true on the first entry to the loop (i.e. when i == 0). +This pattern also brings up another important trick - the use of "null ranges" in forall expressions. Consider the loop invariant above. We need to prove that it's true on the first entry to the loop (i.e. when i == 0). Substituting i == 0 into there, we need to prove ``` -FORALL { int j; (0 <= j && j <= -1) ==> dst[j] == 0 } +forall { int j; (0 <= j && j <= -1) ==> dst[j] == 0 } ``` but how can j be both larger-than-or-equal-to 0 AND less-than-or-equal-to -1 at the same time? Answer: it can't! So.. the left hand side of the quantified predicate is False, so it reduces to: ``` -FORALL { int j; false ==> dst[j] == 0 } +forall { int j; false ==> dst[j] == 0 } ``` The `==>` is a logical implication, and we know that `False ==> ANYTHING` is True, so all is well. @@ -150,7 +146,7 @@ Another important sanity check. If there are no statements following the loop bo // Loop invariant (i >= 0 && i <= len && - (FORALL { int j; (0 <= j && j <= i - 1) ==> dst[j] == 0 } ) + (forall { int j; (0 <= j && j <= i - 1) ==> dst[j] == 0 } ) && // Loop exit condition must be TRUE, so i == len) @@ -158,7 +154,7 @@ i == len) ==> // Post-condition -FORALL { int k; (0 <= k && k < len) ==> dst[k] == 0 } +forall { int k; (0 <= k && k < len) ==> dst[k] == 0 } ``` The loop exit condition means that we can just replace `i` with `len` in the hypotheses, to get: @@ -166,17 +162,17 @@ The loop exit condition means that we can just replace `i` with `len` in the hyp ``` len >= 0 && len <= len && -(FORALL { int j; (0 <= j && j <= len - 1) ==> dst[j] == 0 } ) +(forall { int j; (0 <= j && j <= len - 1) ==> dst[j] == 0 } ) ==> -FORALL { int k; (0 <= k && k < len) ==> dst[k] == 0 } +forall { int k; (0 <= k && k < len) ==> dst[k] == 0 } ``` `j <= len - 1` can be simplified to `j < len` so that simplifies to: ``` -FORALL { int j; (0 <= j && j < len) ==> dst[j] == 0 } +forall { int j; (0 <= j && j < len) ==> dst[j] == 0 } ==> -FORALL { int k; (0 <= k && k < len) ==> dst[k] == 0 } +forall { int k; (0 <= k && k < len) ==> dst[k] == 0 } ``` which is True. @@ -252,7 +248,7 @@ The file `XXX_harness.c` should declare a single function called `XXX_harness()` For example, if a function f() expects a single parameter which is a pointer to some struct s: ``` void f(s *x) -REQUIRES(IS_FRESH(x, sizeof(s)); +requires(memory_no_alias(x, sizeof(s)); ``` then the harness should contain ``` @@ -265,7 +261,7 @@ The harness should _not_ contain f(&a); ``` -Using contracts, this harness function should not need to contain any CBMC `ASSUME` or `ASSERT` statements at all. +Using contracts, this harness function should not need to contain any CBMC `assume` or `assert` statements at all. ### Supply top-level contracts @@ -280,11 +276,10 @@ Check for any BOUND macros in the body that give range constraints on the parame The order of the top-level contracts for a function is _always_: ``` t1 XXX(params...) - // clang-format off -REQUIRES() -ASSIGNS() -ENSURES(); -// clang-format on +__contract__( + requires() + assigns() + ensures()); ``` with a final semi-colon on the end of the last one. That final semi-colon is needed to terminate the function declaration as per normal C syntax. @@ -366,20 +361,19 @@ The comments on `poly_tobytes()` give us a clear hint: * - r: pointer to output byte array * (of MLKEM_POLYBYTES bytes) ``` -So we need to write a REQUIRES contract to constrain the ranges of the coefficients denoted by the parameter `a`. There is no constraint on the output byte array, other than it must be the right length, which is given by the function prototype. +So we need to write a requires contract to constrain the ranges of the coefficients denoted by the parameter `a`. There is no constraint on the output byte array, other than it must be the right length, which is given by the function prototype. We can use the macros in `cbmc.h` to help, thus: ``` void poly_tobytes(uint8_t r[MLKEM_POLYBYTES], const poly *a) - // clang-format off -REQUIRES(IS_FRESH(a, sizeof(poly))) -REQUIRES(ARRAY_BOUND(a->coeffs, 0, (MLKEM_N - 1), 0, (MLKEM_Q - 1))) -ASSIGNS(OBJECT_WHOLE(r)); -// clang-format on +__contract__( + requires(memory_no_alias(a, sizeof(poly))) + requires(array_bound(a->coeffs, 0, (MLKEM_N - 1), 0, (MLKEM_Q - 1))) + assigns(object_whole(r))); ``` -`ARRAY_BOUND` is a macro that expands to a quantified expression that expresses that the elemtns of `a->coeffs` between index values `0` and `(MLKEM_N - 1)` (inclusive) are in the range `0` through `(MLKEM_Q - 1)` (also inclusive). See the macro definition in `mlkem/cbmc.h` for details. +`array_bound` is a macro that expands to a quantified expression that expresses that the elemtns of `a->coeffs` between index values `0` and `(MLKEM_N - 1)` (inclusive) are in the range `0` through `(MLKEM_Q - 1)` (also inclusive). See the macro definition in `mlkem/cbmc.h` for details. ### Interior contracts and loop invariants @@ -399,13 +393,12 @@ Therefore, we add: ``` for (int i = 0; i < MLKEM_N / 2; i++) - // clang-format off - ASSIGNS(i, OBJECT_WHOLE(r)) - INVARIANT(i >= 0) - INVARIANT(i <= MLKEM_N / 2) - DECREASES(MLKEM_N / 2 - i) - // clang-format on - { ... } + __loop__( + assigns(i, object_whole(r)) + invariant(i >= 0) + invariant(i <= MLKEM_N / 2) + decreases(MLKEM_N / 2 - i)) + { ... } ``` Note that the invariant `i >= 0` could be ommitted since `i` is of an `unsigned` integer type. It is given here for clarity only. diff --git a/cbmc/proofs/rej_uniform/rej_uniform_harness.c b/cbmc/proofs/rej_uniform/rej_uniform_harness.c index 4fb2311f8..036bd0969 100644 --- a/cbmc/proofs/rej_uniform/rej_uniform_harness.c +++ b/cbmc/proofs/rej_uniform/rej_uniform_harness.c @@ -23,7 +23,8 @@ * @brief Starting point for formal analysis * */ -void harness(void) { +void harness(void) +{ unsigned int target, offset, inlen; int16_t *r; uint8_t *buf; diff --git a/cbmc/proofs/scalar_compress_d1/scalar_compress_d1_harness.c b/cbmc/proofs/scalar_compress_d1/scalar_compress_d1_harness.c index 8e97edcd3..30c8dfee6 100644 --- a/cbmc/proofs/scalar_compress_d1/scalar_compress_d1_harness.c +++ b/cbmc/proofs/scalar_compress_d1/scalar_compress_d1_harness.c @@ -22,7 +22,8 @@ * @brief Starting point for formal analysis * */ -void harness(void) { +void harness(void) +{ uint16_t u; /* Contracts for this function are in poly.h */ diff --git a/cbmc/proofs/scalar_compress_d10/scalar_compress_d10_harness.c b/cbmc/proofs/scalar_compress_d10/scalar_compress_d10_harness.c index 6b8814754..329c3f46a 100644 --- a/cbmc/proofs/scalar_compress_d10/scalar_compress_d10_harness.c +++ b/cbmc/proofs/scalar_compress_d10/scalar_compress_d10_harness.c @@ -22,7 +22,8 @@ * @brief Starting point for formal analysis * */ -void harness(void) { +void harness(void) +{ uint16_t u; /* Contracts for this function are in poly.h */ diff --git a/cbmc/proofs/scalar_compress_d11/scalar_compress_d11_harness.c b/cbmc/proofs/scalar_compress_d11/scalar_compress_d11_harness.c index 3404dda99..9acaea6d2 100644 --- a/cbmc/proofs/scalar_compress_d11/scalar_compress_d11_harness.c +++ b/cbmc/proofs/scalar_compress_d11/scalar_compress_d11_harness.c @@ -22,7 +22,8 @@ * @brief Starting point for formal analysis * */ -void harness(void) { +void harness(void) +{ uint16_t u; /* Contracts for this function are in poly.h */ diff --git a/cbmc/proofs/scalar_compress_d4/scalar_compress_d4_harness.c b/cbmc/proofs/scalar_compress_d4/scalar_compress_d4_harness.c index d70ff394d..76e72dc47 100644 --- a/cbmc/proofs/scalar_compress_d4/scalar_compress_d4_harness.c +++ b/cbmc/proofs/scalar_compress_d4/scalar_compress_d4_harness.c @@ -22,7 +22,8 @@ * @brief Starting point for formal analysis * */ -void harness(void) { +void harness(void) +{ uint16_t u; /* Contracts for this function are in poly.h */ diff --git a/cbmc/proofs/scalar_compress_d5/scalar_compress_d5_harness.c b/cbmc/proofs/scalar_compress_d5/scalar_compress_d5_harness.c index cf592f5e9..513d6df9d 100644 --- a/cbmc/proofs/scalar_compress_d5/scalar_compress_d5_harness.c +++ b/cbmc/proofs/scalar_compress_d5/scalar_compress_d5_harness.c @@ -22,7 +22,8 @@ * @brief Starting point for formal analysis * */ -void harness(void) { +void harness(void) +{ uint16_t u; /* Contracts for this function are in poly.h */ diff --git a/cbmc/proofs/scalar_decompress_d10/scalar_decompress_d10_harness.c b/cbmc/proofs/scalar_decompress_d10/scalar_decompress_d10_harness.c index a78ab5e34..6d536b33a 100644 --- a/cbmc/proofs/scalar_decompress_d10/scalar_decompress_d10_harness.c +++ b/cbmc/proofs/scalar_decompress_d10/scalar_decompress_d10_harness.c @@ -22,7 +22,8 @@ * @brief Starting point for formal analysis * */ -void harness(void) { +void harness(void) +{ uint32_t u; uint16_t d; d = scalar_decompress_d10(u); diff --git a/cbmc/proofs/scalar_decompress_d11/scalar_decompress_d11_harness.c b/cbmc/proofs/scalar_decompress_d11/scalar_decompress_d11_harness.c index 90826ef99..24553840a 100644 --- a/cbmc/proofs/scalar_decompress_d11/scalar_decompress_d11_harness.c +++ b/cbmc/proofs/scalar_decompress_d11/scalar_decompress_d11_harness.c @@ -22,7 +22,8 @@ * @brief Starting point for formal analysis * */ -void harness(void) { +void harness(void) +{ uint32_t u; uint16_t d; d = scalar_decompress_d11(u); diff --git a/cbmc/proofs/scalar_decompress_d4/scalar_decompress_d4_harness.c b/cbmc/proofs/scalar_decompress_d4/scalar_decompress_d4_harness.c index 524f935ef..24d93d53c 100644 --- a/cbmc/proofs/scalar_decompress_d4/scalar_decompress_d4_harness.c +++ b/cbmc/proofs/scalar_decompress_d4/scalar_decompress_d4_harness.c @@ -22,7 +22,8 @@ * @brief Starting point for formal analysis * */ -void harness(void) { +void harness(void) +{ uint32_t u; uint16_t d; d = scalar_decompress_d4(u); diff --git a/cbmc/proofs/scalar_decompress_d5/scalar_decompress_d5_harness.c b/cbmc/proofs/scalar_decompress_d5/scalar_decompress_d5_harness.c index 7c4de9d91..8072c006c 100644 --- a/cbmc/proofs/scalar_decompress_d5/scalar_decompress_d5_harness.c +++ b/cbmc/proofs/scalar_decompress_d5/scalar_decompress_d5_harness.c @@ -22,7 +22,8 @@ * @brief Starting point for formal analysis * */ -void harness(void) { +void harness(void) +{ uint32_t u; uint16_t d; d = scalar_decompress_d5(u); diff --git a/cbmc/proofs/scalar_signed_to_unsigned_q/scalar_signed_to_unsigned_q_harness.c b/cbmc/proofs/scalar_signed_to_unsigned_q/scalar_signed_to_unsigned_q_harness.c index 14566567d..be9413d30 100644 --- a/cbmc/proofs/scalar_signed_to_unsigned_q/scalar_signed_to_unsigned_q_harness.c +++ b/cbmc/proofs/scalar_signed_to_unsigned_q/scalar_signed_to_unsigned_q_harness.c @@ -23,7 +23,8 @@ * @brief Starting point for formal analysis * */ -void harness(void) { +void harness(void) +{ int16_t u; /* Contracts for this function are in poly.h */ diff --git a/cbmc/proofs/verify/verify_harness.c b/cbmc/proofs/verify/verify_harness.c index c3215fc72..c7f7cf5e5 100644 --- a/cbmc/proofs/verify/verify_harness.c +++ b/cbmc/proofs/verify/verify_harness.c @@ -22,7 +22,8 @@ * @brief Starting point for formal analysis * */ -void harness(void) { +void harness(void) +{ uint8_t *a; uint8_t *b; size_t len; diff --git a/fips202/fips202.c b/fips202/fips202.c index 8a1839046..dc920794e 100644 --- a/fips202/fips202.c +++ b/fips202/fips202.c @@ -33,22 +33,28 @@ *Keccak-derived functions **************************************************/ static void keccak_absorb(uint64_t *s, uint32_t r, const uint8_t *m, - size_t mlen, uint8_t p) { - while (mlen >= r) { + size_t mlen, uint8_t p) +{ + while (mlen >= r) + { KeccakF1600_StateXORBytes(s, m, 0, r); KeccakF1600_StatePermute(s); mlen -= r; m += r; } - if (mlen > 0) { + if (mlen > 0) + { KeccakF1600_StateXORBytes(s, m, 0, mlen); } - if (mlen == r - 1) { + if (mlen == r - 1) + { p |= 128; KeccakF1600_StateXORBytes(s, &p, mlen, 1); - } else { + } + else + { KeccakF1600_StateXORBytes(s, &p, mlen, 1); p = 128; KeccakF1600_StateXORBytes(s, &p, r - 1, 1); @@ -68,8 +74,10 @@ static void keccak_absorb(uint64_t *s, uint32_t r, const uint8_t *m, * - uint32_t r: rate in bytes (e.g., 168 for SHAKE128) **************************************************/ static void keccak_squeezeblocks(uint8_t *h, size_t nblocks, uint64_t *s, - uint32_t r) { - while (nblocks > 0) { + uint32_t r) +{ + while (nblocks > 0) + { KeccakF1600_StatePermute(s); KeccakF1600_StateExtractBytes(s, h, 0, r); h += r; @@ -87,10 +95,12 @@ static void keccak_squeezeblocks(uint8_t *h, size_t nblocks, uint64_t *s, * 26th value represents either the number of absorbed bytes * that have not been permuted, or not-yet-squeezed bytes. **************************************************/ -static void keccak_inc_init(uint64_t *s_inc) { +static void keccak_inc_init(uint64_t *s_inc) +{ size_t i; - for (i = 0; i < 25; ++i) { + for (i = 0; i < 25; ++i) + { s_inc[i] = 0; } s_inc[25] = 0; @@ -110,9 +120,11 @@ static void keccak_inc_init(uint64_t *s_inc) { * - size_t mlen: length of input in bytes **************************************************/ static void keccak_inc_absorb(uint64_t *s_inc, uint32_t r, const uint8_t *m, - size_t mlen) { + size_t mlen) +{ /* Recall that s_inc[25] is the non-absorbed bytes xored into the state */ - while (mlen + s_inc[25] >= r) { + while (mlen + s_inc[25] >= r) + { KeccakF1600_StateXORBytes(s_inc, m, s_inc[25], r - s_inc[25]); mlen -= (size_t)(r - s_inc[25]); m += r - s_inc[25]; @@ -138,13 +150,17 @@ static void keccak_inc_absorb(uint64_t *s_inc, uint32_t r, const uint8_t *m, * - uint8_t p: domain-separation byte for different * Keccak-derived functions **************************************************/ -static void keccak_inc_finalize(uint64_t *s_inc, uint32_t r, uint8_t p) { +static void keccak_inc_finalize(uint64_t *s_inc, uint32_t r, uint8_t p) +{ /* After keccak_inc_absorb, we are guaranteed that s_inc[25] < r, so we can always use one more byte for p in the current state. */ - if (s_inc[25] == r - 1) { + if (s_inc[25] == r - 1) + { p |= 128; KeccakF1600_StateXORBytes(s_inc, &p, s_inc[25], 1); - } else { + } + else + { KeccakF1600_StateXORBytes(s_inc, &p, s_inc[25], 1); p = 128; KeccakF1600_StateXORBytes(s_inc, &p, r - 1, 1); @@ -166,11 +182,15 @@ static void keccak_inc_finalize(uint64_t *s_inc, uint32_t r, uint8_t p) { * - uint32_t r: rate in bytes (e.g., 168 for SHAKE128) **************************************************/ static void keccak_inc_squeeze(uint8_t *h, size_t outlen, uint64_t *s_inc, - uint32_t r) { + uint32_t r) +{ size_t len; - if (outlen < s_inc[25]) { + if (outlen < s_inc[25]) + { len = outlen; - } else { + } + else + { len = s_inc[25]; } @@ -180,12 +200,16 @@ static void keccak_inc_squeeze(uint8_t *h, size_t outlen, uint64_t *s_inc, s_inc[25] -= len; /* Then squeeze the remaining necessary blocks */ - while (outlen > 0) { + while (outlen > 0) + { KeccakF1600_StatePermute(s_inc); - if (outlen < r) { + if (outlen < r) + { len = outlen; - } else { + } + else + { len = r; } KeccakF1600_StateExtractBytes(s_inc, h, 0, len); @@ -198,16 +222,18 @@ static void keccak_inc_squeeze(uint8_t *h, size_t outlen, uint64_t *s_inc, void shake256_inc_init(shake256incctx *state) { keccak_inc_init(state->ctx); } void shake256_inc_absorb(shake256incctx *state, const uint8_t *input, - size_t inlen) { + size_t inlen) +{ keccak_inc_absorb(state->ctx, SHAKE256_RATE, input, inlen); } -void shake256_inc_finalize(shake256incctx *state) { +void shake256_inc_finalize(shake256incctx *state) +{ keccak_inc_finalize(state->ctx, SHAKE256_RATE, 0x1F); } -void shake256_inc_squeeze(uint8_t *output, size_t outlen, - shake256incctx *state) { +void shake256_inc_squeeze(uint8_t *output, size_t outlen, shake256incctx *state) +{ keccak_inc_squeeze(output, outlen, state->ctx, SHAKE256_RATE); } @@ -225,9 +251,11 @@ void shake256_inc_ctx_release(shake256incctx *state) { (void)state; } *state * - size_t inlen: length of input in bytes **************************************************/ -void shake128_absorb(shake128ctx *state, const uint8_t *input, size_t inlen) { +void shake128_absorb(shake128ctx *state, const uint8_t *input, size_t inlen) +{ int i; - for (i = 0; i < 25; i++) { + for (i = 0; i < 25; i++) + { state->ctx[i] = 0; } @@ -246,8 +274,8 @@ void shake128_absorb(shake128ctx *state, const uint8_t *input, size_t inlen) { *to output) * - shake128ctx *state: pointer to in/output Keccak state **************************************************/ -void shake128_squeezeblocks(uint8_t *output, size_t nblocks, - shake128ctx *state) { +void shake128_squeezeblocks(uint8_t *output, size_t nblocks, shake128ctx *state) +{ keccak_squeezeblocks(output, nblocks, state->ctx, SHAKE128_RATE); } @@ -265,7 +293,8 @@ void shake128_ctx_release(shake128ctx *state) { (void)state; } * - size_t inlen: length of input in bytes **************************************************/ void shake256(uint8_t *output, size_t outlen, const uint8_t *input, - size_t inlen) { + size_t inlen) +{ shake256incctx state; keccak_inc_init(state.ctx); @@ -287,7 +316,8 @@ void shake256(uint8_t *output, size_t outlen, const uint8_t *input, * - const uint8_t *input: pointer to input * - size_t inlen: length of input in bytes **************************************************/ -void sha3_256(uint8_t *output, const uint8_t *input, size_t inlen) { +void sha3_256(uint8_t *output, const uint8_t *input, size_t inlen) +{ uint64_t ctx[26]; keccak_inc_init(ctx); @@ -308,7 +338,8 @@ void sha3_256(uint8_t *output, const uint8_t *input, size_t inlen) { * - const uint8_t *input: pointer to input * - size_t inlen: length of input in bytes **************************************************/ -void sha3_512(uint8_t *output, const uint8_t *input, size_t inlen) { +void sha3_512(uint8_t *output, const uint8_t *input, size_t inlen) +{ uint64_t ctx[26]; keccak_inc_init(ctx); diff --git a/fips202/fips202.h b/fips202/fips202.h index cd9d874ad..1ce85b52d 100644 --- a/fips202/fips202.h +++ b/fips202/fips202.h @@ -17,12 +17,14 @@ // Context for non-incremental API -typedef struct { +typedef struct +{ uint64_t ctx[25]; } shake128ctx; // Context for incremental API -typedef struct { +typedef struct +{ uint64_t ctx[26]; } shake256incctx; @@ -32,25 +34,24 @@ typedef struct { * with the same state. */ #define shake128_absorb FIPS202_NAMESPACE(shake128_absorb) -void shake128_absorb(shake128ctx *state, const uint8_t *input, - size_t inlen) // clang-format off -REQUIRES(IS_FRESH(state, sizeof(shake128ctx))) -REQUIRES(IS_FRESH(input, inlen)) -ASSIGNS(OBJECT_UPTO(state, sizeof(shake128ctx))); -// clang-format on +void shake128_absorb(shake128ctx *state, const uint8_t *input, size_t inlen) +__contract__( + requires(memory_no_alias(state, sizeof(shake128ctx))) + requires(memory_no_alias(input, inlen)) + assigns(memory_slice(state, sizeof(shake128ctx))) +); /* Squeeze output out of the sponge. * * Supports being called multiple times */ #define shake128_squeezeblocks FIPS202_NAMESPACE(shake128_squeezeblocks) -void shake128_squeezeblocks(uint8_t *output, size_t nblocks, - shake128ctx *state) // clang-format off -REQUIRES(IS_FRESH(state, sizeof(shake128ctx))) -REQUIRES(IS_FRESH(output, nblocks * SHAKE128_RATE)) -ASSIGNS(OBJECT_UPTO(output, nblocks * SHAKE128_RATE), OBJECT_UPTO(state, sizeof(shake128ctx))); -// clang-format on - +void shake128_squeezeblocks(uint8_t *output, size_t nblocks, shake128ctx *state) +__contract__( + requires(memory_no_alias(state, sizeof(shake128ctx))) + requires(memory_no_alias(output, nblocks * SHAKE128_RATE)) + assigns(memory_slice(output, nblocks * SHAKE128_RATE), memory_slice(state, sizeof(shake128ctx))) +); /* Free the state */ #define shake128_ctx_release FIPS202_NAMESPACE(shake128_ctx_release) @@ -82,32 +83,33 @@ void shake256_inc_ctx_release(shake256incctx *state); * output is not permitted */ #define shake256 FIPS202_NAMESPACE(shake256) void shake256(uint8_t *output, size_t outlen, const uint8_t *input, - size_t inlen) // clang-format off -REQUIRES(IS_FRESH(input, inlen)) -REQUIRES(IS_FRESH(output, outlen)) -ASSIGNS(OBJECT_UPTO(output, outlen)); -// clang-format on + size_t inlen) +__contract__( + requires(memory_no_alias(input, inlen)) + requires(memory_no_alias(output, outlen)) + assigns(memory_slice(output, outlen)) +); /* One-stop SHA3_256 call. Aliasing between input and * output is not permitted */ #define SHA3_256_HASHBYTES 32 #define sha3_256 FIPS202_NAMESPACE(sha3_256) -void sha3_256(uint8_t *output, const uint8_t *input, - size_t inlen) // clang-format off -REQUIRES(IS_FRESH(input, inlen)) -REQUIRES(IS_FRESH(output, SHA3_256_HASHBYTES)) -ASSIGNS(OBJECT_UPTO(output, SHA3_256_HASHBYTES)); -// clang-format on +void sha3_256(uint8_t *output, const uint8_t *input, size_t inlen) +__contract__( + requires(memory_no_alias(input, inlen)) + requires(memory_no_alias(output, SHA3_256_HASHBYTES)) + assigns(memory_slice(output, SHA3_256_HASHBYTES)) +); /* One-stop SHA3_512 call. Aliasing between input and * output is not permitted */ #define SHA3_512_HASHBYTES 64 #define sha3_512 FIPS202_NAMESPACE(sha3_512) -void sha3_512(uint8_t *output, const uint8_t *input, - size_t inlen) // clang-format off -REQUIRES(IS_FRESH(input, inlen)) -REQUIRES(IS_FRESH(output, SHA3_512_HASHBYTES)) -ASSIGNS(OBJECT_UPTO(output, SHA3_512_HASHBYTES)); -// clang-format on +void sha3_512(uint8_t *output, const uint8_t *input, size_t inlen) +__contract__( + requires(memory_no_alias(input, inlen)) + requires(memory_no_alias(output, SHA3_512_HASHBYTES)) + assigns(memory_slice(output, SHA3_512_HASHBYTES)) +); #endif diff --git a/fips202/fips202x4.c b/fips202/fips202x4.c index 7c54d512f..90697ab16 100644 --- a/fips202/fips202x4.c +++ b/fips202/fips202x4.c @@ -8,10 +8,12 @@ static void keccak_absorb_x4(keccakx4_state *ctxt, uint32_t r, const uint8_t *in0, const uint8_t *in1, const uint8_t *in2, const uint8_t *in3, - size_t inlen, uint8_t p) { + size_t inlen, uint8_t p) +{ uint64_t *s = (uint64_t *)ctxt; - while (inlen >= r) { + while (inlen >= r) + { KeccakF1600x4_StateXORBytes(s, in0, in1, in2, in3, 0, r); KeccakF1600x4_StatePermute(s); @@ -22,14 +24,18 @@ static void keccak_absorb_x4(keccakx4_state *ctxt, uint32_t r, inlen -= r; } - if (inlen > 0) { + if (inlen > 0) + { KeccakF1600x4_StateXORBytes(s, in0, in1, in2, in3, 0, inlen); } - if (inlen == r - 1) { + if (inlen == r - 1) + { p |= 128; KeccakF1600x4_StateXORBytes(s, &p, &p, &p, &p, inlen, 1); - } else { + } + else + { KeccakF1600x4_StateXORBytes(s, &p, &p, &p, &p, inlen, 1); p = 128; KeccakF1600x4_StateXORBytes(s, &p, &p, &p, &p, r - 1, 1); @@ -38,10 +44,12 @@ static void keccak_absorb_x4(keccakx4_state *ctxt, uint32_t r, static void keccak_squeezeblocks_x4(uint8_t *out0, uint8_t *out1, uint8_t *out2, uint8_t *out3, size_t nblocks, - keccakx4_state *ctxt, uint32_t r) { + keccakx4_state *ctxt, uint32_t r) +{ uint64_t *s = (uint64_t *)ctxt; - while (nblocks > 0) { + while (nblocks > 0) + { KeccakF1600x4_StatePermute(s); KeccakF1600x4_StateExtractBytes(s, out0, out1, out2, out3, 0, r); @@ -55,14 +63,16 @@ static void keccak_squeezeblocks_x4(uint8_t *out0, uint8_t *out1, uint8_t *out2, void shake128x4_absorb(keccakx4_state *state, const uint8_t *in0, const uint8_t *in1, const uint8_t *in2, - const uint8_t *in3, size_t inlen) { + const uint8_t *in3, size_t inlen) +{ memset(state, 0, sizeof(keccakx4_state)); keccak_absorb_x4(state, SHAKE128_RATE, in0, in1, in2, in3, inlen, 0x1F); } void shake256x4_absorb(keccakx4_state *state, const uint8_t *in0, const uint8_t *in1, const uint8_t *in2, - const uint8_t *in3, size_t inlen) { + const uint8_t *in3, size_t inlen) +{ memset(state, 0, sizeof(keccakx4_state)); keccak_absorb_x4(state, SHAKE256_RATE, in0, in1, in2, in3, inlen, 0x1F); } @@ -70,14 +80,16 @@ void shake256x4_absorb(keccakx4_state *state, const uint8_t *in0, void shake128x4_squeezeblocks(uint8_t *out0, uint8_t *out1, uint8_t *out2, uint8_t *out3, size_t nblocks, - keccakx4_state *state) { + keccakx4_state *state) +{ keccak_squeezeblocks_x4(out0, out1, out2, out3, nblocks, state, SHAKE128_RATE); } void shake256x4_squeezeblocks(uint8_t *out0, uint8_t *out1, uint8_t *out2, uint8_t *out3, size_t nblocks, - keccakx4_state *state) { + keccakx4_state *state) +{ keccak_squeezeblocks_x4(out0, out1, out2, out3, nblocks, state, SHAKE256_RATE); } @@ -88,7 +100,8 @@ void shake256x4_ctx_release(keccakx4_state *state) { (void)state; } void shake256x4(uint8_t *out0, uint8_t *out1, uint8_t *out2, uint8_t *out3, size_t outlen, uint8_t *in0, uint8_t *in1, uint8_t *in2, - uint8_t *in3, size_t inlen) { + uint8_t *in3, size_t inlen) +{ keccakx4_state statex; size_t nblocks = outlen / SHAKE256_RATE; uint8_t tmp[KECCAK_WAY][SHAKE256_RATE]; @@ -103,7 +116,8 @@ void shake256x4(uint8_t *out0, uint8_t *out1, uint8_t *out2, uint8_t *out3, outlen -= nblocks * SHAKE256_RATE; - if (outlen) { + if (outlen) + { shake256x4_squeezeblocks(tmp[0], tmp[1], tmp[2], tmp[3], 1, &statex); memcpy(out0, tmp[0], outlen); memcpy(out1, tmp[1], outlen); diff --git a/fips202/fips202x4.h b/fips202/fips202x4.h index 064a33983..63cc95f80 100644 --- a/fips202/fips202x4.h +++ b/fips202/fips202x4.h @@ -20,30 +20,32 @@ void shake128x4_absorb(keccakx4_state *state, const uint8_t *in0, #define shake256x4_absorb FIPS202_NAMESPACE(shake256x4_absorb) void shake256x4_absorb(keccakx4_state *state, const uint8_t *in0, const uint8_t *in1, const uint8_t *in2, - const uint8_t *in3, size_t inlen) // clang-format off -REQUIRES(IS_FRESH(state, sizeof(keccakx4_state))) -REQUIRES(IS_FRESH(in0, inlen)) -REQUIRES(IS_FRESH(in1, inlen)) -REQUIRES(IS_FRESH(in2, inlen)) -REQUIRES(IS_FRESH(in3, inlen)) -ASSIGNS(OBJECT_WHOLE(state)); -// clang-format on + const uint8_t *in3, size_t inlen) +__contract__( + requires(memory_no_alias(state, sizeof(keccakx4_state))) + requires(memory_no_alias(in0, inlen)) + requires(memory_no_alias(in1, inlen)) + requires(memory_no_alias(in2, inlen)) + requires(memory_no_alias(in3, inlen)) + assigns(object_whole(state)) +); #define shake128x4_squeezeblocks FIPS202_NAMESPACE(shake128x4_squeezeblocks) void shake128x4_squeezeblocks(uint8_t *out0, uint8_t *out1, uint8_t *out2, uint8_t *out3, size_t nblocks, - keccakx4_state *state) // clang-format off -REQUIRES(IS_FRESH(state, sizeof(keccakx4_state))) -REQUIRES(IS_FRESH(out0, nblocks * SHAKE128_RATE)) -REQUIRES(IS_FRESH(out1, nblocks * SHAKE128_RATE)) -REQUIRES(IS_FRESH(out2, nblocks * SHAKE128_RATE)) -REQUIRES(IS_FRESH(out3, nblocks * SHAKE128_RATE)) -ASSIGNS(OBJECT_UPTO(out0, nblocks * SHAKE128_RATE), - OBJECT_UPTO(out1, nblocks * SHAKE128_RATE), - OBJECT_UPTO(out2, nblocks * SHAKE128_RATE), - OBJECT_UPTO(out3, nblocks * SHAKE128_RATE), - OBJECT_WHOLE(state)); -// clang-format on + keccakx4_state *state) +__contract__( + requires(memory_no_alias(state, sizeof(keccakx4_state))) + requires(memory_no_alias(out0, nblocks * SHAKE128_RATE)) + requires(memory_no_alias(out1, nblocks * SHAKE128_RATE)) + requires(memory_no_alias(out2, nblocks * SHAKE128_RATE)) + requires(memory_no_alias(out3, nblocks * SHAKE128_RATE)) + assigns(memory_slice(out0, nblocks * SHAKE128_RATE), + memory_slice(out1, nblocks * SHAKE128_RATE), + memory_slice(out2, nblocks * SHAKE128_RATE), + memory_slice(out3, nblocks * SHAKE128_RATE), + object_whole(state)) +); #define shake256x4_squeezeblocks FIPS202_NAMESPACE(shake256x4_squeezeblocks) void shake256x4_squeezeblocks(uint8_t *out0, uint8_t *out1, uint8_t *out2, @@ -59,20 +61,21 @@ void shake256x4_ctx_release(keccakx4_state *state); #define shake256x4 FIPS202_NAMESPACE(shake256x4) void shake256x4(uint8_t *out0, uint8_t *out1, uint8_t *out2, uint8_t *out3, size_t outlen, uint8_t *in0, uint8_t *in1, uint8_t *in2, - uint8_t *in3, size_t inlen) // clang-format off + uint8_t *in3, size_t inlen) +__contract__( // Refine +prove this spec, e.g. add disjointness constraints? -REQUIRES(READABLE(in0, inlen)) -REQUIRES(READABLE(in1, inlen)) -REQUIRES(READABLE(in2, inlen)) -REQUIRES(READABLE(in3, inlen)) -REQUIRES(WRITEABLE(out0, outlen)) -REQUIRES(WRITEABLE(out1, outlen)) -REQUIRES(WRITEABLE(out2, outlen)) -REQUIRES(WRITEABLE(out3, outlen)) -ASSIGNS(OBJECT_UPTO(out0, outlen)) -ASSIGNS(OBJECT_UPTO(out1, outlen)) -ASSIGNS(OBJECT_UPTO(out2, outlen)) -ASSIGNS(OBJECT_UPTO(out3, outlen)); -// clang-format on + requires(readable(in0, inlen)) + requires(readable(in1, inlen)) + requires(readable(in2, inlen)) + requires(readable(in3, inlen)) + requires(writeable(out0, outlen)) + requires(writeable(out1, outlen)) + requires(writeable(out2, outlen)) + requires(writeable(out3, outlen)) + assigns(memory_slice(out0, outlen)) + assigns(memory_slice(out1, outlen)) + assigns(memory_slice(out2, outlen)) + assigns(memory_slice(out3, outlen)) +); #endif diff --git a/fips202/keccakf1600.c b/fips202/keccakf1600.c index 6d329d57a..5f076aa3a 100644 --- a/fips202/keccakf1600.c +++ b/fips202/keccakf1600.c @@ -20,32 +20,38 @@ #define ROL(a, offset) ((a << offset) ^ (a >> (64 - offset))) void KeccakF1600_StateExtractBytes(uint64_t *state, unsigned char *data, - unsigned int offset, unsigned int length) { + unsigned int offset, unsigned int length) +{ #if defined(SYS_LITTLE_ENDIAN) uint8_t *state_ptr = (uint8_t *)state + offset; - for (unsigned int i = 0; i < length; i++) { + for (unsigned int i = 0; i < length; i++) + { data[i] = state_ptr[i]; } #else /* SYS_LITTLE_ENDIAN */ // Portable version unsigned int i; - for (i = 0; i < length; i++) { + for (i = 0; i < length; i++) + { data[i] = state[(offset + i) >> 3] >> (8 * ((offset + i) & 0x07)); } #endif /* SYS_LITTLE_ENDIAN */ } void KeccakF1600_StateXORBytes(uint64_t *state, const unsigned char *data, - unsigned int offset, unsigned int length) { + unsigned int offset, unsigned int length) +{ #if defined(SYS_LITTLE_ENDIAN) uint8_t *state_ptr = (uint8_t *)state + offset; - for (unsigned int i = 0; i < length; i++) { + for (unsigned int i = 0; i < length; i++) + { state_ptr[i] ^= data[i]; } #else /* SYS_LITTLE_ENDIAN */ // Portable version unsigned int i; - for (i = 0; i < length; i++) { + for (i = 0; i < length; i++) + { state[(offset + i) >> 3] ^= (uint64_t)data[i] << (8 * ((offset + i) & 0x07)); } @@ -55,7 +61,8 @@ void KeccakF1600_StateXORBytes(uint64_t *state, const unsigned char *data, void KeccakF1600x4_StateExtractBytes(uint64_t *state, unsigned char *data0, unsigned char *data1, unsigned char *data2, unsigned char *data3, unsigned int offset, - unsigned int length) { + unsigned int length) +{ KeccakF1600_StateExtractBytes(state + KECCAK_LANES * 0, data0, offset, length); KeccakF1600_StateExtractBytes(state + KECCAK_LANES * 1, data1, offset, @@ -70,14 +77,16 @@ void KeccakF1600x4_StateXORBytes(uint64_t *state, const unsigned char *data0, const unsigned char *data1, const unsigned char *data2, const unsigned char *data3, - unsigned int offset, unsigned int length) { + unsigned int offset, unsigned int length) +{ KeccakF1600_StateXORBytes(state + KECCAK_LANES * 0, data0, offset, length); KeccakF1600_StateXORBytes(state + KECCAK_LANES * 1, data1, offset, length); KeccakF1600_StateXORBytes(state + KECCAK_LANES * 2, data2, offset, length); KeccakF1600_StateXORBytes(state + KECCAK_LANES * 3, data3, offset, length); } -void KeccakF1600x4_StatePermute(uint64_t *state) { +void KeccakF1600x4_StatePermute(uint64_t *state) +{ #if defined(MLKEM_USE_FIPS202_X4_NATIVE) keccak_f1600_x4_native(state); #elif defined(MLKEM_USE_FIPS202_X2_NATIVE) @@ -106,7 +115,8 @@ static const uint64_t KeccakF_RoundConstants[NROUNDS] = { (uint64_t)0x8000000080008081ULL, (uint64_t)0x8000000000008080ULL, (uint64_t)0x0000000080000001ULL, (uint64_t)0x8000000080008008ULL}; -void KeccakF1600_StatePermute(uint64_t *state) { +void KeccakF1600_StatePermute(uint64_t *state) +{ int round; uint64_t Aba, Abe, Abi, Abo, Abu; @@ -149,7 +159,8 @@ void KeccakF1600_StatePermute(uint64_t *state) { Aso = state[23]; Asu = state[24]; - for (round = 0; round < NROUNDS; round += 2) { + for (round = 0; round < NROUNDS; round += 2) + { // prepareTheta BCa = Aba ^ Aga ^ Aka ^ Ama ^ Asa; BCe = Abe ^ Age ^ Ake ^ Ame ^ Ase; @@ -371,7 +382,8 @@ void KeccakF1600_StatePermute(uint64_t *state) { #undef round } #else /* !MLKEM_USE_FIPS202_X1_NATIVE */ -void KeccakF1600_StatePermute(uint64_t *state) { +void KeccakF1600_StatePermute(uint64_t *state) +{ keccak_f1600_x1_native(state); } #endif /* !MLKEM_USE_FIPS202_X1_NATIVE */ diff --git a/fips202/native/aarch64/profiles/cortex_a55.h b/fips202/native/aarch64/profiles/cortex_a55.h index cb77505f0..5881ed56d 100644 --- a/fips202/native/aarch64/profiles/cortex_a55.h +++ b/fips202/native/aarch64/profiles/cortex_a55.h @@ -13,7 +13,8 @@ // On Cortex-A55, we use lazy rotation assembly for Keccak-x1, // but no batched assembly implementation. #define MLKEM_USE_FIPS202_X1_NATIVE -static inline void keccak_f1600_x1_native(uint64_t *state) { +static inline void keccak_f1600_x1_native(uint64_t *state) +{ keccak_f1600_x1_scalar_asm_opt(state); } diff --git a/fips202/native/aarch64/profiles/default.h b/fips202/native/aarch64/profiles/default.h index c76ddf761..3ea38f292 100644 --- a/fips202/native/aarch64/profiles/default.h +++ b/fips202/native/aarch64/profiles/default.h @@ -27,12 +27,14 @@ // fall back to the standard C implementation. #if defined(__ARM_FEATURE_SHA3) && defined(__APPLE__) #define MLKEM_USE_FIPS202_X1_NATIVE -static inline void keccak_f1600_x1_native(uint64_t *state) { +static inline void keccak_f1600_x1_native(uint64_t *state) +{ keccak_f1600_x1_v84a_asm_clean(state); } #elif !defined(SYS_AARCH64_SLOW_BARREL_SHIFTER) #define MLKEM_USE_FIPS202_X1_NATIVE -static inline void keccak_f1600_x1_native(uint64_t *state) { +static inline void keccak_f1600_x1_native(uint64_t *state) +{ keccak_f1600_x1_scalar_asm_opt(state); } #endif /* !SYS_AARCH64_SLOW_BARREL_SHIFTER */ @@ -54,12 +56,14 @@ static inline void keccak_f1600_x1_native(uint64_t *state) { // instructions only. #if defined(__APPLE__) #define MLKEM_USE_FIPS202_X2_NATIVE -static inline void keccak_f1600_x2_native(uint64_t *state) { +static inline void keccak_f1600_x2_native(uint64_t *state) +{ keccak_f1600_x2_v84a_asm_clean(state); } #else /* __APPLE__ */ #define MLKEM_USE_FIPS202_X4_NATIVE -static inline void keccak_f1600_x4_native(uint64_t *state) { +static inline void keccak_f1600_x4_native(uint64_t *state) +{ keccak_f1600_x4_scalar_v8a_v84a_hybrid_asm_opt(state); } #endif /* __APPLE__ */ @@ -67,7 +71,8 @@ static inline void keccak_f1600_x4_native(uint64_t *state) { #else /* __ARM_FEATURE_SHA3 */ #define MLKEM_USE_FIPS202_X4_NATIVE -static inline void keccak_f1600_x4_native(uint64_t *state) { +static inline void keccak_f1600_x4_native(uint64_t *state) +{ keccak_f1600_x4_scalar_v8a_asm_hybrid_opt(state); } diff --git a/fips202/native/x86_64/profiles/xkcp.h b/fips202/native/x86_64/profiles/xkcp.h index f5b04e89a..96af69280 100644 --- a/fips202/native/x86_64/profiles/xkcp.h +++ b/fips202/native/x86_64/profiles/xkcp.h @@ -13,7 +13,8 @@ #if defined(MLKEM_USE_NATIVE_X86_64) && defined(SYS_X86_64_AVX2) #define MLKEM_USE_FIPS202_X4_NATIVE -static inline void keccak_f1600_x4_native(uint64_t *state) { +static inline void keccak_f1600_x4_native(uint64_t *state) +{ KeccakP1600times4_PermuteAll_24rounds(state); } diff --git a/fips202/native/x86_64/xkcp/KeccakP-1600-times4-SIMD256.c b/fips202/native/x86_64/xkcp/KeccakP-1600-times4-SIMD256.c index b445d7e9d..0cc10ab0e 100644 --- a/fips202/native/x86_64/xkcp/KeccakP-1600-times4-SIMD256.c +++ b/fips202/native/x86_64/xkcp/KeccakP-1600-times4-SIMD256.c @@ -321,7 +321,8 @@ static ALIGN(KeccakP1600times4_statesAlignment) const UINT64 #include #define copyFromState(X, state) \ - do { \ + do \ + { \ const uint64_t *state64 = (const uint64_t *)(state); \ __m256i _idx = \ _mm256_set_epi64x((long long)&state64[75], (long long)&state64[50], \ @@ -354,7 +355,8 @@ static ALIGN(KeccakP1600times4_statesAlignment) const UINT64 } while (0); #define SCATTER_STORE256(state, idx, v) \ - do { \ + do \ + { \ const uint64_t *state64 = (const uint64_t *)(state); \ __m128d t = _mm_castsi128_pd(_mm256_castsi256_si128((v))); \ _mm_storel_pd((double *)&state64[0 + (idx)], t); \ @@ -425,7 +427,8 @@ static ALIGN(KeccakP1600times4_statesAlignment) const UINT64 #endif #include "KeccakP-1600-unrolling.macros" -void KeccakP1600times4_PermuteAll_24rounds(void *states) { +void KeccakP1600times4_PermuteAll_24rounds(void *states) +{ V256 *statesAsLanes = (V256 *)states; declareABCDE #ifndef KeccakP1600times4_fullUnrolling diff --git a/mlkem/cbd.c b/mlkem/cbd.c index a4e2be2b5..1de0bed52 100644 --- a/mlkem/cbd.c +++ b/mlkem/cbd.c @@ -14,7 +14,8 @@ * * Returns 32-bit unsigned integer loaded from x **************************************************/ -static uint32_t load32_littleendian(const uint8_t x[4]) { +static uint32_t load32_littleendian(const uint8_t x[4]) +{ uint32_t r; r = (uint32_t)x[0]; r |= (uint32_t)x[1] << 8; @@ -35,7 +36,8 @@ static uint32_t load32_littleendian(const uint8_t x[4]) { * Returns 32-bit unsigned integer loaded from x (most significant byte is zero) **************************************************/ #if MLKEM_ETA1 == 3 -static uint32_t load24_littleendian(const uint8_t x[3]) { +static uint32_t load24_littleendian(const uint8_t x[3]) +{ uint32_t r; r = (uint32_t)x[0]; r |= (uint32_t)x[1] << 8; @@ -54,24 +56,27 @@ static uint32_t load24_littleendian(const uint8_t x[3]) { * Arguments: - poly *r: pointer to output polynomial * - const uint8_t *buf: pointer to input byte array **************************************************/ -static void cbd2(poly *r, const uint8_t buf[2 * MLKEM_N / 4]) { - for (int i = 0; i < MLKEM_N / 8; i++) // clang-format off - INVARIANT(i >= 0 && i <= MLKEM_N / 8) - INVARIANT(ARRAY_ABS_BOUND(r->coeffs, 0, (8 * i - 1), 2)) // clang-format on - { - uint32_t t = load32_littleendian(buf + 4 * i); - uint32_t d = t & 0x55555555; - d += (t >> 1) & 0x55555555; +static void cbd2(poly *r, const uint8_t buf[2 * MLKEM_N / 4]) +{ + for (int i = 0; i < MLKEM_N / 8; i++) + __loop__( + invariant(i >= 0 && i <= MLKEM_N / 8) + invariant(array_abs_bound(r->coeffs, 0, (8 * i - 1), 2))) + { + uint32_t t = load32_littleendian(buf + 4 * i); + uint32_t d = t & 0x55555555; + d += (t >> 1) & 0x55555555; - for (int j = 0; j < 8; j++) // clang-format off - INVARIANT(i >= 0 && i <= MLKEM_N / 8 && j >= 0 && j <= 8) - INVARIANT(ARRAY_ABS_BOUND(r->coeffs, 0, 8 * i + j - 1, 2)) // clang-format on - { - const int16_t a = (d >> (4 * j + 0)) & 0x3; - const int16_t b = (d >> (4 * j + 2)) & 0x3; - r->coeffs[8 * i + j] = a - b; - } + for (int j = 0; j < 8; j++) + __loop__( + invariant(i >= 0 && i <= MLKEM_N / 8 && j >= 0 && j <= 8) + invariant(array_abs_bound(r->coeffs, 0, 8 * i + j - 1, 2))) + { + const int16_t a = (d >> (4 * j + 0)) & 0x3; + const int16_t b = (d >> (4 * j + 2)) & 0x3; + r->coeffs[8 * i + j] = a - b; } + } } /************************************************* @@ -86,29 +91,33 @@ static void cbd2(poly *r, const uint8_t buf[2 * MLKEM_N / 4]) { * - const uint8_t *buf: pointer to input byte array **************************************************/ #if MLKEM_ETA1 == 3 -static void cbd3(poly *r, const uint8_t buf[3 * MLKEM_N / 4]) { - for (int i = 0; i < MLKEM_N / 4; i++) // clang-format off - INVARIANT(i >= 0 && i <= MLKEM_N / 4) - INVARIANT(ARRAY_ABS_BOUND(r->coeffs, 0, (4 * i - 1), 3)) // clang-format on - { - const uint32_t t = load24_littleendian(buf + 3 * i); - uint32_t d = t & 0x00249249; - d += (t >> 1) & 0x00249249; - d += (t >> 2) & 0x00249249; +static void cbd3(poly *r, const uint8_t buf[3 * MLKEM_N / 4]) +{ + for (int i = 0; i < MLKEM_N / 4; i++) + __loop__( + invariant(i >= 0 && i <= MLKEM_N / 4) + invariant(array_abs_bound(r->coeffs, 0, (4 * i - 1), 3))) + { + const uint32_t t = load24_littleendian(buf + 3 * i); + uint32_t d = t & 0x00249249; + d += (t >> 1) & 0x00249249; + d += (t >> 2) & 0x00249249; - for (int j = 0; j < 4; j++) // clang-format off - INVARIANT(i >= 0 && i <= MLKEM_N / 4 && j >= 0 && j <= 4) - INVARIANT(ARRAY_ABS_BOUND(r->coeffs, 0, 4 * i + j - 1, 3)) // clang-format on - { - const int16_t a = (d >> (6 * j + 0)) & 0x7; - const int16_t b = (d >> (6 * j + 3)) & 0x7; - r->coeffs[4 * i + j] = a - b; - } + for (int j = 0; j < 4; j++) + __loop__( + invariant(i >= 0 && i <= MLKEM_N / 4 && j >= 0 && j <= 4) + invariant(array_abs_bound(r->coeffs, 0, 4 * i + j - 1, 3))) + { + const int16_t a = (d >> (6 * j + 0)) & 0x7; + const int16_t b = (d >> (6 * j + 3)) & 0x7; + r->coeffs[4 * i + j] = a - b; } + } } #endif -void poly_cbd_eta1(poly *r, const uint8_t buf[MLKEM_ETA1 * MLKEM_N / 4]) { +void poly_cbd_eta1(poly *r, const uint8_t buf[MLKEM_ETA1 * MLKEM_N / 4]) +{ #if MLKEM_ETA1 == 2 cbd2(r, buf); #elif MLKEM_ETA1 == 3 @@ -118,7 +127,8 @@ void poly_cbd_eta1(poly *r, const uint8_t buf[MLKEM_ETA1 * MLKEM_N / 4]) { #endif } -void poly_cbd_eta2(poly *r, const uint8_t buf[MLKEM_ETA2 * MLKEM_N / 4]) { +void poly_cbd_eta2(poly *r, const uint8_t buf[MLKEM_ETA2 * MLKEM_N / 4]) +{ #if MLKEM_ETA2 == 2 cbd2(r, buf); #else diff --git a/mlkem/cbd.h b/mlkem/cbd.h index 3b340c41b..6012ce910 100644 --- a/mlkem/cbd.h +++ b/mlkem/cbd.h @@ -18,14 +18,13 @@ * Arguments: - poly *r: pointer to output polynomial * - const uint8_t *buf: pointer to input byte array **************************************************/ - -void poly_cbd_eta1( - poly *r, const uint8_t buf[MLKEM_ETA1 * MLKEM_N / 4]) // clang-format off -REQUIRES(IS_FRESH(r, sizeof(poly))) -REQUIRES(IS_FRESH(buf, MLKEM_ETA1 * MLKEM_N / 4)) -ASSIGNS(OBJECT_UPTO(r, sizeof(poly))) -ENSURES(ARRAY_ABS_BOUND(r->coeffs, 0, MLKEM_N - 1, MLKEM_ETA1)); -// clang-format on +void poly_cbd_eta1(poly *r, const uint8_t buf[MLKEM_ETA1 * MLKEM_N / 4]) +__contract__( + requires(memory_no_alias(r, sizeof(poly))) + requires(memory_no_alias(buf, MLKEM_ETA1 * MLKEM_N / 4)) + assigns(memory_slice(r, sizeof(poly))) + ensures(array_abs_bound(r->coeffs, 0, MLKEM_N - 1, MLKEM_ETA1)) +); #define poly_cbd_eta2 MLKEM_NAMESPACE(poly_cbd_eta2) /************************************************* @@ -38,13 +37,12 @@ ENSURES(ARRAY_ABS_BOUND(r->coeffs, 0, MLKEM_N - 1, MLKEM_ETA1)); * Arguments: - poly *r: pointer to output polynomial * - const uint8_t *buf: pointer to input byte array **************************************************/ - -void poly_cbd_eta2( - poly *r, const uint8_t buf[MLKEM_ETA2 * MLKEM_N / 4]) // clang-format off -REQUIRES(IS_FRESH(r, sizeof(poly))) -REQUIRES(IS_FRESH(buf, MLKEM_ETA2 * MLKEM_N / 4)) -ASSIGNS(OBJECT_UPTO(r, sizeof(poly))) -ENSURES(ARRAY_ABS_BOUND(r->coeffs, 0, MLKEM_N - 1, MLKEM_ETA2)); -// clang-format on +void poly_cbd_eta2(poly *r, const uint8_t buf[MLKEM_ETA2 * MLKEM_N / 4]) +__contract__( + requires(memory_no_alias(r, sizeof(poly))) + requires(memory_no_alias(buf, MLKEM_ETA2 * MLKEM_N / 4)) + assigns(memory_slice(r, sizeof(poly))) + ensures(array_abs_bound(r->coeffs, 0, MLKEM_N - 1, MLKEM_ETA2)) +); #endif diff --git a/mlkem/cbmc.h b/mlkem/cbmc.h index 642636a24..af1c31bbd 100644 --- a/mlkem/cbmc.h +++ b/mlkem/cbmc.h @@ -12,14 +12,9 @@ #define STATIC_TESTABLE static #define STATIC_INLINE_TESTABLE static inline -// CBMC top-level contracts are replaced by "" for compilation -#define ASSIGNS(...) -#define REQUIRES(...) -#define ENSURES(...) -#define DECREASES(...) -#define INVARIANT(...) -#define ASSERT(...) -#define ASSUME(...) +#define __contract__(x) +#define __loop__(x) +#define cassert(x, y) #else // CBMC _is_ defined, therefore we're doing proof @@ -27,60 +22,47 @@ #define STATIC_TESTABLE #define STATIC_INLINE_TESTABLE +#define __contract__(x) x +#define __loop__(x) x // https://diffblue.github.io/cbmc/contracts-assigns.html -#define ASSIGNS(...) __CPROVER_assigns(__VA_ARGS__) +#define assigns(...) __CPROVER_assigns(__VA_ARGS__) // https://diffblue.github.io/cbmc/contracts-requires-ensures.html -#define REQUIRES(...) __CPROVER_requires(__VA_ARGS__) -#define ENSURES(...) __CPROVER_ensures(__VA_ARGS__) - -// note we drop "loop_" here since there are no other kind of invariants -// in CBMC. An "invariant" is _always_ a "loop invariant" so no need to -// keep that qualification +#define requires(...) __CPROVER_requires(__VA_ARGS__) +#define ensures(...) __CPROVER_ensures(__VA_ARGS__) // https://diffblue.github.io/cbmc/contracts-loops.html -#define INVARIANT(...) __CPROVER_loop_invariant(__VA_ARGS__) -#define DECREASES(...) __CPROVER_decreases(__VA_ARGS__) - -#define ASSERT(...) __CPROVER_assert(__VA_ARGS__) -#define ASSUME(...) __CPROVER_assume(__VA_ARGS__) - -#define READABLE(...) __CPROVER_r_ok(__VA_ARGS__) -#define WRITEABLE(...) __CPROVER_w_ok(__VA_ARGS__) +#define invariant(...) __CPROVER_loop_invariant(__VA_ARGS__) +#define decreases(...) __CPROVER_decreases(__VA_ARGS__) +// cassert to avoid confusion with in-built assert +#define cassert(...) __CPROVER_assert(__VA_ARGS__) +#define assume(...) __CPROVER_assume(__VA_ARGS__) /////////////////////////////////////////////////// // Macros for "expression" forms that may appear // _inside_ top-level contracts. /////////////////////////////////////////////////// -// function return value - useful inside ENSURES +// function return value - useful inside ensures // https://diffblue.github.io/cbmc/contracts-functions.html -#define RETURN_VALUE (__CPROVER_return_value) +#define return_value (__CPROVER_return_value) -// ASSIGNS l-value targets +// assigns l-value targets // https://diffblue.github.io/cbmc/contracts-assigns.html -#define TYPED_TARGET(...) __CPROVER_typed_target(__VA_ARGS__) -#define OBJECT_WHOLE(...) __CPROVER_object_whole(__VA_ARGS__) -#define OBJECT_FROM(...) __CPROVER_object_from(__VA_ARGS__) -#define OBJECT_UPTO(...) __CPROVER_object_upto(__VA_ARGS__) - -#define SAME_OBJECT(...) __CPROVER_same_object(__VA_ARGS__) +#define object_whole(...) __CPROVER_object_whole(__VA_ARGS__) +#define memory_slice(...) __CPROVER_object_upto(__VA_ARGS__) +#define same_object(...) __CPROVER_same_object(__VA_ARGS__) // Pointer-related predicates // https://diffblue.github.io/cbmc/contracts-memory-predicates.html -#define IS_FRESH(...) __CPROVER_is_fresh(__VA_ARGS__) -#define POINTER_IN_RANGE(...) __CPROVER_pointer_in_range_dfcc(__VA_ARGS__) -#define READABLE(...) __CPROVER_r_ok(__VA_ARGS__) -#define WRITEABLE(...) __CPROVER_w_ok(__VA_ARGS__) - -// Function pointer/contract establishment -// https://diffblue.github.io/cbmc/contracts-function-pointer-predicates.html -#define OBEYS_CONTRACT(...) __CPROVER_obeys_contract(__VA_ARGS__) +#define memory_no_alias(...) __CPROVER_is_fresh(__VA_ARGS__) +#define readable(...) __CPROVER_r_ok(__VA_ARGS__) +#define writeable(...) __CPROVER_w_ok(__VA_ARGS__) // History variables // https://diffblue.github.io/cbmc/contracts-history-variables.html -#define OLD(...) __CPROVER_old(__VA_ARGS__) -#define LOOP_ENTRY(...) __CPROVER_loop_entry(__VA_ARGS__) +#define old(...) __CPROVER_old(__VA_ARGS__) +#define loop_entry(...) __CPROVER_loop_entry(__VA_ARGS__) // Quantifiers // Note that the range on qvar is _inclusive_ between qvar_lb .. qvar_ub @@ -88,19 +70,20 @@ // Prevent clang-format from corrupting CBMC's special ==> operator // clang-format off -#define FORALL(type, qvar, qvar_lb, qvar_ub, predicate) \ - __CPROVER_forall \ - { \ - type qvar; \ - ((qvar_lb) <= (qvar) && (qvar) <= (qvar_ub)) ==> (predicate) \ +#define forall(type, qvar, qvar_lb, qvar_ub, predicate) \ + __CPROVER_forall \ + { \ + type qvar; \ + ((qvar_lb) <= (qvar) && (qvar) <= (qvar_ub)) ==> (predicate) \ } -// clang-format on #define EXISTS(type, qvar, qvar_lb, qvar_ub, predicate) \ - __CPROVER_exists { \ + __CPROVER_exists \ + { \ type qvar; \ ((qvar_lb) <= (qvar) && (qvar) <= (qvar_ub)) && (predicate) \ } +// clang-format on /////////////////////////////////////////////////// // Convenience macros for common contract patterns @@ -110,36 +93,34 @@ // range value_lb .. value_ub (inclusive)" // // Example: -// ARRAY_BOUND(a->coeffs, 0, MLKEM_N-1, -(MLKEM_Q - 1), MLKEM_Q - 1) +// array_bound(a->coeffs, 0, MLKEM_N-1, -(MLKEM_Q - 1), MLKEM_Q - 1) // expands to // __CPROVER_forall { int k; (0 <= k && k <= MLKEM_N-1) ==> ( (-(MLKEM_Q - // 1) <= a->coeffs[k]) && (a->coeffs[k] <= (MLKEM_Q - 1))) } // Prevent clang-format from corrupting CBMC's special ==> operator // clang-format off - #define CBMC_CONCAT_(left, right) left##right -#define CBMC_CONCAT(left, right) CBMC_CONCAT_(left,right) - -#define ARRAY_BOUND_CORE(indextype, qvar, qvar_lb, qvar_ub, array_var, \ - value_lb, value_ub) \ - __CPROVER_forall \ - { \ - indextype qvar; \ - ((qvar_lb) <= (qvar) && (qvar) <= (qvar_ub)) ==> \ - (((value_lb) <= (array_var[(qvar)])) && \ - ((array_var[(qvar)]) <= (value_ub))) \ +#define CBMC_CONCAT(left, right) CBMC_CONCAT_(left, right) + +#define array_bound_core(indextype, qvar, qvar_lb, qvar_ub, array_var, \ + value_lb, value_ub) \ + __CPROVER_forall \ + { \ + indextype qvar; \ + ((qvar_lb) <= (qvar) && (qvar) <= (qvar_ub)) ==> \ + (((value_lb) <= (array_var[(qvar)])) && \ + ((array_var[(qvar)]) <= (value_ub))) \ } -#define ARRAY_BOUND(array_var, qvar_lb, qvar_ub, \ - value_lb, value_ub) \ - ARRAY_BOUND_CORE(int, CBMC_CONCAT(_cbmc_idx,__LINE__), \ - (qvar_lb), (qvar_ub), (array_var), (value_lb), (value_ub)) +#define array_bound(array_var, qvar_lb, qvar_ub, value_lb, value_ub) \ + array_bound_core(int, CBMC_CONCAT(_cbmc_idx, __LINE__), (qvar_lb), \ + (qvar_ub), (array_var), (value_lb), (value_ub)) -// clang-format on -// Wrapper around ARRAY_BOUND operating on absolute values -#define ARRAY_ABS_BOUND(arr, lb, ub, k) \ - ARRAY_BOUND((arr), (lb), (ub), (-(k)), (k)) +// Wrapper around array_bound operating on absolute values +#define array_abs_bound(arr, lb, ub, k) \ + array_bound((arr), (lb), (ub), (-(k)), (k)) +// clang-format on #endif diff --git a/mlkem/debug/debug.c b/mlkem/debug/debug.c index 93c1e38cb..aaebef755 100644 --- a/mlkem/debug/debug.c +++ b/mlkem/debug/debug.c @@ -7,8 +7,10 @@ static char debug_buf[256]; void mlkem_debug_assert(const char *file, int line, const char *description, - const int val) { - if (val == 0) { + const int val) +{ + if (val == 0) + { snprintf(debug_buf, sizeof(debug_buf), "Assertion failed: %s (value %d)", description, val); mlkem_debug_print_error(file, line, debug_buf); @@ -18,12 +20,15 @@ void mlkem_debug_assert(const char *file, int line, const char *description, void mlkem_debug_check_bounds(const char *file, int line, const char *description, const int16_t *ptr, unsigned len, int lower_bound_exclusive, - int upper_bound_exclusive) { + int upper_bound_exclusive) +{ int err = 0; unsigned i; - for (i = 0; i < len; i++) { + for (i = 0; i < len; i++) + { int16_t val = ptr[i]; - if (!(val > lower_bound_exclusive && val < upper_bound_exclusive)) { + if (!(val > lower_bound_exclusive && val < upper_bound_exclusive)) + { snprintf(debug_buf, sizeof(debug_buf), "%s, index %u, value %d out of bounds (%d,%d)", description, i, (int)val, lower_bound_exclusive, upper_bound_exclusive); @@ -36,7 +41,8 @@ void mlkem_debug_check_bounds(const char *file, int line, exit(1); } -void mlkem_debug_print_error(const char *file, int line, const char *msg) { +void mlkem_debug_print_error(const char *file, int line, const char *msg) +{ fprintf(stderr, "[ERROR:%s:%04d] %s\n", file, line, msg); fflush(stderr); } diff --git a/mlkem/debug/debug.h b/mlkem/debug/debug.h index 76ebdd90a..6b0bcd275 100644 --- a/mlkem/debug/debug.h +++ b/mlkem/debug/debug.h @@ -57,7 +57,8 @@ void mlkem_debug_print_error(const char *file, int line, const char *msg); * Currently called CASSERT to avoid clash with CBMC assert. */ #define CASSERT(val, msg) \ - do { \ + do \ + { \ mlkem_debug_assert(__FILE__, __LINE__, (msg), (val)); \ } while (0) @@ -76,7 +77,8 @@ void mlkem_debug_print_error(const char *file, int line, const char *msg); * high_bound: Exclusive upper bound on absolute value to check * msg: Message to print on failure */ #define UBOUND(ptr, len, high_bound, msg) \ - do { \ + do \ + { \ mlkem_debug_check_bounds(__FILE__, __LINE__, (msg), (int16_t *)(ptr), \ (len), -1, ((high_bound))); \ } while (0) @@ -87,7 +89,8 @@ void mlkem_debug_print_error(const char *file, int line, const char *msg); * abs_bound: Exclusive upper bound on absolute value to check * msg: Message to print on failure */ #define BOUND(ptr, len, abs_bound, msg) \ - do { \ + do \ + { \ mlkem_debug_check_bounds(__FILE__, __LINE__, (msg), (int16_t *)(ptr), \ (len), -(abs_bound), (abs_bound)); \ } while (0) @@ -125,7 +128,8 @@ void mlkem_debug_print_error(const char *file, int line, const char *msg); * ptr: polyvec* or polyvec_mulcache* pointer to vector of polynomials to check * abs_bound: Exclusive upper bound on absolute value to check */ #define POLYVEC_BOUND(ptr, abs_bound) \ - do { \ + do \ + { \ for (unsigned _debug_polyvec_bound_idx = 0; \ _debug_polyvec_bound_idx < MLKEM_K; _debug_polyvec_bound_idx++) \ POLY_BOUND_MSG(&(ptr)->vec[_debug_polyvec_bound_idx], (abs_bound), \ @@ -137,7 +141,8 @@ void mlkem_debug_print_error(const char *file, int line, const char *msg); * ubound: Exclusive upper bound on value to check. Inclusive lower bound is 0. */ #define POLYVEC_UBOUND(ptr, ubound) \ - do { \ + do \ + { \ for (unsigned _debug_polyvec_bound_idx = 0; \ _debug_polyvec_bound_idx < MLKEM_K; _debug_polyvec_bound_idx++) \ POLY_UBOUND_MSG(&(ptr)->vec[_debug_polyvec_bound_idx], (ubound), \ @@ -146,7 +151,8 @@ void mlkem_debug_print_error(const char *file, int line, const char *msg); // Following AWS-LC to define a C99-compliant static assert #define MLKEM_STATIC_ASSERT_DEFINE(cond, msg) \ - typedef struct { \ + typedef struct \ + { \ unsigned int MLKEM_CONCAT(static_assertion_, msg) : (cond) ? 1 : -1; \ } MLKEM_CONCAT(static_assertion_, msg) __attribute__((unused)); @@ -163,34 +169,44 @@ void mlkem_debug_print_error(const char *file, int line, const char *msg); #else /* MLKEM_DEBUG */ #define CASSERT(...) \ - do { \ + do \ + { \ } while (0) #define SCALAR_BOUND(...) \ - do { \ + do \ + { \ } while (0) #define BOUND(...) \ - do { \ + do \ + { \ } while (0) #define POLY_BOUND(...) \ - do { \ + do \ + { \ } while (0) #define POLYVEC_BOUND(...) \ - do { \ + do \ + { \ } while (0) #define POLY_BOUND_MSG(...) \ - do { \ + do \ + { \ } while (0) #define UBOUND(...) \ - do { \ + do \ + { \ } while (0) #define POLY_UBOUND(...) \ - do { \ + do \ + { \ } while (0) #define POLYVEC_UBOUND(...) \ - do { \ + do \ + { \ } while (0) #define POLY_UBOUND_MSG(...) \ - do { \ + do \ + { \ } while (0) #define STATIC_ASSERT(...) diff --git a/mlkem/indcpa.c b/mlkem/indcpa.c index f1abd0e93..0c3f3f6af 100644 --- a/mlkem/indcpa.c +++ b/mlkem/indcpa.c @@ -33,7 +33,8 @@ * const uint8_t *seed: pointer to the input public seed **************************************************/ static void pack_pk(uint8_t r[MLKEM_INDCPA_PUBLICKEYBYTES], polyvec *pk, - const uint8_t seed[MLKEM_SYMBYTES]) { + const uint8_t seed[MLKEM_SYMBYTES]) +{ POLYVEC_BOUND(pk, MLKEM_Q); polyvec_tobytes(r, pk); memcpy(r + MLKEM_POLYVECBYTES, seed, MLKEM_SYMBYTES); @@ -52,7 +53,8 @@ static void pack_pk(uint8_t r[MLKEM_INDCPA_PUBLICKEYBYTES], polyvec *pk, * key. **************************************************/ static void unpack_pk(polyvec *pk, uint8_t seed[MLKEM_SYMBYTES], - const uint8_t packedpk[MLKEM_INDCPA_PUBLICKEYBYTES]) { + const uint8_t packedpk[MLKEM_INDCPA_PUBLICKEYBYTES]) +{ polyvec_frombytes(pk, packedpk); memcpy(seed, packedpk + MLKEM_POLYVECBYTES, MLKEM_SYMBYTES); @@ -71,7 +73,8 @@ static void unpack_pk(polyvec *pk, uint8_t seed[MLKEM_SYMBYTES], * - polyvec *sk: pointer to input vector of polynomials (secret *key) **************************************************/ -static void pack_sk(uint8_t r[MLKEM_INDCPA_SECRETKEYBYTES], polyvec *sk) { +static void pack_sk(uint8_t r[MLKEM_INDCPA_SECRETKEYBYTES], polyvec *sk) +{ POLYVEC_BOUND(sk, MLKEM_Q); polyvec_tobytes(r, sk); } @@ -87,7 +90,8 @@ static void pack_sk(uint8_t r[MLKEM_INDCPA_SECRETKEYBYTES], polyvec *sk) { *key **************************************************/ static void unpack_sk(polyvec *sk, - const uint8_t packedsk[MLKEM_INDCPA_SECRETKEYBYTES]) { + const uint8_t packedsk[MLKEM_INDCPA_SECRETKEYBYTES]) +{ polyvec_frombytes(sk, packedsk); polyvec_reduce(sk); } @@ -103,8 +107,8 @@ static void unpack_sk(polyvec *sk, * poly *pk: pointer to the input vector of polynomials b * poly *v: pointer to the input polynomial v **************************************************/ -static void pack_ciphertext(uint8_t r[MLKEM_INDCPA_BYTES], polyvec *b, - poly *v) { +static void pack_ciphertext(uint8_t r[MLKEM_INDCPA_BYTES], polyvec *b, poly *v) +{ polyvec_compress_du(r, b); poly_compress_dv(r + MLKEM_POLYVECCOMPRESSEDBYTES_DU, v); } @@ -120,7 +124,8 @@ static void pack_ciphertext(uint8_t r[MLKEM_INDCPA_BYTES], polyvec *b, * - const uint8_t *c: pointer to the input serialized ciphertext **************************************************/ static void unpack_ciphertext(polyvec *b, poly *v, - const uint8_t c[MLKEM_INDCPA_BYTES]) { + const uint8_t c[MLKEM_INDCPA_BYTES]) +{ polyvec_decompress_du(b, c); poly_decompress_dv(v, c + MLKEM_POLYVECCOMPRESSEDBYTES_DU); } @@ -133,19 +138,19 @@ static void unpack_ciphertext(polyvec *b, poly *v, // Generate four A matrix entries from a seed, using rejection // sampling on the output of a XOF. STATIC_TESTABLE -void gen_matrix_entry_x4(poly *vec, uint8_t *seed[4]) // clang-format off -REQUIRES(IS_FRESH(vec, sizeof(poly) * 4)) -REQUIRES(IS_FRESH(seed, sizeof(uint8_t*) * 4)) -REQUIRES(IS_FRESH(seed[0], MLKEM_SYMBYTES + 2)) -REQUIRES(IS_FRESH(seed[1], MLKEM_SYMBYTES + 2)) -REQUIRES(IS_FRESH(seed[2], MLKEM_SYMBYTES + 2)) -REQUIRES(IS_FRESH(seed[3], MLKEM_SYMBYTES + 2)) -ASSIGNS(OBJECT_UPTO(vec, sizeof(poly) * 4)) -ENSURES(ARRAY_BOUND(vec[0].coeffs, 0, MLKEM_N - 1, 0, (MLKEM_Q - 1))) -ENSURES(ARRAY_BOUND(vec[1].coeffs, 0, MLKEM_N - 1, 0, (MLKEM_Q - 1))) -ENSURES(ARRAY_BOUND(vec[2].coeffs, 0, MLKEM_N - 1, 0, (MLKEM_Q - 1))) -ENSURES(ARRAY_BOUND(vec[3].coeffs, 0, MLKEM_N - 1, 0, (MLKEM_Q - 1))) -// clang-format on +void gen_matrix_entry_x4(poly *vec, uint8_t *seed[4]) +__contract__( + requires(memory_no_alias(vec, sizeof(poly) * 4)) + requires(memory_no_alias(seed, sizeof(uint8_t*) * 4)) + requires(memory_no_alias(seed[0], MLKEM_SYMBYTES + 2)) + requires(memory_no_alias(seed[1], MLKEM_SYMBYTES + 2)) + requires(memory_no_alias(seed[2], MLKEM_SYMBYTES + 2)) + requires(memory_no_alias(seed[3], MLKEM_SYMBYTES + 2)) + assigns(memory_slice(vec, sizeof(poly) * 4)) + ensures(array_bound(vec[0].coeffs, 0, MLKEM_N - 1, 0, (MLKEM_Q - 1))) + ensures(array_bound(vec[1].coeffs, 0, MLKEM_N - 1, 0, (MLKEM_Q - 1))) + ensures(array_bound(vec[2].coeffs, 0, MLKEM_N - 1, 0, (MLKEM_Q - 1))) + ensures(array_bound(vec[3].coeffs, 0, MLKEM_N - 1, 0, (MLKEM_Q - 1)))) { // Temporary buffers for XOF output before rejection sampling uint8_t buf0[MLKEM_GEN_MATRIX_NBLOCKS * SHAKE128_RATE]; @@ -176,23 +181,23 @@ ENSURES(ARRAY_BOUND(vec[3].coeffs, 0, MLKEM_N - 1, 0, (MLKEM_Q - 1))) // one more block a time until we're done. buflen = SHAKE128_RATE; while (ctr[0] < MLKEM_N || ctr[1] < MLKEM_N || ctr[2] < MLKEM_N || - ctr[3] < MLKEM_N) // clang-format off - ASSIGNS(ctr, statex, OBJECT_UPTO(vec, sizeof(poly) * 4), OBJECT_WHOLE(buf0), - OBJECT_WHOLE(buf1), OBJECT_WHOLE(buf2), OBJECT_WHOLE(buf3)) - INVARIANT(ctr[0] <= MLKEM_N && ctr[1] <= MLKEM_N) - INVARIANT(ctr[2] <= MLKEM_N && ctr[3] <= MLKEM_N) - INVARIANT(ctr[0] > 0 ==> ARRAY_BOUND(vec[0].coeffs, 0, ctr[0] - 1, 0, (MLKEM_Q - 1))) - INVARIANT(ctr[1] > 0 ==> ARRAY_BOUND(vec[1].coeffs, 0, ctr[1] - 1, 0, (MLKEM_Q - 1))) - INVARIANT(ctr[2] > 0 ==> ARRAY_BOUND(vec[2].coeffs, 0, ctr[2] - 1, 0, (MLKEM_Q - 1))) - INVARIANT(ctr[3] > 0 ==> ARRAY_BOUND(vec[3].coeffs, 0, ctr[3] - 1, 0, (MLKEM_Q - 1))) - // clang-format on - { - shake128x4_squeezeblocks(buf0, buf1, buf2, buf3, 1, &statex); - ctr[0] = rej_uniform(vec[0].coeffs, MLKEM_N, ctr[0], buf0, buflen); - ctr[1] = rej_uniform(vec[1].coeffs, MLKEM_N, ctr[1], buf1, buflen); - ctr[2] = rej_uniform(vec[2].coeffs, MLKEM_N, ctr[2], buf2, buflen); - ctr[3] = rej_uniform(vec[3].coeffs, MLKEM_N, ctr[3], buf3, buflen); - } + ctr[3] < MLKEM_N) + __loop__( + assigns(ctr, statex, memory_slice(vec, sizeof(poly) * 4), object_whole(buf0), + object_whole(buf1), object_whole(buf2), object_whole(buf3)) + invariant(ctr[0] <= MLKEM_N && ctr[1] <= MLKEM_N) + invariant(ctr[2] <= MLKEM_N && ctr[3] <= MLKEM_N) + invariant(ctr[0] > 0 ==> array_bound(vec[0].coeffs, 0, ctr[0] - 1, 0, (MLKEM_Q - 1))) + invariant(ctr[1] > 0 ==> array_bound(vec[1].coeffs, 0, ctr[1] - 1, 0, (MLKEM_Q - 1))) + invariant(ctr[2] > 0 ==> array_bound(vec[2].coeffs, 0, ctr[2] - 1, 0, (MLKEM_Q - 1))) + invariant(ctr[3] > 0 ==> array_bound(vec[3].coeffs, 0, ctr[3] - 1, 0, (MLKEM_Q - 1)))) + { + shake128x4_squeezeblocks(buf0, buf1, buf2, buf3, 1, &statex); + ctr[0] = rej_uniform(vec[0].coeffs, MLKEM_N, ctr[0], buf0, buflen); + ctr[1] = rej_uniform(vec[1].coeffs, MLKEM_N, ctr[1], buf1, buflen); + ctr[2] = rej_uniform(vec[2].coeffs, MLKEM_N, ctr[2], buf2, buflen); + ctr[3] = rej_uniform(vec[3].coeffs, MLKEM_N, ctr[3], buf3, buflen); + } shake128x4_ctx_release(&statex); } @@ -200,13 +205,13 @@ ENSURES(ARRAY_BOUND(vec[3].coeffs, 0, MLKEM_N - 1, 0, (MLKEM_Q - 1))) // Generate a single A matrix entry from a seed, using rejection // sampling on the output of a XOF. STATIC_TESTABLE -void gen_matrix_entry(poly *entry, - uint8_t seed[MLKEM_SYMBYTES + 2]) // clang-format off -REQUIRES(IS_FRESH(entry, sizeof(poly))) -REQUIRES(IS_FRESH(seed, MLKEM_SYMBYTES + 2)) -ASSIGNS(OBJECT_UPTO(entry, sizeof(poly))) -ENSURES(ARRAY_BOUND(entry->coeffs, 0, MLKEM_N - 1, 0, (MLKEM_Q - 1))) -{ // clang-format on +void gen_matrix_entry(poly *entry, uint8_t seed[MLKEM_SYMBYTES + 2]) +__contract__( + requires(memory_no_alias(entry, sizeof(poly))) + requires(memory_no_alias(seed, MLKEM_SYMBYTES + 2)) + assigns(memory_slice(entry, sizeof(poly))) + ensures(array_bound(entry->coeffs, 0, MLKEM_N - 1, 0, (MLKEM_Q - 1)))) +{ shake128ctx state; uint8_t buf[MLKEM_GEN_MATRIX_NBLOCKS * SHAKE128_RATE]; unsigned int ctr, buflen; @@ -221,15 +226,16 @@ ENSURES(ARRAY_BOUND(entry->coeffs, 0, MLKEM_N - 1, 0, (MLKEM_Q - 1))) // Squeeze + sample one more block a time until we're done buflen = SHAKE128_RATE; - while (ctr < MLKEM_N) // clang-format off - ASSIGNS(ctr, state, OBJECT_UPTO(entry, sizeof(poly)), OBJECT_WHOLE(buf)) - INVARIANT(0 <= ctr && ctr <= MLKEM_N) - INVARIANT(ctr > 0 ==> ARRAY_BOUND(entry->coeffs, 0, ctr - 1, - 0, (MLKEM_Q - 1))) // clang-format on - { - shake128_squeezeblocks(buf, 1, &state); - ctr = rej_uniform(entry->coeffs, MLKEM_N, ctr, buf, SHAKE128_RATE); - } + while (ctr < MLKEM_N) + __loop__( + assigns(ctr, state, memory_slice(entry, sizeof(poly)), object_whole(buf)) + invariant(0 <= ctr && ctr <= MLKEM_N) + invariant(ctr > 0 ==> array_bound(entry->coeffs, 0, ctr - 1, + 0, (MLKEM_Q - 1)))) + { + shake128_squeezeblocks(buf, 1, &state); + ctr = rej_uniform(entry->coeffs, MLKEM_N, ctr, buf, SHAKE128_RATE); + } shake128_ctx_release(&state); } @@ -247,8 +253,8 @@ ENSURES(ARRAY_BOUND(entry->coeffs, 0, MLKEM_N - 1, 0, (MLKEM_Q - 1))) * - int transposed: boolean deciding whether A or A^T is generated **************************************************/ // Not static for benchmarking -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) +{ int i; // We generate four separate seed arrays rather than a single one to work // around limitations in CBMC function contracts dealing with disjoint slices @@ -259,7 +265,8 @@ void gen_matrix(polyvec *a, const uint8_t seed[MLKEM_SYMBYTES], ALIGN uint8_t seed3[MLKEM_SYMBYTES + 2]; uint8_t *seedxy[] = {seed0, seed1, seed2, seed3}; - for (unsigned j = 0; j < KECCAK_WAY; j++) { + for (unsigned j = 0; j < KECCAK_WAY; j++) + { memcpy(seedxy[j], seed, MLKEM_SYMBYTES); } @@ -269,16 +276,21 @@ void gen_matrix(polyvec *a, const uint8_t seed[MLKEM_SYMBYTES], // Either add suitable pragmas, or split gen_matrix according to MLKEM_K // and unroll by hand. for (i = 0; i < (MLKEM_K * MLKEM_K / KECCAK_WAY) * KECCAK_WAY; - i += KECCAK_WAY) { + i += KECCAK_WAY) + { uint8_t x, y; - for (unsigned int j = 0; j < KECCAK_WAY; j++) { + for (unsigned int j = 0; j < KECCAK_WAY; j++) + { x = (i + j) / MLKEM_K; y = (i + j) % MLKEM_K; - if (transposed) { + if (transposed) + { seedxy[j][MLKEM_SYMBYTES + 0] = x; seedxy[j][MLKEM_SYMBYTES + 1] = y; - } else { + } + else + { seedxy[j][MLKEM_SYMBYTES + 0] = y; seedxy[j][MLKEM_SYMBYTES + 1] = x; } @@ -290,15 +302,19 @@ void gen_matrix(polyvec *a, const uint8_t seed[MLKEM_SYMBYTES], } // For left over polynomial, we use single keccak. - if (i < MLKEM_K * MLKEM_K) { + if (i < MLKEM_K * MLKEM_K) + { uint8_t x, y; x = i / MLKEM_K; y = i % MLKEM_K; - if (transposed) { + if (transposed) + { seed0[MLKEM_SYMBYTES + 0] = x; seed0[MLKEM_SYMBYTES + 1] = y; - } else { + } + else + { seed0[MLKEM_SYMBYTES + 0] = y; seed0[MLKEM_SYMBYTES + 1] = x; } @@ -307,13 +323,16 @@ void gen_matrix(polyvec *a, const uint8_t seed[MLKEM_SYMBYTES], i++; } - ASSERT(i == MLKEM_K * MLKEM_K, "gen_matrix: failed to generate whole matrix"); + cassert(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. - for (i = 0; i < MLKEM_K; i++) { - for (int j = 0; j < MLKEM_K; j++) { + for (i = 0; i < MLKEM_K; i++) + { + for (int j = 0; j < MLKEM_K; j++) + { poly_permute_bitrev_to_custom(&a[i].vec[j]); } } @@ -335,23 +354,24 @@ void gen_matrix(polyvec *a, const uint8_t seed[MLKEM_SYMBYTES], **************************************************/ STATIC_TESTABLE void matvec_mul(polyvec *out, const polyvec a[MLKEM_K], const polyvec *v, - const polyvec_mulcache *vc) // clang-format off -REQUIRES(IS_FRESH(out, sizeof(polyvec))) -REQUIRES(IS_FRESH(a, sizeof(polyvec) * MLKEM_K)) -REQUIRES(IS_FRESH(v, sizeof(polyvec))) -REQUIRES(IS_FRESH(vc, sizeof(polyvec_mulcache))) -REQUIRES(FORALL(int, k0, 0, MLKEM_K - 1, - FORALL(int, k1, 0, MLKEM_K - 1, - ARRAY_ABS_BOUND(a[k0].vec[k1].coeffs, 0, MLKEM_N - 1, (MLKEM_Q - 1))))) -ASSIGNS(OBJECT_WHOLE(out)) -// clang-format on + const polyvec_mulcache *vc) +__contract__( + requires(memory_no_alias(out, sizeof(polyvec))) + requires(memory_no_alias(a, sizeof(polyvec) * MLKEM_K)) + requires(memory_no_alias(v, sizeof(polyvec))) + requires(memory_no_alias(vc, sizeof(polyvec_mulcache))) + requires(forall(int, k0, 0, MLKEM_K - 1, + forall(int, k1, 0, MLKEM_K - 1, + array_abs_bound(a[k0].vec[k1].coeffs, 0, MLKEM_N - 1, (MLKEM_Q - 1))))) + assigns(object_whole(out))) { - for (int i = 0; i < MLKEM_K; i++) // clang-format off - ASSIGNS(i, OBJECT_WHOLE(out)) - INVARIANT(i >= 0 && i <= MLKEM_K) // clang-format on - { - polyvec_basemul_acc_montgomery_cached(&out->vec[i], &a[i], v, vc); - } + for (int i = 0; i < MLKEM_K; i++) + __loop__( + assigns(i, object_whole(out)) + invariant(i >= 0 && i <= MLKEM_K)) + { + polyvec_basemul_acc_montgomery_cached(&out->vec[i], &a[i], v, vc); + } } /************************************************* @@ -372,7 +392,8 @@ STATIC_ASSERT(NTT_BOUND + MLKEM_Q < INT16_MAX, indcpa_enc_bound_0) void indcpa_keypair_derand(uint8_t pk[MLKEM_INDCPA_PUBLICKEYBYTES], uint8_t sk[MLKEM_INDCPA_SECRETKEYBYTES], - const uint8_t coins[MLKEM_SYMBYTES]) { + const uint8_t coins[MLKEM_SYMBYTES]) +{ ALIGN uint8_t buf[2 * MLKEM_SYMBYTES]; const uint8_t *publicseed = buf; const uint8_t *noiseseed = buf + MLKEM_SYMBYTES; @@ -448,7 +469,8 @@ STATIC_ASSERT(INVNTT_BOUND + MLKEM_ETA2 + MLKEM_Q < INT16_MAX, void indcpa_enc(uint8_t c[MLKEM_INDCPA_BYTES], const uint8_t m[MLKEM_INDCPA_MSGBYTES], const uint8_t pk[MLKEM_INDCPA_PUBLICKEYBYTES], - const uint8_t coins[MLKEM_SYMBYTES]) { + const uint8_t coins[MLKEM_SYMBYTES]) +{ ALIGN uint8_t seed[MLKEM_SYMBYTES]; polyvec sp, pkpv, ep, at[MLKEM_K], b; poly v, k, epp; @@ -503,7 +525,8 @@ STATIC_ASSERT(INVNTT_BOUND + MLKEM_Q < INT16_MAX, indcpa_dec_bound_0) void indcpa_dec(uint8_t m[MLKEM_INDCPA_MSGBYTES], const uint8_t c[MLKEM_INDCPA_BYTES], - const uint8_t sk[MLKEM_INDCPA_SECRETKEYBYTES]) { + const uint8_t sk[MLKEM_INDCPA_SECRETKEYBYTES]) +{ polyvec b, skpv; poly v, sb; diff --git a/mlkem/indcpa.h b/mlkem/indcpa.h index c72799196..16e165ab6 100644 --- a/mlkem/indcpa.h +++ b/mlkem/indcpa.h @@ -11,27 +11,27 @@ #define gen_matrix MLKEM_NAMESPACE(gen_matrix) -void gen_matrix(polyvec *a, const uint8_t seed[MLKEM_SYMBYTES], - int transposed) // clang-format off -REQUIRES(IS_FRESH(a, sizeof(polyvec) * MLKEM_K)) -REQUIRES(IS_FRESH(seed, MLKEM_SYMBYTES)) -REQUIRES(transposed == 0 || transposed == 1) -ASSIGNS(OBJECT_WHOLE(a)) -ENSURES(FORALL(int, x, 0, MLKEM_K - 1, FORALL(int, y, 0, MLKEM_K - 1, - ARRAY_BOUND(a[x].vec[y].coeffs, 0, MLKEM_N - 1, 0, (MLKEM_Q - 1))))); -// clang-format on +void gen_matrix(polyvec *a, const uint8_t seed[MLKEM_SYMBYTES], int transposed) +__contract__( + requires(memory_no_alias(a, sizeof(polyvec) * MLKEM_K)) + requires(memory_no_alias(seed, MLKEM_SYMBYTES)) + requires(transposed == 0 || transposed == 1) + assigns(object_whole(a)) + ensures(forall(int, x, 0, MLKEM_K - 1, forall(int, y, 0, MLKEM_K - 1, + array_bound(a[x].vec[y].coeffs, 0, MLKEM_N - 1, 0, (MLKEM_Q - 1))))); +); #define indcpa_keypair_derand MLKEM_NAMESPACE(indcpa_keypair_derand) -void indcpa_keypair_derand( - uint8_t pk[MLKEM_INDCPA_PUBLICKEYBYTES], - uint8_t sk[MLKEM_INDCPA_SECRETKEYBYTES], - const uint8_t coins[MLKEM_SYMBYTES]) // clang-format off -REQUIRES(IS_FRESH(pk, MLKEM_INDCPA_PUBLICKEYBYTES)) -REQUIRES(IS_FRESH(sk, MLKEM_INDCPA_SECRETKEYBYTES)) -REQUIRES(IS_FRESH(coins, MLKEM_SYMBYTES)) -ASSIGNS(OBJECT_WHOLE(pk)) -ASSIGNS(OBJECT_WHOLE(sk)); -// clang-format on +void indcpa_keypair_derand(uint8_t pk[MLKEM_INDCPA_PUBLICKEYBYTES], + uint8_t sk[MLKEM_INDCPA_SECRETKEYBYTES], + const uint8_t coins[MLKEM_SYMBYTES]) +__contract__( + requires(memory_no_alias(pk, MLKEM_INDCPA_PUBLICKEYBYTES)) + requires(memory_no_alias(sk, MLKEM_INDCPA_SECRETKEYBYTES)) + requires(memory_no_alias(coins, MLKEM_SYMBYTES)) + assigns(object_whole(pk)) + assigns(object_whole(sk)) +); #define indcpa_enc MLKEM_NAMESPACE(indcpa_enc) /************************************************* @@ -50,22 +50,24 @@ ASSIGNS(OBJECT_WHOLE(sk)); void indcpa_enc(uint8_t c[MLKEM_INDCPA_BYTES], const uint8_t m[MLKEM_INDCPA_MSGBYTES], const uint8_t pk[MLKEM_INDCPA_PUBLICKEYBYTES], - const uint8_t coins[MLKEM_SYMBYTES]) // clang-format off -REQUIRES(IS_FRESH(c, MLKEM_INDCPA_BYTES)) -REQUIRES(IS_FRESH(m, MLKEM_INDCPA_MSGBYTES)) -REQUIRES(IS_FRESH(pk, MLKEM_INDCPA_PUBLICKEYBYTES)) -REQUIRES(IS_FRESH(coins, MLKEM_SYMBYTES)) -ASSIGNS(OBJECT_WHOLE(c)); -// clang-format on + const uint8_t coins[MLKEM_SYMBYTES]) +__contract__( + requires(memory_no_alias(c, MLKEM_INDCPA_BYTES)) + requires(memory_no_alias(m, MLKEM_INDCPA_MSGBYTES)) + requires(memory_no_alias(pk, MLKEM_INDCPA_PUBLICKEYBYTES)) + requires(memory_no_alias(coins, MLKEM_SYMBYTES)) + assigns(object_whole(c)) +); #define indcpa_dec MLKEM_NAMESPACE(indcpa_dec) -void indcpa_dec( - uint8_t m[MLKEM_INDCPA_MSGBYTES], const uint8_t c[MLKEM_INDCPA_BYTES], - const uint8_t sk[MLKEM_INDCPA_SECRETKEYBYTES]) // clang-format off -REQUIRES(IS_FRESH(c, MLKEM_INDCPA_BYTES)) -REQUIRES(IS_FRESH(m, MLKEM_INDCPA_MSGBYTES)) -REQUIRES(IS_FRESH(sk, MLKEM_INDCPA_SECRETKEYBYTES)) -ASSIGNS(OBJECT_WHOLE(m)); -// clang-format on +void indcpa_dec(uint8_t m[MLKEM_INDCPA_MSGBYTES], + const uint8_t c[MLKEM_INDCPA_BYTES], + const uint8_t sk[MLKEM_INDCPA_SECRETKEYBYTES]) +__contract__( + requires(memory_no_alias(c, MLKEM_INDCPA_BYTES)) + requires(memory_no_alias(m, MLKEM_INDCPA_MSGBYTES)) + requires(memory_no_alias(sk, MLKEM_INDCPA_SECRETKEYBYTES)) + assigns(object_whole(m)) +); #endif diff --git a/mlkem/kem.c b/mlkem/kem.c index 00cd9d133..780eac8b9 100644 --- a/mlkem/kem.c +++ b/mlkem/kem.c @@ -12,10 +12,11 @@ #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 +int memcmp(const void *str1, const void *str2, size_t n) +__contract__( + requires(memory_no_alias(str1, n)) + requires(memory_no_alias(str2, n)) +); #endif /************************************************* @@ -30,14 +31,16 @@ REQUIRES(IS_FRESH(str2, n)); ** * Returns 0 on success, and -1 on failure **************************************************/ -static int check_pk(const uint8_t pk[MLKEM_PUBLICKEYBYTES]) { +static int check_pk(const uint8_t pk[MLKEM_PUBLICKEYBYTES]) +{ polyvec p; uint8_t p_reencoded[MLKEM_POLYVECBYTES]; polyvec_frombytes(&p, pk); polyvec_reduce(&p); polyvec_tobytes(p_reencoded, &p); // Data is public, so a variable-time memcmp() is OK - if (memcmp(pk, p_reencoded, MLKEM_POLYVECBYTES)) { + if (memcmp(pk, p_reencoded, MLKEM_POLYVECBYTES)) + { return -1; } return 0; @@ -56,14 +59,16 @@ static int check_pk(const uint8_t pk[MLKEM_PUBLICKEYBYTES]) { * * Returns 0 on success, and -1 on failure **************************************************/ -static int check_sk(const uint8_t sk[MLKEM_SECRETKEYBYTES]) { +static int check_sk(const uint8_t sk[MLKEM_SECRETKEYBYTES]) +{ uint8_t test[MLKEM_SYMBYTES]; // The parts of `sk` being hashed and compared here are public, so // no public information is leaked through the runtime or the return value // of this function. hash_h(test, sk + MLKEM_INDCPA_SECRETKEYBYTES, MLKEM_PUBLICKEYBYTES); if (memcmp(sk + MLKEM_SECRETKEYBYTES - 2 * MLKEM_SYMBYTES, test, - MLKEM_SYMBYTES)) { + MLKEM_SYMBYTES)) + { return -1; } return 0; @@ -85,7 +90,8 @@ static int check_sk(const uint8_t sk[MLKEM_SECRETKEYBYTES]) { ** * Returns 0 (success) **************************************************/ -int crypto_kem_keypair_derand(uint8_t *pk, uint8_t *sk, const uint8_t *coins) { +int crypto_kem_keypair_derand(uint8_t *pk, uint8_t *sk, const uint8_t *coins) +{ indcpa_keypair_derand(pk, sk, coins); memcpy(sk + MLKEM_INDCPA_SECRETKEYBYTES, pk, MLKEM_PUBLICKEYBYTES); hash_h(sk + MLKEM_SECRETKEYBYTES - 2 * MLKEM_SYMBYTES, pk, @@ -96,7 +102,8 @@ int crypto_kem_keypair_derand(uint8_t *pk, uint8_t *sk, const uint8_t *coins) { return 0; } -int crypto_kem_keypair(uint8_t *pk, uint8_t *sk) { +int crypto_kem_keypair(uint8_t *pk, uint8_t *sk) +{ ALIGN uint8_t coins[2 * MLKEM_SYMBYTES]; randombytes(coins, 2 * MLKEM_SYMBYTES); crypto_kem_keypair_derand(pk, sk, coins); @@ -104,12 +111,14 @@ int crypto_kem_keypair(uint8_t *pk, uint8_t *sk) { } int crypto_kem_enc_derand(uint8_t *ct, uint8_t *ss, const uint8_t *pk, - const uint8_t *coins) { + const uint8_t *coins) +{ ALIGN uint8_t buf[2 * MLKEM_SYMBYTES]; /* Will contain key, coins */ ALIGN uint8_t kr[2 * MLKEM_SYMBYTES]; - if (check_pk(pk)) { + if (check_pk(pk)) + { return -1; } @@ -126,13 +135,15 @@ int crypto_kem_enc_derand(uint8_t *ct, uint8_t *ss, const uint8_t *pk, return 0; } -int crypto_kem_enc(uint8_t *ct, uint8_t *ss, const uint8_t *pk) { +int crypto_kem_enc(uint8_t *ct, uint8_t *ss, const uint8_t *pk) +{ ALIGN uint8_t coins[MLKEM_SYMBYTES]; randombytes(coins, MLKEM_SYMBYTES); return crypto_kem_enc_derand(ct, ss, pk, coins); } -int crypto_kem_dec(uint8_t *ss, const uint8_t *ct, const uint8_t *sk) { +int crypto_kem_dec(uint8_t *ss, const uint8_t *ct, const uint8_t *sk) +{ int fail; ALIGN uint8_t buf[2 * MLKEM_SYMBYTES]; /* Will contain key, coins */ @@ -140,7 +151,8 @@ int crypto_kem_dec(uint8_t *ss, const uint8_t *ct, const uint8_t *sk) { ALIGN uint8_t cmp[MLKEM_CIPHERTEXTBYTES + MLKEM_SYMBYTES]; const uint8_t *pk = sk + MLKEM_INDCPA_SECRETKEYBYTES; - if (check_sk(sk)) { + if (check_sk(sk)) + { return -1; } diff --git a/mlkem/kem.h b/mlkem/kem.h index 18c400b3d..e82b88e85 100644 --- a/mlkem/kem.h +++ b/mlkem/kem.h @@ -21,14 +21,14 @@ #endif #define crypto_kem_keypair_derand MLKEM_NAMESPACE(keypair_derand) -int crypto_kem_keypair_derand(uint8_t *pk, uint8_t *sk, - const uint8_t *coins) // clang-format off -REQUIRES(IS_FRESH(pk, MLKEM_PUBLICKEYBYTES)) -REQUIRES(IS_FRESH(sk, MLKEM_SECRETKEYBYTES)) -REQUIRES(IS_FRESH(coins, 2 * MLKEM_SYMBYTES)) -ASSIGNS(OBJECT_WHOLE(pk)) -ASSIGNS(OBJECT_WHOLE(sk)); -// clang-format on +int crypto_kem_keypair_derand(uint8_t *pk, uint8_t *sk, const uint8_t *coins) +__contract__( + requires(memory_no_alias(pk, MLKEM_PUBLICKEYBYTES)) + requires(memory_no_alias(sk, MLKEM_SECRETKEYBYTES)) + requires(memory_no_alias(coins, 2 * MLKEM_SYMBYTES)) + assigns(object_whole(pk)) + assigns(object_whole(sk)) +); #define crypto_kem_keypair MLKEM_NAMESPACE(keypair) /************************************************* @@ -44,12 +44,13 @@ ASSIGNS(OBJECT_WHOLE(sk)); * * 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 +int crypto_kem_keypair(uint8_t *pk, uint8_t *sk) +__contract__( + requires(memory_no_alias(pk, MLKEM_PUBLICKEYBYTES)) + requires(memory_no_alias(sk, MLKEM_SECRETKEYBYTES)) + assigns(object_whole(pk)) + assigns(object_whole(sk)) +); #define crypto_kem_enc_derand MLKEM_NAMESPACE(enc_derand) /************************************************* @@ -72,14 +73,15 @@ ASSIGNS(OBJECT_WHOLE(sk)); * of FIPS203) fails. **************************************************/ int crypto_kem_enc_derand(uint8_t *ct, uint8_t *ss, const uint8_t *pk, - const uint8_t *coins) // clang-format off -REQUIRES(IS_FRESH(ct, MLKEM_CIPHERTEXTBYTES)) -REQUIRES(IS_FRESH(ss, MLKEM_SSBYTES)) -REQUIRES(IS_FRESH(pk, MLKEM_PUBLICKEYBYTES)) -REQUIRES(IS_FRESH(coins, MLKEM_SYMBYTES)) -ASSIGNS(OBJECT_WHOLE(ct)) -ASSIGNS(OBJECT_WHOLE(ss)); -// clang-format on + const uint8_t *coins) +__contract__( + requires(memory_no_alias(ct, MLKEM_CIPHERTEXTBYTES)) + requires(memory_no_alias(ss, MLKEM_SSBYTES)) + requires(memory_no_alias(pk, MLKEM_PUBLICKEYBYTES)) + requires(memory_no_alias(coins, MLKEM_SYMBYTES)) + assigns(object_whole(ct)) + assigns(object_whole(ss)) +); #define crypto_kem_enc MLKEM_NAMESPACE(enc) /************************************************* @@ -98,14 +100,14 @@ ASSIGNS(OBJECT_WHOLE(ss)); * Returns 0 on success, and -1 if the public key modulus check (see Section 7.2 * of FIPS203) fails. **************************************************/ -int crypto_kem_enc(uint8_t *ct, uint8_t *ss, - const uint8_t *pk) // clang-format off -REQUIRES(IS_FRESH(ct, MLKEM_CIPHERTEXTBYTES)) -REQUIRES(IS_FRESH(ss, MLKEM_SSBYTES)) -REQUIRES(IS_FRESH(pk, MLKEM_PUBLICKEYBYTES)) -ASSIGNS(OBJECT_WHOLE(ct)) -ASSIGNS(OBJECT_WHOLE(ss)); -// clang-format on +int crypto_kem_enc(uint8_t *ct, uint8_t *ss, const uint8_t *pk) +__contract__( + requires(memory_no_alias(ct, MLKEM_CIPHERTEXTBYTES)) + requires(memory_no_alias(ss, MLKEM_SSBYTES)) + requires(memory_no_alias(pk, MLKEM_PUBLICKEYBYTES)) + assigns(object_whole(ct)) + assigns(object_whole(ss)) +); #define crypto_kem_dec MLKEM_NAMESPACE(dec) /************************************************* @@ -126,12 +128,12 @@ ASSIGNS(OBJECT_WHOLE(ss)); * * On failure, ss will contain a pseudo-random value. **************************************************/ -int crypto_kem_dec(uint8_t *ss, const uint8_t *ct, - const uint8_t *sk) // clang-format off -REQUIRES(IS_FRESH(ss, MLKEM_SSBYTES)) -REQUIRES(IS_FRESH(ct, MLKEM_CIPHERTEXTBYTES)) -REQUIRES(IS_FRESH(sk, MLKEM_SECRETKEYBYTES)) -ASSIGNS(OBJECT_WHOLE(ss)); -// clang-format on +int crypto_kem_dec(uint8_t *ss, const uint8_t *ct, const uint8_t *sk) +__contract__( + requires(memory_no_alias(ss, MLKEM_SSBYTES)) + requires(memory_no_alias(ct, MLKEM_CIPHERTEXTBYTES)) + requires(memory_no_alias(sk, MLKEM_SECRETKEYBYTES)) + assigns(object_whole(ss)) +); #endif diff --git a/mlkem/native/aarch64/profiles/clean.h b/mlkem/native/aarch64/profiles/clean.h index e0fbdeb54..c512ad913 100644 --- a/mlkem/native/aarch64/profiles/clean.h +++ b/mlkem/native/aarch64/profiles/clean.h @@ -21,45 +21,53 @@ #define MLKEM_USE_NATIVE_REJ_UNIFORM #define NTT_BOUND_NATIVE (6 * MLKEM_Q) -static inline void ntt_native(poly *data) { +static inline void ntt_native(poly *data) +{ ntt_asm_clean(data->coeffs, aarch64_ntt_zetas_layer01234, aarch64_ntt_zetas_layer56); } #define INVNTT_BOUND_NATIVE (8 * MLKEM_Q) -static inline void intt_native(poly *data) { +static inline void intt_native(poly *data) +{ intt_asm_clean(data->coeffs, aarch64_invntt_zetas_layer01234, aarch64_invntt_zetas_layer56); } -static inline void poly_reduce_native(poly *data) { +static inline void poly_reduce_native(poly *data) +{ poly_reduce_asm_clean(data->coeffs); } -static inline void poly_tomont_native(poly *data) { +static inline void poly_tomont_native(poly *data) +{ poly_tomont_asm_clean(data->coeffs); } -static inline void poly_mulcache_compute_native(poly_mulcache *x, - const poly *y) { +static inline void poly_mulcache_compute_native(poly_mulcache *x, const poly *y) +{ poly_mulcache_compute_asm_clean(x->coeffs, y->coeffs, aarch64_zetas_mulcache_native, aarch64_zetas_mulcache_twisted_native); } static inline void polyvec_basemul_acc_montgomery_cached_native( poly *r, const polyvec *a, const polyvec *b, - const polyvec_mulcache *b_cache) { + const polyvec_mulcache *b_cache) +{ polyvec_basemul_acc_montgomery_cached_asm_clean( r->coeffs, a->vec[0].coeffs, b->vec[0].coeffs, b_cache->vec[0].coeffs); } static inline void poly_tobytes_native(uint8_t r[MLKEM_POLYBYTES], - const poly *a) { + const poly *a) +{ poly_tobytes_asm_clean(r, a->coeffs); } static inline int rej_uniform_native(int16_t *r, unsigned int len, - const uint8_t *buf, unsigned int buflen) { - if (len != MLKEM_N || buflen % 24 != 0) { + const uint8_t *buf, unsigned int buflen) +{ + if (len != MLKEM_N || buflen % 24 != 0) + { return -1; } return (int)rej_uniform_asm_clean(r, buf, buflen); diff --git a/mlkem/native/aarch64/profiles/opt.h b/mlkem/native/aarch64/profiles/opt.h index 330cff1b7..efec4fc36 100644 --- a/mlkem/native/aarch64/profiles/opt.h +++ b/mlkem/native/aarch64/profiles/opt.h @@ -21,45 +21,53 @@ #define MLKEM_USE_NATIVE_REJ_UNIFORM #define NTT_BOUND_NATIVE (6 * MLKEM_Q) -static inline void ntt_native(poly *data) { +static inline void ntt_native(poly *data) +{ ntt_asm_opt(data->coeffs, aarch64_ntt_zetas_layer01234, aarch64_ntt_zetas_layer56); } #define INVNTT_BOUND_NATIVE (8 * MLKEM_Q) -static inline void intt_native(poly *data) { +static inline void intt_native(poly *data) +{ intt_asm_opt(data->coeffs, aarch64_invntt_zetas_layer01234, aarch64_invntt_zetas_layer56); } -static inline void poly_reduce_native(poly *data) { +static inline void poly_reduce_native(poly *data) +{ poly_reduce_asm_opt(data->coeffs); } -static inline void poly_tomont_native(poly *data) { +static inline void poly_tomont_native(poly *data) +{ poly_tomont_asm_opt(data->coeffs); } -static inline void poly_mulcache_compute_native(poly_mulcache *x, - const poly *y) { +static inline void poly_mulcache_compute_native(poly_mulcache *x, const poly *y) +{ poly_mulcache_compute_asm_opt(x->coeffs, y->coeffs, aarch64_zetas_mulcache_native, aarch64_zetas_mulcache_twisted_native); } static inline void polyvec_basemul_acc_montgomery_cached_native( poly *r, const polyvec *a, const polyvec *b, - const polyvec_mulcache *b_cache) { + const polyvec_mulcache *b_cache) +{ polyvec_basemul_acc_montgomery_cached_asm_opt( r->coeffs, a->vec[0].coeffs, b->vec[0].coeffs, b_cache->vec[0].coeffs); } static inline void poly_tobytes_native(uint8_t r[MLKEM_POLYBYTES], - const poly *a) { + const poly *a) +{ poly_tobytes_asm_clean(r, a->coeffs); } static inline int rej_uniform_native(int16_t *r, unsigned int len, - const uint8_t *buf, unsigned int buflen) { - if (len != MLKEM_N || buflen % 24 != 0) { + const uint8_t *buf, unsigned int buflen) +{ + if (len != MLKEM_N || buflen % 24 != 0) + { return -1; } return (int)rej_uniform_asm_clean(r, buf, buflen); diff --git a/mlkem/native/x86_64/align.h b/mlkem/native/x86_64/align.h index 32bbbb8e6..cfa4a6398 100644 --- a/mlkem/native/x86_64/align.h +++ b/mlkem/native/x86_64/align.h @@ -11,13 +11,15 @@ #include #define ALIGNED_UINT8(N) \ - union { \ + union \ + { \ uint8_t coeffs[N]; \ __m256i vec[(N + 31) / 32]; \ } #define ALIGNED_INT16(N) \ - union { \ + union \ + { \ int16_t coeffs[N]; \ __m256i vec[(N + 15) / 16]; \ } diff --git a/mlkem/native/x86_64/basemul.c b/mlkem/native/x86_64/basemul.c index af8766730..24dee0374 100644 --- a/mlkem/native/x86_64/basemul.c +++ b/mlkem/native/x86_64/basemul.c @@ -10,19 +10,21 @@ #include "poly.h" #include "polyvec.h" -static void poly_basemul_montgomery_avx2(poly *r, const poly *a, - const poly *b) { +static void poly_basemul_montgomery_avx2(poly *r, const poly *a, const poly *b) +{ basemul_avx2((__m256i *)r->coeffs, (const __m256i *)a->coeffs, (const __m256i *)b->coeffs, qdata.vec); } // Implementation from Kyber reference repository // https://github.com/pq-crystals/kyber/blob/main/avx2 -static void poly_add_avx2(poly *r, const poly *a, const poly *b) { +static void poly_add_avx2(poly *r, const poly *a, const poly *b) +{ unsigned int i; __m256i f0, f1; - for (i = 0; i < MLKEM_N; i += 16) { + for (i = 0; i < MLKEM_N; i += 16) + { f0 = _mm256_load_si256((const __m256i *)&a->coeffs[i]); f1 = _mm256_load_si256((const __m256i *)&b->coeffs[i]); f0 = _mm256_add_epi16(f0, f1); @@ -30,9 +32,10 @@ static void poly_add_avx2(poly *r, const poly *a, const poly *b) { } } -void polyvec_basemul_acc_montgomery_cached_avx2( - poly *r, const polyvec *a, const polyvec *b, - const polyvec_mulcache *b_cache) { +void polyvec_basemul_acc_montgomery_cached_avx2(poly *r, const polyvec *a, + const polyvec *b, + const polyvec_mulcache *b_cache) +{ ((void)b_cache); // cache unused // TODO! Think through bounds @@ -41,7 +44,8 @@ void polyvec_basemul_acc_montgomery_cached_avx2( poly t; poly_basemul_montgomery_avx2(r, &a->vec[0], &b->vec[0]); - for (i = 1; i < MLKEM_K; i++) { + for (i = 1; i < MLKEM_K; i++) + { poly_basemul_montgomery_avx2(&t, &a->vec[i], &b->vec[i]); poly_add_avx2(r, r, &t); } diff --git a/mlkem/native/x86_64/profiles/default.h b/mlkem/native/x86_64/profiles/default.h index 548f003c1..befbc7a30 100644 --- a/mlkem/native/x86_64/profiles/default.h +++ b/mlkem/native/x86_64/profiles/default.h @@ -33,38 +33,45 @@ #define NTT_BOUND_NATIVE \ (16118 + 1) // Bound from the official Kyber repository -static inline void poly_permute_bitrev_to_custom(poly *data) { +static inline void poly_permute_bitrev_to_custom(poly *data) +{ nttunpack_avx2((__m256i *)(data->coeffs), qdata.vec); } static inline int rej_uniform_native(int16_t *r, unsigned int len, - const uint8_t *buf, unsigned int buflen) { + const uint8_t *buf, unsigned int buflen) +{ // AVX2 implementation assumes specific buffer lengths - if (len != MLKEM_N || buflen != REJ_UNIFORM_AVX_BUFLEN) { + if (len != MLKEM_N || buflen != REJ_UNIFORM_AVX_BUFLEN) + { return -1; } return (int)rej_uniform_avx2(r, buf); } -static inline void ntt_native(poly *data) { +static inline void ntt_native(poly *data) +{ ntt_avx2((__m256i *)data, qdata.vec); } -static inline void intt_native(poly *data) { +static inline void intt_native(poly *data) +{ invntt_avx2((__m256i *)data, qdata.vec); } -static inline void poly_reduce_native(poly *data) { +static inline void poly_reduce_native(poly *data) +{ reduce_avx2((__m256i *)data->coeffs, qdata.vec); } -static inline void poly_tomont_native(poly *data) { +static inline void poly_tomont_native(poly *data) +{ tomont_avx2((__m256i *)data->coeffs, qdata.vec); } -static inline void poly_mulcache_compute_native(poly_mulcache *x, - const poly *y) { +static inline void poly_mulcache_compute_native(poly_mulcache *x, const poly *y) +{ // AVX2 backend does not use mulcache ((void)y); @@ -76,17 +83,20 @@ static inline void poly_mulcache_compute_native(poly_mulcache *x, static inline void polyvec_basemul_acc_montgomery_cached_native( poly *r, const polyvec *a, const polyvec *b, - const polyvec_mulcache *b_cache) { + const polyvec_mulcache *b_cache) +{ polyvec_basemul_acc_montgomery_cached_avx2(r, a, b, b_cache); } static inline void poly_tobytes_native(uint8_t r[MLKEM_POLYBYTES], - const poly *a) { + const poly *a) +{ ntttobytes_avx2(r, (const __m256i *)a->coeffs, qdata.vec); } static inline void poly_frombytes_native(poly *r, - const uint8_t a[MLKEM_POLYBYTES]) { + const uint8_t a[MLKEM_POLYBYTES]) +{ nttfrombytes_avx2((__m256i *)r->coeffs, a, qdata.vec); } diff --git a/mlkem/native/x86_64/rej_uniform_avx2.c b/mlkem/native/x86_64/rej_uniform_avx2.c index b3129ae79..0686991c8 100644 --- a/mlkem/native/x86_64/rej_uniform_avx2.c +++ b/mlkem/native/x86_64/rej_uniform_avx2.c @@ -153,7 +153,8 @@ static const uint8_t idx[256][8] = { #define _mm256_cmpge_epu16(a, b) _mm256_cmpeq_epi16(_mm256_max_epu16(a, b), a) #define _mm_cmpge_epu16(a, b) _mm_cmpeq_epi16(_mm_max_epu16(a, b), a) -unsigned int rej_uniform_avx2(int16_t *restrict r, const uint8_t *buf) { +unsigned int rej_uniform_avx2(int16_t *restrict r, const uint8_t *buf) +{ unsigned int ctr, pos; uint16_t val0, val1; uint32_t good; @@ -170,7 +171,8 @@ unsigned int rej_uniform_avx2(int16_t *restrict r, const uint8_t *buf) { __m128i f, t, pilo, pihi; ctr = pos = 0; - while (ctr <= MLKEM_N - 32 && pos <= REJ_UNIFORM_AVX_BUFLEN - 48) { + while (ctr <= MLKEM_N - 32 && pos <= REJ_UNIFORM_AVX_BUFLEN - 48) + { f0 = _mm256_loadu_si256((__m256i *)&buf[pos]); // Don't load from offset 24, as this would over-read the buffer f1 = _mm256_loadu_si256((__m256i *)&buf[pos + 16]); @@ -239,7 +241,8 @@ unsigned int rej_uniform_avx2(int16_t *restrict r, const uint8_t *buf) { ctr += _mm_popcnt_u32((good >> 24) & 0xFF); } - while (ctr <= MLKEM_N - 8 && pos <= REJ_UNIFORM_AVX_BUFLEN - 24) { + while (ctr <= MLKEM_N - 8 && pos <= REJ_UNIFORM_AVX_BUFLEN - 24) + { f = _mm_loadu_si128((__m128i *)&buf[pos]); f = _mm_shuffle_epi8(f, _mm256_castsi256_si128(idx8)); t = _mm_srli_epi16(f, 4); @@ -268,7 +271,8 @@ unsigned int rej_uniform_avx2(int16_t *restrict r, const uint8_t *buf) { ctr += _mm_popcnt_u32(good); } - while (ctr < MLKEM_N && pos <= REJ_UNIFORM_AVX_BUFLEN - 3) { + while (ctr < MLKEM_N && pos <= REJ_UNIFORM_AVX_BUFLEN - 3) + { val0 = ((buf[pos + 0] >> 0) | ((uint16_t)buf[pos + 1] << 8)) & 0xFFF; val1 = ((buf[pos + 1] >> 4) | ((uint16_t)buf[pos + 2] << 4)); pos += 3; diff --git a/mlkem/ntt.c b/mlkem/ntt.c index 858b3b2d0..3bb0694a7 100644 --- a/mlkem/ntt.c +++ b/mlkem/ntt.c @@ -43,36 +43,36 @@ // STATIC_TESTABLE void ntt_butterfly_block(int16_t r[MLKEM_N], int16_t zeta, int start, int len, - int bound) // clang-format off -REQUIRES(0 <= start && start < MLKEM_N) -REQUIRES(1 <= len && len <= MLKEM_N / 2 && start + 2 * len <= MLKEM_N) -REQUIRES(0 <= bound && bound < INT16_MAX - MLKEM_Q) -REQUIRES(-HALF_Q < zeta && zeta < HALF_Q) -REQUIRES(IS_FRESH(r, sizeof(int16_t) * MLKEM_N)) -REQUIRES(ARRAY_ABS_BOUND(r, 0, start - 1, bound + MLKEM_Q)) -REQUIRES(ARRAY_ABS_BOUND(r, start, MLKEM_N - 1, bound)) -ASSIGNS(OBJECT_UPTO(r, sizeof(int16_t) * MLKEM_N)) -ENSURES(ARRAY_ABS_BOUND(r, 0, start + 2*len - 1, bound + MLKEM_Q)) -ENSURES(ARRAY_ABS_BOUND(r, start + 2 * len, MLKEM_N - 1, bound)) -// clang-format on + int bound) +__contract__( + requires(0 <= start && start < MLKEM_N) + requires(1 <= len && len <= MLKEM_N / 2 && start + 2 * len <= MLKEM_N) + requires(0 <= bound && bound < INT16_MAX - MLKEM_Q) + requires(-HALF_Q < zeta && zeta < HALF_Q) + requires(memory_no_alias(r, sizeof(int16_t) * MLKEM_N)) + requires(array_abs_bound(r, 0, start - 1, bound + MLKEM_Q)) + requires(array_abs_bound(r, start, MLKEM_N - 1, bound)) + assigns(memory_slice(r, sizeof(int16_t) * MLKEM_N)) + ensures(array_abs_bound(r, 0, start + 2*len - 1, bound + MLKEM_Q)) + ensures(array_abs_bound(r, start + 2 * len, MLKEM_N - 1, bound))) { // `bound` is a ghost variable only needed in the CBMC specification ((void)bound); - for (int j = start; j < start + len; j++) // clang-format off - INVARIANT(start <= j && j <= start + len) + for (int j = start; j < start + len; j++) + __loop__( + invariant(start <= j && j <= start + len) // Coefficients are updated in strided pairs, so the bounds for the // intermediate states alternate twice between the old and new bound - INVARIANT(ARRAY_ABS_BOUND(r, 0, j - 1, bound + MLKEM_Q)) - INVARIANT(ARRAY_ABS_BOUND(r, j, start + len - 1, bound)) - INVARIANT(ARRAY_ABS_BOUND(r, start + len, j + len - 1, bound + MLKEM_Q)) - INVARIANT(ARRAY_ABS_BOUND(r, j + len, MLKEM_N - 1, bound)) - // clang-format on - { - int16_t t; - t = fqmul(r[j + len], zeta); - r[j + len] = r[j] - t; - r[j] = r[j] + t; - } + invariant(array_abs_bound(r, 0, j - 1, bound + MLKEM_Q)) + invariant(array_abs_bound(r, j, start + len - 1, bound)) + invariant(array_abs_bound(r, start + len, j + len - 1, bound + MLKEM_Q)) + invariant(array_abs_bound(r, j + len, MLKEM_N - 1, bound))) + { + int16_t t; + t = fqmul(r[j + len], zeta); + r[j + len] = r[j] - t; + r[j] = r[j] + t; + } } // Compute one layer of forward NTT @@ -88,28 +88,28 @@ ENSURES(ARRAY_ABS_BOUND(r, start + 2 * len, MLKEM_N - 1, bound)) // official Kyber implementation here, merely adding `layer` as // a ghost variable for the specifications. STATIC_TESTABLE -void ntt_layer(int16_t r[MLKEM_N], int len, int layer) // clang-format off -REQUIRES(IS_FRESH(r, sizeof(int16_t) * MLKEM_N)) -REQUIRES(1 <= layer && layer <= 7 && len == (MLKEM_N >> layer)) -REQUIRES(ARRAY_ABS_BOUND(r, 0, MLKEM_N - 1, layer * MLKEM_Q - 1)) -ASSIGNS(OBJECT_UPTO(r, sizeof(int16_t) * MLKEM_N)) -ENSURES(ARRAY_ABS_BOUND(r, 0, MLKEM_N - 1, (layer + 1) * MLKEM_Q - 1)) -// clang-format on +void ntt_layer(int16_t r[MLKEM_N], int len, int layer) +__contract__( + requires(memory_no_alias(r, sizeof(int16_t) * MLKEM_N)) + requires(1 <= layer && layer <= 7 && len == (MLKEM_N >> layer)) + requires(array_abs_bound(r, 0, MLKEM_N - 1, layer * MLKEM_Q - 1)) + assigns(memory_slice(r, sizeof(int16_t) * MLKEM_N)) + ensures(array_abs_bound(r, 0, MLKEM_N - 1, (layer + 1) * MLKEM_Q - 1))) { // `layer` is a ghost variable only needed in the CBMC specification ((void)layer); // Twiddle factors for layer n start at index 2^(layer-1) int k = MLKEM_N / (2 * len); - for (int start = 0; start < MLKEM_N; start += 2 * len) // clang-format off - INVARIANT(0 <= start && start < MLKEM_N + 2 * len) - INVARIANT(0 <= k && k <= MLKEM_N / 2 && 2 * len * k == start + MLKEM_N) - INVARIANT(ARRAY_ABS_BOUND(r, 0, start - 1, (layer * MLKEM_Q - 1) + MLKEM_Q)) - INVARIANT(ARRAY_ABS_BOUND(r, start, MLKEM_N - 1, layer * MLKEM_Q - 1)) - // clang-format on - { - int16_t zeta = zetas[k++]; - ntt_butterfly_block(r, zeta, start, len, layer * MLKEM_Q - 1); - } + for (int start = 0; start < MLKEM_N; start += 2 * len) + __loop__( + invariant(0 <= start && start < MLKEM_N + 2 * len) + invariant(0 <= k && k <= MLKEM_N / 2 && 2 * len * k == start + MLKEM_N) + invariant(array_abs_bound(r, 0, start - 1, (layer * MLKEM_Q - 1) + MLKEM_Q)) + invariant(array_abs_bound(r, start, MLKEM_N - 1, layer * MLKEM_Q - 1))) + { + int16_t zeta = zetas[k++]; + ntt_butterfly_block(r, zeta, start, len, layer * MLKEM_Q - 1); + } } // Compute full forward NTT @@ -122,18 +122,18 @@ ENSURES(ARRAY_ABS_BOUND(r, 0, MLKEM_N - 1, (layer + 1) * MLKEM_Q - 1)) // // REF-CHANGE: Removed indirection poly_ntt -> ntt() // and integrated polynomial reduction into the NTT. -void poly_ntt(poly *p) { +void poly_ntt(poly *p) +{ POLY_BOUND_MSG(p, MLKEM_Q, "ref ntt input"); int16_t *r = p->coeffs; - for (int len = 128, layer = 1; len >= 2; - len >>= 1, layer++) // clang-format off - INVARIANT(1 <= layer && layer <= 8 && len == (MLKEM_N >> layer)) - INVARIANT(ARRAY_ABS_BOUND(r, 0, MLKEM_N - 1, layer * MLKEM_Q - 1)) - // clang-format on - { - ntt_layer(r, len, layer); - } + for (int len = 128, layer = 1; len >= 2; len >>= 1, layer++) + __loop__( + invariant(1 <= layer && layer <= 8 && len == (MLKEM_N >> layer)) + invariant(array_abs_bound(r, 0, MLKEM_N - 1, layer * MLKEM_Q - 1))) + { + ntt_layer(r, len, layer); + } // Check the stronger bound POLY_BOUND_MSG(p, NTT_BOUND, "ref ntt output"); @@ -143,7 +143,8 @@ void poly_ntt(poly *p) { // Check that bound for native NTT implies contractual bound STATIC_ASSERT(NTT_BOUND_NATIVE <= NTT_BOUND, invntt_bound) -void poly_ntt(poly *p) { +void poly_ntt(poly *p) +{ POLY_BOUND_MSG(p, MLKEM_Q, "native ntt input"); ntt_native(p); POLY_BOUND_MSG(p, NTT_BOUND_NATIVE, "native ntt output"); @@ -158,41 +159,42 @@ STATIC_ASSERT(INVNTT_BOUND_REF <= INVNTT_BOUND, invntt_bound) // Compute one layer of inverse NTT STATIC_TESTABLE -void invntt_layer(int16_t *r, int len, int layer) // clang-format off -REQUIRES(IS_FRESH(r, sizeof(int16_t) * MLKEM_N)) -REQUIRES(2 <= len && len <= 128 && 1 <= layer && layer <= 7) -REQUIRES(len == (1 << (8 - layer))) -REQUIRES(ARRAY_ABS_BOUND(r, 0, MLKEM_N - 1, MLKEM_Q)) -ASSIGNS(OBJECT_UPTO(r, sizeof(int16_t) * MLKEM_N)) -ENSURES(ARRAY_ABS_BOUND(r, 0, MLKEM_N - 1, MLKEM_Q)) -// clang-format on +void invntt_layer(int16_t *r, int len, int layer) +__contract__( + requires(memory_no_alias(r, sizeof(int16_t) * MLKEM_N)) + requires(2 <= len && len <= 128 && 1 <= layer && layer <= 7) + requires(len == (1 << (8 - layer))) + requires(array_abs_bound(r, 0, MLKEM_N - 1, MLKEM_Q)) + assigns(memory_slice(r, sizeof(int16_t) * MLKEM_N)) + ensures(array_abs_bound(r, 0, MLKEM_N - 1, MLKEM_Q))) { // `layer` is a ghost variable used only in the specification ((void)layer); int k = MLKEM_N / len - 1; - for (int start = 0; start < MLKEM_N; start += 2 * len) // clang-format off - INVARIANT(ARRAY_ABS_BOUND(r, 0, MLKEM_N - 1, MLKEM_Q)) - INVARIANT(0 <= start && start <= MLKEM_N && 0 <= k && k <= 127) + for (int start = 0; start < MLKEM_N; start += 2 * len) + __loop__( + invariant(array_abs_bound(r, 0, MLKEM_N - 1, MLKEM_Q)) + invariant(0 <= start && start <= MLKEM_N && 0 <= k && k <= 127) // Normalised form of k == MLKEM_N / len - 1 - start / (2 * len) - INVARIANT(2 * len * k + start == 2 * MLKEM_N - 2 * len) - // clang-format on + invariant(2 * len * k + start == 2 * MLKEM_N - 2 * len)) + { + int16_t zeta = zetas[k--]; + for (int j = start; j < start + len; j++) + __loop__( + invariant(start <= j && j <= start + len) + invariant(0 <= start && start <= MLKEM_N && 0 <= k && k <= 127) + invariant(array_abs_bound(r, 0, MLKEM_N - 1, MLKEM_Q))) { - int16_t zeta = zetas[k--]; - for (int j = start; j < start + len; j++) // clang-format off - INVARIANT(start <= j && j <= start + len) - INVARIANT(0 <= start && start <= MLKEM_N && 0 <= k && k <= 127) - INVARIANT(ARRAY_ABS_BOUND(r, 0, MLKEM_N - 1, MLKEM_Q)) - // clang-format on - { - int16_t t = r[j]; - r[j] = barrett_reduce(t + r[j + len]); - r[j + len] = r[j + len] - t; - r[j + len] = fqmul(r[j + len], zeta); - } + int16_t t = r[j]; + r[j] = barrett_reduce(t + r[j + len]); + r[j + len] = r[j + len] - t; + r[j + len] = fqmul(r[j + len], zeta); } + } } -void poly_invntt_tomont(poly *p) { +void poly_invntt_tomont(poly *p) +{ const int16_t f = 1441; // mont^2/128 int16_t *r = p->coeffs; @@ -200,22 +202,22 @@ void poly_invntt_tomont(poly *p) { // and NTT twist. This also brings coefficients down to // absolute value < MLKEM_Q. - for (int j = 0; j < MLKEM_N; j++) // clang-format off - INVARIANT(0 <= j && j <= MLKEM_N && ARRAY_ABS_BOUND(r, 0, j - 1, MLKEM_Q)) - // clang-format on - { - r[j] = fqmul(r[j], f); - } + for (int j = 0; j < MLKEM_N; j++) + __loop__( + invariant(0 <= j && j <= MLKEM_N) + invariant(array_abs_bound(r, 0, j - 1, MLKEM_Q))) + { + r[j] = fqmul(r[j], f); + } // Run the invNTT layers - for (int len = 2, layer = 7; len <= 128; - len <<= 1, layer--) // clang-format off - INVARIANT(2 <= len && len <= 256 && 0 <= layer && layer <= 7 && len == (1 << (8 - layer))) - INVARIANT(ARRAY_ABS_BOUND(r, 0, MLKEM_N - 1, MLKEM_Q)) - // clang-format on - { - invntt_layer(p->coeffs, len, layer); - } + for (int len = 2, layer = 7; len <= 128; len <<= 1, layer--) + __loop__( + invariant(2 <= len && len <= 256 && 0 <= layer && layer <= 7 && len == (1 << (8 - layer))) + invariant(array_abs_bound(r, 0, MLKEM_N - 1, MLKEM_Q))) + { + invntt_layer(p->coeffs, len, layer); + } POLY_BOUND_MSG(p, INVNTT_BOUND_REF, "ref intt output"); } @@ -224,7 +226,8 @@ void poly_invntt_tomont(poly *p) { // Check that bound for native invNTT implies contractual bound STATIC_ASSERT(INVNTT_BOUND_NATIVE <= INVNTT_BOUND, invntt_bound) -void poly_invntt_tomont(poly *p) { +void poly_invntt_tomont(poly *p) +{ intt_native(p); POLY_BOUND_MSG(p, INVNTT_BOUND_NATIVE, "native intt output"); } @@ -246,7 +249,8 @@ void poly_invntt_tomont(poly *p) { * - int16_t b_cached: Cached precomputation of b[1] * zeta **************************************************/ void basemul_cached(int16_t r[2], const int16_t a[2], const int16_t b[2], - int16_t b_cached) { + int16_t b_cached) +{ BOUND(a, 2, MLKEM_Q, "basemul input bound"); int32_t t0, t1; diff --git a/mlkem/ntt.h b/mlkem/ntt.h index 2a4ce3bc3..48fbd43c7 100644 --- a/mlkem/ntt.h +++ b/mlkem/ntt.h @@ -32,12 +32,13 @@ extern const int16_t zetas[128]; **************************************************/ #define poly_ntt MLKEM_NAMESPACE(poly_ntt) -void poly_ntt(poly *r) // clang-format off -REQUIRES(IS_FRESH(r, sizeof(poly))) -REQUIRES(ARRAY_ABS_BOUND(r->coeffs, 0, MLKEM_N - 1, MLKEM_Q - 1)) -ASSIGNS(OBJECT_UPTO(r, sizeof(poly))) -ENSURES(ARRAY_ABS_BOUND(r->coeffs, 0, MLKEM_N - 1, NTT_BOUND - 1)); -// clang-format on +void poly_ntt(poly *r) +__contract__( + requires(memory_no_alias(r, sizeof(poly))) + requires(array_abs_bound(r->coeffs, 0, MLKEM_N - 1, MLKEM_Q - 1)) + assigns(memory_slice(r, sizeof(poly))) + ensures(array_abs_bound(r->coeffs, 0, MLKEM_N - 1, NTT_BOUND - 1)) +); /************************************************* * Name: poly_invntt_tomont @@ -56,11 +57,12 @@ ENSURES(ARRAY_ABS_BOUND(r->coeffs, 0, MLKEM_N - 1, NTT_BOUND - 1)); * Arguments: - uint16_t *a: pointer to in/output polynomial **************************************************/ #define poly_invntt_tomont MLKEM_NAMESPACE(poly_invntt_tomont) -void poly_invntt_tomont(poly *r) // clang-format off -REQUIRES(IS_FRESH(r, sizeof(poly))) -ASSIGNS(OBJECT_UPTO(r, sizeof(poly))) -ENSURES(ARRAY_ABS_BOUND(r->coeffs, 0, MLKEM_N - 1, INVNTT_BOUND - 1)); -// clang-format on +void poly_invntt_tomont(poly *r) +__contract__( + requires(memory_no_alias(r, sizeof(poly))) + assigns(memory_slice(r, sizeof(poly))) + ensures(array_abs_bound(r->coeffs, 0, MLKEM_N - 1, INVNTT_BOUND - 1)) +); #define basemul_cached MLKEM_NAMESPACE(basemul_cached) /************************************************************ @@ -84,14 +86,15 @@ ENSURES(ARRAY_ABS_BOUND(r->coeffs, 0, MLKEM_N - 1, INVNTT_BOUND - 1)); * b1 and a twiddle factor. Can be an arbitary int16_t. ************************************************************/ void basemul_cached(int16_t r[2], const int16_t a[2], const int16_t b[2], - int16_t b_cached) // clang-format off -REQUIRES(IS_FRESH(r, 2 * sizeof(int16_t))) -REQUIRES(IS_FRESH(a, 2 * sizeof(int16_t))) -REQUIRES(IS_FRESH(b, 2 * sizeof(int16_t))) -REQUIRES(ARRAY_ABS_BOUND(a, 0, 1, MLKEM_Q - 1)) -ASSIGNS(OBJECT_UPTO(r, 2 * sizeof(int16_t))) -ENSURES(ARRAY_ABS_BOUND(r, 0, 1, (3 * HALF_Q - 1))); -// clang-format on + int16_t b_cached) +__contract__( + requires(memory_no_alias(r, 2 * sizeof(int16_t))) + requires(memory_no_alias(a, 2 * sizeof(int16_t))) + requires(memory_no_alias(b, 2 * sizeof(int16_t))) + requires(array_abs_bound(a, 0, 1, MLKEM_Q - 1)) + assigns(memory_slice(r, 2 * sizeof(int16_t))) + ensures(array_abs_bound(r, 0, 1, (3 * HALF_Q - 1))) +); #endif diff --git a/mlkem/poly.c b/mlkem/poly.c index bbff1b057..f0d300e3e 100644 --- a/mlkem/poly.c +++ b/mlkem/poly.c @@ -15,210 +15,223 @@ #include "arith_native.h" #include "debug/debug.h" -void poly_compress_du(uint8_t r[MLKEM_POLYCOMPRESSEDBYTES_DU], const poly *a) { +void poly_compress_du(uint8_t r[MLKEM_POLYCOMPRESSEDBYTES_DU], const poly *a) +{ #if (MLKEM_POLYCOMPRESSEDBYTES_DU == 352) - for (int j = 0; j < MLKEM_N / 8; j++) // clang-format off - INVARIANT(j >= 0 && j <= MLKEM_N / 8) - { // clang-format on - uint16_t t[8]; - for (int k = 0; k < 8; k++) // clang-format off - INVARIANT(k >= 0 && k <= 8) - INVARIANT(FORALL(int, r, 0, k - 1, t[r] < (1u << 11))) - { // clang-format on - t[k] = scalar_compress_d11(a->coeffs[8 * j + k]); - } - - // REF-CHANGE: Use array indexing into - // r rather than pointer-arithmetic to simplify verification - // - // Make all implicit truncation explicit. No data is being - // truncated for the LHS's since each t[i] is 11-bit in size. - r[11 * j + 0] = (t[0] >> 0) & 0xFF; - r[11 * j + 1] = (t[0] >> 8) | ((t[1] << 3) & 0xFF); - r[11 * j + 2] = (t[1] >> 5) | ((t[2] << 6) & 0xFF); - r[11 * j + 3] = (t[2] >> 2) & 0xFF; - r[11 * j + 4] = (t[2] >> 10) | ((t[3] << 1) & 0xFF); - r[11 * j + 5] = (t[3] >> 7) | ((t[4] << 4) & 0xFF); - r[11 * j + 6] = (t[4] >> 4) | ((t[5] << 7) & 0xFF); - r[11 * j + 7] = (t[5] >> 1) & 0xFF; - r[11 * j + 8] = (t[5] >> 9) | ((t[6] << 2) & 0xFF); - r[11 * j + 9] = (t[6] >> 6) | ((t[7] << 5) & 0xFF); - r[11 * j + 10] = (t[7] >> 3); + for (int j = 0; j < MLKEM_N / 8; j++) + __loop__(invariant(j >= 0 && j <= MLKEM_N / 8)) + { + uint16_t t[8]; + for (int k = 0; k < 8; k++) + __loop__( + invariant(k >= 0 && k <= 8) + invariant(forall(int, r, 0, k - 1, t[r] < (1u << 11)))) + { + t[k] = scalar_compress_d11(a->coeffs[8 * j + k]); } + // REF-CHANGE: Use array indexing into + // r rather than pointer-arithmetic to simplify verification + // + // Make all implicit truncation explicit. No data is being + // truncated for the LHS's since each t[i] is 11-bit in size. + r[11 * j + 0] = (t[0] >> 0) & 0xFF; + r[11 * j + 1] = (t[0] >> 8) | ((t[1] << 3) & 0xFF); + r[11 * j + 2] = (t[1] >> 5) | ((t[2] << 6) & 0xFF); + r[11 * j + 3] = (t[2] >> 2) & 0xFF; + r[11 * j + 4] = (t[2] >> 10) | ((t[3] << 1) & 0xFF); + r[11 * j + 5] = (t[3] >> 7) | ((t[4] << 4) & 0xFF); + r[11 * j + 6] = (t[4] >> 4) | ((t[5] << 7) & 0xFF); + r[11 * j + 7] = (t[5] >> 1) & 0xFF; + r[11 * j + 8] = (t[5] >> 9) | ((t[6] << 2) & 0xFF); + r[11 * j + 9] = (t[6] >> 6) | ((t[7] << 5) & 0xFF); + r[11 * j + 10] = (t[7] >> 3); + } + #elif (MLKEM_POLYCOMPRESSEDBYTES_DU == 320) - for (int j = 0; j < MLKEM_N / 4; j++) // clang-format off - INVARIANT(j >= 0 && j <= MLKEM_N / 4) - { // clang-format on - uint16_t t[4]; - for (int k = 0; k < 4; k++) // clang-format off - INVARIANT(k >= 0 && k <= 4) - INVARIANT(FORALL(int, r, 0, k - 1, t[r] < (1u << 10))) - { // clang-format on - t[k] = scalar_compress_d10(a->coeffs[4 * j + k]); - } - - // REF-CHANGE: Use array indexing into - // r rather than pointer-arithmetic to simplify verification - // - // Make all implicit truncation explicit. No data is being - // truncated for the LHS's since each t[i] is 10-bit in size. - r[5 * j + 0] = (t[0] >> 0) & 0xFF; - r[5 * j + 1] = (t[0] >> 8) | ((t[1] << 2) & 0xFF); - r[5 * j + 2] = (t[1] >> 6) | ((t[2] << 4) & 0xFF); - r[5 * j + 3] = (t[2] >> 4) | ((t[3] << 6) & 0xFF); - r[5 * j + 4] = (t[3] >> 2); + for (int j = 0; j < MLKEM_N / 4; j++) + __loop__(invariant(j >= 0 && j <= MLKEM_N / 4)) + { + uint16_t t[4]; + for (int k = 0; k < 4; k++) + __loop__( + invariant(k >= 0 && k <= 4) + invariant(forall(int, r, 0, k - 1, t[r] < (1u << 10)))) + { + t[k] = scalar_compress_d10(a->coeffs[4 * j + k]); } + + // REF-CHANGE: Use array indexing into + // r rather than pointer-arithmetic to simplify verification + // + // Make all implicit truncation explicit. No data is being + // truncated for the LHS's since each t[i] is 10-bit in size. + r[5 * j + 0] = (t[0] >> 0) & 0xFF; + r[5 * j + 1] = (t[0] >> 8) | ((t[1] << 2) & 0xFF); + r[5 * j + 2] = (t[1] >> 6) | ((t[2] << 4) & 0xFF); + r[5 * j + 3] = (t[2] >> 4) | ((t[3] << 6) & 0xFF); + r[5 * j + 4] = (t[3] >> 2); + } #else #error "MLKEM_POLYCOMPRESSEDBYTES_DU needs to be in {320,352}" #endif } -void poly_decompress_du(poly *r, - const uint8_t a[MLKEM_POLYCOMPRESSEDBYTES_DU]) { +void poly_decompress_du(poly *r, const uint8_t a[MLKEM_POLYCOMPRESSEDBYTES_DU]) +{ #if (MLKEM_POLYCOMPRESSEDBYTES_DU == 352) - for (int j = 0; j < MLKEM_N / 8; j++) // clang-format off - INVARIANT(0 <= j && j <= MLKEM_N / 8) - INVARIANT(ARRAY_BOUND(r->coeffs, 0, 8 * j - 1, 0, (MLKEM_Q - 1))) - { // clang-format on - uint16_t t[8]; - uint8_t const *base = &a[11 * j]; - t[0] = 0x7FF & ((base[0] >> 0) | ((uint16_t)base[1] << 8)); - t[1] = 0x7FF & ((base[1] >> 3) | ((uint16_t)base[2] << 5)); - t[2] = 0x7FF & ((base[2] >> 6) | ((uint16_t)base[3] << 2) | - ((uint16_t)base[4] << 10)); - t[3] = 0x7FF & ((base[4] >> 1) | ((uint16_t)base[5] << 7)); - t[4] = 0x7FF & ((base[5] >> 4) | ((uint16_t)base[6] << 4)); - t[5] = 0x7FF & ((base[6] >> 7) | ((uint16_t)base[7] << 1) | - ((uint16_t)base[8] << 9)); - t[6] = 0x7FF & ((base[8] >> 2) | ((uint16_t)base[9] << 6)); - t[7] = 0x7FF & ((base[9] >> 5) | ((uint16_t)base[10] << 3)); - - for (int k = 0; k < 8; k++) // clang-format off - INVARIANT(0 <= k && k <= 8) - INVARIANT(ARRAY_BOUND(r->coeffs, 0, 8 * j + k - 1, 0, (MLKEM_Q - 1))) - { // clang-format on - r->coeffs[8 * j + k] = scalar_decompress_d11(t[k]); - } + for (int j = 0; j < MLKEM_N / 8; j++) + __loop__( + invariant(0 <= j && j <= MLKEM_N / 8) + invariant(array_bound(r->coeffs, 0, 8 * j - 1, 0, (MLKEM_Q - 1)))) + { + uint16_t t[8]; + uint8_t const *base = &a[11 * j]; + t[0] = 0x7FF & ((base[0] >> 0) | ((uint16_t)base[1] << 8)); + t[1] = 0x7FF & ((base[1] >> 3) | ((uint16_t)base[2] << 5)); + t[2] = 0x7FF & ((base[2] >> 6) | ((uint16_t)base[3] << 2) | + ((uint16_t)base[4] << 10)); + t[3] = 0x7FF & ((base[4] >> 1) | ((uint16_t)base[5] << 7)); + t[4] = 0x7FF & ((base[5] >> 4) | ((uint16_t)base[6] << 4)); + t[5] = 0x7FF & ((base[6] >> 7) | ((uint16_t)base[7] << 1) | + ((uint16_t)base[8] << 9)); + t[6] = 0x7FF & ((base[8] >> 2) | ((uint16_t)base[9] << 6)); + t[7] = 0x7FF & ((base[9] >> 5) | ((uint16_t)base[10] << 3)); + + for (int k = 0; k < 8; k++) + __loop__( + invariant(0 <= k && k <= 8) + invariant(array_bound(r->coeffs, 0, 8 * j + k - 1, 0, (MLKEM_Q - 1)))) + { + r->coeffs[8 * j + k] = scalar_decompress_d11(t[k]); } + } #elif (MLKEM_POLYCOMPRESSEDBYTES_DU == 320) - for (int j = 0; j < MLKEM_N / 4; j++) // clang-format off - INVARIANT(0 <= j && j <= MLKEM_N / 4) - INVARIANT(ARRAY_BOUND(r->coeffs, 0, 4 * j - 1, 0, (MLKEM_Q - 1))) - { // clang-format on - uint16_t t[4]; - uint8_t const *base = &a[5 * j]; - - t[0] = 0x3FF & ((base[0] >> 0) | ((uint16_t)base[1] << 8)); - t[1] = 0x3FF & ((base[1] >> 2) | ((uint16_t)base[2] << 6)); - t[2] = 0x3FF & ((base[2] >> 4) | ((uint16_t)base[3] << 4)); - t[3] = 0x3FF & ((base[3] >> 6) | ((uint16_t)base[4] << 2)); - - for (int k = 0; k < 4; k++) // clang-format off - INVARIANT(0 <= k && k <= 4) - INVARIANT(ARRAY_BOUND(r->coeffs, 0, 4 * j + k - 1, 0, (MLKEM_Q - 1))) - { // clang-format on - r->coeffs[4 * j + k] = scalar_decompress_d10(t[k]); - } + for (int j = 0; j < MLKEM_N / 4; j++) + __loop__( + invariant(0 <= j && j <= MLKEM_N / 4) + invariant(array_bound(r->coeffs, 0, 4 * j - 1, 0, (MLKEM_Q - 1)))) + { + uint16_t t[4]; + uint8_t const *base = &a[5 * j]; + + t[0] = 0x3FF & ((base[0] >> 0) | ((uint16_t)base[1] << 8)); + t[1] = 0x3FF & ((base[1] >> 2) | ((uint16_t)base[2] << 6)); + t[2] = 0x3FF & ((base[2] >> 4) | ((uint16_t)base[3] << 4)); + t[3] = 0x3FF & ((base[3] >> 6) | ((uint16_t)base[4] << 2)); + + for (int k = 0; k < 4; k++) + __loop__( + invariant(0 <= k && k <= 4) + invariant(array_bound(r->coeffs, 0, 4 * j + k - 1, 0, (MLKEM_Q - 1)))) + { + r->coeffs[4 * j + k] = scalar_decompress_d10(t[k]); } + } #else #error "MLKEM_POLYCOMPRESSEDBYTES_DU needs to be in {320,352}" #endif } -void poly_compress_dv(uint8_t r[MLKEM_POLYCOMPRESSEDBYTES_DV], const poly *a) { +void poly_compress_dv(uint8_t r[MLKEM_POLYCOMPRESSEDBYTES_DV], const poly *a) +{ POLY_UBOUND(a, MLKEM_Q); #if (MLKEM_POLYCOMPRESSEDBYTES_DV == 128) - for (int i = 0; i < MLKEM_N / 8; i++) // clang-format off - INVARIANT(i >= 0 && i <= MLKEM_N / 8) // clang-format on + for (int i = 0; i < MLKEM_N / 8; i++) + __loop__(invariant(i >= 0 && i <= MLKEM_N / 8)) + { + uint8_t t[8] = {0}; + for (int j = 0; j < 8; j++) + __loop__( + invariant(i >= 0 && i <= MLKEM_N / 8 && j >= 0 && j <= 8) + invariant(array_bound(t, 0, (j-1), 0, 15))) { - uint8_t t[8] = {0}; - for (int j = 0; j < 8; j++) // clang-format off - INVARIANT(i >= 0 && i <= MLKEM_N / 8 && j >= 0 && j <= 8) - INVARIANT(ARRAY_BOUND(t, 0, (j-1), 0, 15)) - { // clang-format on - // REF-CHANGE: Precondition change, we assume unsigned canonical data - t[j] = scalar_compress_d4(a->coeffs[8 * i + j]); - } - - // REF-CHANGE: Use array indexing into - // r rather than pointer-arithmetic to simplify verification - r[i * 4] = t[0] | (t[1] << 4); - r[i * 4 + 1] = t[2] | (t[3] << 4); - r[i * 4 + 2] = t[4] | (t[5] << 4); - r[i * 4 + 3] = t[6] | (t[7] << 4); + // REF-CHANGE: Precondition change, we assume unsigned canonical data + t[j] = scalar_compress_d4(a->coeffs[8 * i + j]); } + + // REF-CHANGE: Use array indexing into + // r rather than pointer-arithmetic to simplify verification + r[i * 4] = t[0] | (t[1] << 4); + r[i * 4 + 1] = t[2] | (t[3] << 4); + r[i * 4 + 2] = t[4] | (t[5] << 4); + r[i * 4 + 3] = t[6] | (t[7] << 4); + } #elif (MLKEM_POLYCOMPRESSEDBYTES_DV == 160) - for (int i = 0; i < MLKEM_N / 8; i++) // clang-format off - INVARIANT(i >= 0 && i <= MLKEM_N / 8) // clang-format on + for (int i = 0; i < MLKEM_N / 8; i++) + __loop__(invariant(i >= 0 && i <= MLKEM_N / 8)) + { + uint8_t t[8] = {0}; + for (int j = 0; j < 8; j++) + __loop__( + invariant(i >= 0 && i <= MLKEM_N / 8 && j >= 0 && j <= 8) + invariant(array_bound(t, 0, (j-1), 0, 31))) { - uint8_t t[8] = {0}; - for (int j = 0; j < 8; j++) // clang-format off - INVARIANT(i >= 0 && i <= MLKEM_N / 8 && j >= 0 && j <= 8) - INVARIANT(ARRAY_BOUND(t, 0, (j-1), 0, 31)) - { // clang-format on - // REF-CHANGE: Precondition change, we assume unsigned canonical data - t[j] = scalar_compress_d5(a->coeffs[8 * i + j]); - } - - // REF-CHANGE: Explicitly truncate to avoid warning about - // implicit truncation in CBMC, and use array indexing into - // r rather than pointer-arithmetic to simplify verification - r[i * 5] = 0xFF & ((t[0] >> 0) | (t[1] << 5)); - r[i * 5 + 1] = 0xFF & ((t[1] >> 3) | (t[2] << 2) | (t[3] << 7)); - r[i * 5 + 2] = 0xFF & ((t[3] >> 1) | (t[4] << 4)); - r[i * 5 + 3] = 0xFF & ((t[4] >> 4) | (t[5] << 1) | (t[6] << 6)); - r[i * 5 + 4] = 0xFF & ((t[6] >> 2) | (t[7] << 3)); + // REF-CHANGE: Precondition change, we assume unsigned canonical data + t[j] = scalar_compress_d5(a->coeffs[8 * i + j]); } + + // REF-CHANGE: Explicitly truncate to avoid warning about + // implicit truncation in CBMC, and use array indexing into + // r rather than pointer-arithmetic to simplify verification + r[i * 5] = 0xFF & ((t[0] >> 0) | (t[1] << 5)); + r[i * 5 + 1] = 0xFF & ((t[1] >> 3) | (t[2] << 2) | (t[3] << 7)); + r[i * 5 + 2] = 0xFF & ((t[3] >> 1) | (t[4] << 4)); + r[i * 5 + 3] = 0xFF & ((t[4] >> 4) | (t[5] << 1) | (t[6] << 6)); + r[i * 5 + 4] = 0xFF & ((t[6] >> 2) | (t[7] << 3)); + } #else #error "MLKEM_POLYCOMPRESSEDBYTES_DV needs to be in {128, 160}" #endif } -void poly_decompress_dv(poly *r, - const uint8_t a[MLKEM_POLYCOMPRESSEDBYTES_DV]) { +void poly_decompress_dv(poly *r, const uint8_t a[MLKEM_POLYCOMPRESSEDBYTES_DV]) +{ #if (MLKEM_POLYCOMPRESSEDBYTES_DV == 128) - for (int i = 0; i < MLKEM_N / 2; i++) // clang-format off - INVARIANT(i >= 0 && i <= MLKEM_N / 2) - INVARIANT(ARRAY_BOUND(r->coeffs, 0, (2 * i - 1), 0, (MLKEM_Q - 1))) - { // clang-format on - // REF-CHANGE: Hoist scalar decompression into separate function - r->coeffs[2 * i + 0] = scalar_decompress_d4((a[i] >> 0) & 0xF); - r->coeffs[2 * i + 1] = scalar_decompress_d4((a[i] >> 4) & 0xF); - } + for (int i = 0; i < MLKEM_N / 2; i++) + __loop__( + invariant(i >= 0 && i <= MLKEM_N / 2) + invariant(array_bound(r->coeffs, 0, (2 * i - 1), 0, (MLKEM_Q - 1)))) + { + // REF-CHANGE: Hoist scalar decompression into separate function + r->coeffs[2 * i + 0] = scalar_decompress_d4((a[i] >> 0) & 0xF); + r->coeffs[2 * i + 1] = scalar_decompress_d4((a[i] >> 4) & 0xF); + } #elif (MLKEM_POLYCOMPRESSEDBYTES_DV == 160) - for (int i = 0; i < MLKEM_N / 8; i++) // clang-format off - INVARIANT(i >= 0 && i <= MLKEM_N / 8) - INVARIANT(ARRAY_BOUND(r->coeffs, 0, (8 * i - 1), 0, (MLKEM_Q - 1))) - { // clang-format on - uint8_t t[8]; - const int offset = i * 5; - // REF-CHANGE: Explicitly truncate to avoid warning about - // implicit truncation in CBMC and unwind loop for ease - // of proof. - - // Decompress 5 8-bit bytes (so 40 bits) into - // 8 5-bit values stored in t[] - t[0] = 0x1F & (a[offset + 0] >> 0); - t[1] = 0x1F & ((a[offset + 0] >> 5) | (a[offset + 1] << 3)); - t[2] = 0x1F & (a[offset + 1] >> 2); - t[3] = 0x1F & ((a[offset + 1] >> 7) | (a[offset + 2] << 1)); - t[4] = 0x1F & ((a[offset + 2] >> 4) | (a[offset + 3] << 4)); - t[5] = 0x1F & (a[offset + 3] >> 1); - t[6] = 0x1F & ((a[offset + 3] >> 6) | (a[offset + 4] << 2)); - t[7] = 0x1F & (a[offset + 4] >> 3); - - // and copy to the correct slice in r[] - for (int j = 0; j < 8; j++) // clang-format off - INVARIANT(j >= 0 && j <= 8 && i >= 0 && i <= MLKEM_N / 8) - INVARIANT(ARRAY_BOUND(r->coeffs, 0, (8 * i + j - 1), 0, (MLKEM_Q - 1))) - { // clang-format on - // REF-CHANGE: Hoist scalar decompression into separate function - r->coeffs[8 * i + j] = scalar_decompress_d5(t[j]); - } + for (int i = 0; i < MLKEM_N / 8; i++) + __loop__( + invariant(i >= 0 && i <= MLKEM_N / 8) + invariant(array_bound(r->coeffs, 0, (8 * i - 1), 0, (MLKEM_Q - 1)))) + { + uint8_t t[8]; + const int offset = i * 5; + // REF-CHANGE: Explicitly truncate to avoid warning about + // implicit truncation in CBMC and unwind loop for ease + // of proof. + + // Decompress 5 8-bit bytes (so 40 bits) into + // 8 5-bit values stored in t[] + t[0] = 0x1F & (a[offset + 0] >> 0); + t[1] = 0x1F & ((a[offset + 0] >> 5) | (a[offset + 1] << 3)); + t[2] = 0x1F & (a[offset + 1] >> 2); + t[3] = 0x1F & ((a[offset + 1] >> 7) | (a[offset + 2] << 1)); + t[4] = 0x1F & ((a[offset + 2] >> 4) | (a[offset + 3] << 4)); + t[5] = 0x1F & (a[offset + 3] >> 1); + t[6] = 0x1F & ((a[offset + 3] >> 6) | (a[offset + 4] << 2)); + t[7] = 0x1F & (a[offset + 4] >> 3); + + // and copy to the correct slice in r[] + for (int j = 0; j < 8; j++) + __loop__( + invariant(j >= 0 && j <= 8 && i >= 0 && i <= MLKEM_N / 8) + invariant(array_bound(r->coeffs, 0, (8 * i + j - 1), 0, (MLKEM_Q - 1)))) + { + // REF-CHANGE: Hoist scalar decompression into separate function + r->coeffs[8 * i + j] = scalar_decompress_d5(t[j]); } + } #else #error "MLKEM_POLYCOMPRESSEDBYTES_DV needs to be in {128, 160}" #endif @@ -227,104 +240,114 @@ void poly_decompress_dv(poly *r, } #if !defined(MLKEM_USE_NATIVE_POLY_TOBYTES) -void poly_tobytes(uint8_t r[MLKEM_POLYBYTES], const poly *a) { +void poly_tobytes(uint8_t r[MLKEM_POLYBYTES], const poly *a) +{ POLY_UBOUND(a, MLKEM_Q); - for (unsigned int i = 0; i < MLKEM_N / 2; i++) // clang-format off - INVARIANT(i >= 0 && i <= MLKEM_N / 2) - // clang-format on - { - const uint16_t t0 = a->coeffs[2 * i]; - const uint16_t t1 = a->coeffs[2 * i + 1]; - // REF-CHANGE: Precondition change, we assume unsigned canonical data + for (unsigned int i = 0; i < MLKEM_N / 2; i++) + __loop__(invariant(i >= 0 && i <= MLKEM_N / 2)) + { + const uint16_t t0 = a->coeffs[2 * i]; + const uint16_t t1 = a->coeffs[2 * i + 1]; + // REF-CHANGE: Precondition change, we assume unsigned canonical data - // t0 and t1 are both < MLKEM_Q, so contain at most 12 bits each of - // significant data, so these can be packed into 24 bits or exactly - // 3 bytes, as follows. + // t0 and t1 are both < MLKEM_Q, so contain at most 12 bits each of + // significant data, so these can be packed into 24 bits or exactly + // 3 bytes, as follows. - // Least significant bits 0 - 7 of t0. - r[3 * i + 0] = t0 & 0xFF; + // Least significant bits 0 - 7 of t0. + r[3 * i + 0] = t0 & 0xFF; - // Most significant bits 8 - 11 of t0 become the least significant - // nibble of the second byte. The least significant 4 bits - // of t1 become the upper nibble of the second byte. - r[3 * i + 1] = (t0 >> 8) | ((t1 << 4) & 0xF0); + // Most significant bits 8 - 11 of t0 become the least significant + // nibble of the second byte. The least significant 4 bits + // of t1 become the upper nibble of the second byte. + r[3 * i + 1] = (t0 >> 8) | ((t1 << 4) & 0xF0); - // Bits 4 - 11 of t1 become the third byte. - r[3 * i + 2] = t1 >> 4; - } + // Bits 4 - 11 of t1 become the third byte. + r[3 * i + 2] = t1 >> 4; + } } #else /* MLKEM_USE_NATIVE_POLY_TOBYTES */ -void poly_tobytes(uint8_t r[MLKEM_POLYBYTES], const poly *a) { +void poly_tobytes(uint8_t r[MLKEM_POLYBYTES], const poly *a) +{ POLY_UBOUND(a, MLKEM_Q); poly_tobytes_native(r, a); } #endif /* MLKEM_USE_NATIVE_POLY_TOBYTES */ #if !defined(MLKEM_USE_NATIVE_POLY_FROMBYTES) -void poly_frombytes(poly *r, const uint8_t a[MLKEM_POLYBYTES]) { +void poly_frombytes(poly *r, const uint8_t a[MLKEM_POLYBYTES]) +{ int i; - for (i = 0; i < MLKEM_N / 2; i++) // clang-format off - INVARIANT(i >= 0 && i <= MLKEM_N / 2) - INVARIANT(ARRAY_BOUND(r->coeffs, 0, (2 * i - 1), 0, 4095)) - { // clang-format on - // REF-CHANGE: Introduce some locals for better readability - const uint8_t t0 = a[3 * i + 0]; - const uint8_t t1 = a[3 * i + 1]; - const uint8_t t2 = a[3 * i + 2]; - r->coeffs[2 * i + 0] = t0 | ((t1 << 8) & 0xFFF); - r->coeffs[2 * i + 1] = (t1 >> 4) | (t2 << 4); - } + for (i = 0; i < MLKEM_N / 2; i++) + __loop__( + invariant(i >= 0 && i <= MLKEM_N / 2) + invariant(array_bound(r->coeffs, 0, (2 * i - 1), 0, 4095))) + { + // REF-CHANGE: Introduce some locals for better readability + const uint8_t t0 = a[3 * i + 0]; + const uint8_t t1 = a[3 * i + 1]; + const uint8_t t2 = a[3 * i + 2]; + r->coeffs[2 * i + 0] = t0 | ((t1 << 8) & 0xFFF); + r->coeffs[2 * i + 1] = (t1 >> 4) | (t2 << 4); + } // Note that the coefficients are not canonical POLY_UBOUND(r, 4096); } #else /* MLKEM_USE_NATIVE_POLY_FROMBYTES */ -void poly_frombytes(poly *r, const uint8_t a[MLKEM_POLYBYTES]) { +void poly_frombytes(poly *r, const uint8_t a[MLKEM_POLYBYTES]) +{ poly_frombytes_native(r, a); } #endif /* MLKEM_USE_NATIVE_POLY_FROMBYTES */ -void poly_frommsg(poly *r, const uint8_t msg[MLKEM_INDCPA_MSGBYTES]) { +void poly_frommsg(poly *r, const uint8_t msg[MLKEM_INDCPA_MSGBYTES]) +{ #if (MLKEM_INDCPA_MSGBYTES != MLKEM_N / 8) #error "MLKEM_INDCPA_MSGBYTES must be equal to MLKEM_N/8 bytes!" #endif - for (int i = 0; i < MLKEM_N / 8; i++) // clang-format off - INVARIANT(i >= 0 && i <= MLKEM_N / 8) - INVARIANT(ARRAY_BOUND(r->coeffs, 0, (8 * i - 1), 0, (MLKEM_Q - 1))) - { // clang-format on - for (int j = 0; j < 8; j++) // clang-format off - INVARIANT(i >= 0 && i < MLKEM_N / 8 && j >= 0 && j <= 8) - INVARIANT(ARRAY_BOUND(r->coeffs, 0, (8 * i + j - 1), 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); - } + for (int i = 0; i < MLKEM_N / 8; i++) + __loop__( + invariant(i >= 0 && i <= MLKEM_N / 8) + invariant(array_bound(r->coeffs, 0, (8 * i - 1), 0, (MLKEM_Q - 1)))) + { + for (int j = 0; j < 8; j++) + __loop__( + invariant(i >= 0 && i < MLKEM_N / 8 && j >= 0 && j <= 8) + invariant(array_bound(r->coeffs, 0, (8 * i + j - 1), 0, (MLKEM_Q - 1)))) + { + 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"); } -void poly_tomsg(uint8_t msg[MLKEM_INDCPA_MSGBYTES], const poly *a) { +void poly_tomsg(uint8_t msg[MLKEM_INDCPA_MSGBYTES], const poly *a) +{ POLY_UBOUND(a, MLKEM_Q); - for (int i = 0; i < MLKEM_N / 8; i++) // clang-format off - INVARIANT(i >= 0 && i <= MLKEM_N / 8) - { // clang-format on - msg[i] = 0; - for (int j = 0; j < 8; j++) // clang-format off - INVARIANT(i >= 0 && i <= MLKEM_N / 8 && j >= 0 && j <= 8) - { // clang-format on - uint32_t t = scalar_compress_d1(a->coeffs[8 * i + j]); - msg[i] |= t << j; - } + for (int i = 0; i < MLKEM_N / 8; i++) + __loop__(invariant(i >= 0 && i <= MLKEM_N / 8)) + { + msg[i] = 0; + for (int j = 0; j < 8; j++) + __loop__( + invariant(i >= 0 && i <= MLKEM_N / 8 && j >= 0 && j <= 8)) + { + uint32_t t = scalar_compress_d1(a->coeffs[8 * i + j]); + msg[i] |= t << j; } + } } void poly_getnoise_eta1_4x(poly *r0, poly *r1, poly *r2, poly *r3, const uint8_t seed[MLKEM_SYMBYTES], uint8_t nonce0, - uint8_t nonce1, uint8_t nonce2, uint8_t nonce3) { + uint8_t nonce1, uint8_t nonce2, uint8_t nonce3) +{ ALIGN uint8_t buf[KECCAK_WAY][MLKEM_ETA1 * MLKEM_N / 4]; ALIGN uint8_t extkey[KECCAK_WAY][MLKEM_SYMBYTES + 1]; memcpy(extkey[0], seed, MLKEM_SYMBYTES); @@ -349,7 +372,8 @@ void poly_getnoise_eta1_4x(poly *r0, poly *r1, poly *r2, poly *r3, } void poly_getnoise_eta2(poly *r, const uint8_t seed[MLKEM_SYMBYTES], - uint8_t nonce) { + uint8_t nonce) +{ ALIGN uint8_t buf[MLKEM_ETA2 * MLKEM_N / 4]; prf(buf, sizeof(buf), seed, nonce); poly_cbd_eta2(r, buf); @@ -360,7 +384,8 @@ void poly_getnoise_eta2(poly *r, const uint8_t seed[MLKEM_SYMBYTES], void poly_getnoise_eta1122_4x(poly *r0, poly *r1, poly *r2, poly *r3, const uint8_t seed[MLKEM_SYMBYTES], uint8_t nonce0, uint8_t nonce1, uint8_t nonce2, - uint8_t nonce3) { + uint8_t nonce3) +{ ALIGN uint8_t buf1[KECCAK_WAY / 2][MLKEM_ETA1 * MLKEM_N / 4]; ALIGN uint8_t buf2[KECCAK_WAY / 2][MLKEM_ETA2 * MLKEM_N / 4]; ALIGN uint8_t extkey[KECCAK_WAY][MLKEM_SYMBYTES + 1]; @@ -395,97 +420,111 @@ void poly_getnoise_eta1122_4x(poly *r0, poly *r1, poly *r2, poly *r3, } void poly_basemul_montgomery_cached(poly *r, const poly *a, const poly *b, - const poly_mulcache *b_cache) { + const poly_mulcache *b_cache) +{ int i; - for (i = 0; i < MLKEM_N / 4; i++) // clang-format off - ASSIGNS(i, OBJECT_WHOLE(r)) - INVARIANT(i >= 0 && i <= MLKEM_N / 4) - INVARIANT(ARRAY_ABS_BOUND(r->coeffs, 0, (4 * i - 1), (3 * HALF_Q - 1))) - { // clang-format on - basemul_cached(&r->coeffs[4 * i], &a->coeffs[4 * i], &b->coeffs[4 * i], - b_cache->coeffs[2 * i]); - basemul_cached(&r->coeffs[4 * i + 2], &a->coeffs[4 * i + 2], - &b->coeffs[4 * i + 2], b_cache->coeffs[2 * i + 1]); - } + for (i = 0; i < MLKEM_N / 4; i++) + __loop__( + assigns(i, object_whole(r)) + invariant(i >= 0 && i <= MLKEM_N / 4) + invariant(array_abs_bound(r->coeffs, 0, (4 * i - 1), (3 * HALF_Q - 1)))) + { + basemul_cached(&r->coeffs[4 * i], &a->coeffs[4 * i], &b->coeffs[4 * i], + b_cache->coeffs[2 * i]); + basemul_cached(&r->coeffs[4 * i + 2], &a->coeffs[4 * i + 2], + &b->coeffs[4 * i + 2], b_cache->coeffs[2 * i + 1]); + } } #if !defined(MLKEM_USE_NATIVE_POLY_TOMONT) -void poly_tomont(poly *r) { +void poly_tomont(poly *r) +{ int i; - const int16_t f = (1ULL << 32) % MLKEM_Q; // 1353 - for (i = 0; i < MLKEM_N; i++) // clang-format off - INVARIANT(i >= 0 && i <= MLKEM_N) - INVARIANT(ARRAY_ABS_BOUND(r->coeffs ,0, (i - 1), (MLKEM_Q - 1))) - { // clang-format on - r->coeffs[i] = fqmul(r->coeffs[i], f); - } + const int16_t f = (1ULL << 32) % MLKEM_Q; // 1353 + for (i = 0; i < MLKEM_N; i++) + __loop__( + invariant(i >= 0 && i <= MLKEM_N) + invariant(array_abs_bound(r->coeffs ,0, (i - 1), (MLKEM_Q - 1)))) + { + r->coeffs[i] = fqmul(r->coeffs[i], f); + } POLY_BOUND(r, MLKEM_Q); } #else /* MLKEM_USE_NATIVE_POLY_TOMONT */ -void poly_tomont(poly *r) { +void poly_tomont(poly *r) +{ poly_tomont_native(r); POLY_BOUND(r, MLKEM_Q); } #endif /* MLKEM_USE_NATIVE_POLY_TOMONT */ #if !defined(MLKEM_USE_NATIVE_POLY_REDUCE) -void poly_reduce(poly *r) { +void poly_reduce(poly *r) +{ int i; - for (i = 0; i < MLKEM_N; i++) // clang-format off - INVARIANT(i >= 0 && i <= MLKEM_N) - INVARIANT(ARRAY_BOUND(r->coeffs, 0, (i - 1), 0, (MLKEM_Q - 1))) - { // clang-format on - // Barrett reduction, giving signed canonical representative - int16_t t = barrett_reduce(r->coeffs[i]); - // Conditional addition to get unsigned canonical representative - r->coeffs[i] = scalar_signed_to_unsigned_q(t); - } + for (i = 0; i < MLKEM_N; i++) + __loop__( + invariant(i >= 0 && i <= MLKEM_N) + invariant(array_bound(r->coeffs, 0, (i - 1), 0, (MLKEM_Q - 1)))) + { + // Barrett reduction, giving signed canonical representative + int16_t t = barrett_reduce(r->coeffs[i]); + // Conditional addition to get unsigned canonical representative + r->coeffs[i] = scalar_signed_to_unsigned_q(t); + } POLY_UBOUND(r, MLKEM_Q); } #else /* MLKEM_USE_NATIVE_POLY_REDUCE */ -void poly_reduce(poly *r) { +void poly_reduce(poly *r) +{ poly_reduce_native(r); POLY_UBOUND(r, MLKEM_Q); } #endif /* MLKEM_USE_NATIVE_POLY_REDUCE */ -void poly_add(poly *r, const poly *b) { +void poly_add(poly *r, const poly *b) +{ int i; - for (i = 0; i < MLKEM_N; i++) // clang-format off - INVARIANT(i >= 0 && i <= MLKEM_N) - INVARIANT(FORALL(int, k0, i, MLKEM_N - 1, r->coeffs[k0] == LOOP_ENTRY(*r).coeffs[k0])) - INVARIANT(FORALL(int, k1, 0, i - 1, r->coeffs[k1] == LOOP_ENTRY(*r).coeffs[k1] + b->coeffs[k1])) - { // clang-format on - r->coeffs[i] = r->coeffs[i] + b->coeffs[i]; - } + for (i = 0; i < MLKEM_N; i++) + __loop__( + invariant(i >= 0 && i <= MLKEM_N) + invariant(forall(int, k0, i, MLKEM_N - 1, r->coeffs[k0] == loop_entry(*r).coeffs[k0])) + invariant(forall(int, k1, 0, i - 1, r->coeffs[k1] == loop_entry(*r).coeffs[k1] + b->coeffs[k1]))) + { + r->coeffs[i] = r->coeffs[i] + b->coeffs[i]; + } } -void poly_sub(poly *r, const poly *b) { +void poly_sub(poly *r, const poly *b) +{ int i; - for (i = 0; i < MLKEM_N; i++) // clang-format off - INVARIANT(i >= 0 && i <= MLKEM_N) - INVARIANT(FORALL(int, k0, i, MLKEM_N - 1, r->coeffs[k0] == LOOP_ENTRY(*r).coeffs[k0])) - INVARIANT(FORALL(int, k1, 0, i - 1, r->coeffs[k1] == LOOP_ENTRY(*r).coeffs[k1] - b->coeffs[k1])) - { // clang-format on - r->coeffs[i] = r->coeffs[i] - b->coeffs[i]; - } + for (i = 0; i < MLKEM_N; i++) + __loop__( + invariant(i >= 0 && i <= MLKEM_N) + invariant(forall(int, k0, i, MLKEM_N - 1, r->coeffs[k0] == loop_entry(*r).coeffs[k0])) + invariant(forall(int, k1, 0, i - 1, r->coeffs[k1] == loop_entry(*r).coeffs[k1] - b->coeffs[k1]))) + { + r->coeffs[i] = r->coeffs[i] - b->coeffs[i]; + } } #if !defined(MLKEM_USE_NATIVE_POLY_MULCACHE_COMPUTE) -void poly_mulcache_compute(poly_mulcache *x, const poly *a) { +void poly_mulcache_compute(poly_mulcache *x, const poly *a) +{ int i; - for (i = 0; i < MLKEM_N / 4; i++) // clang-format off - INVARIANT(i >= 0 && i <= MLKEM_N / 4) - { // clang-format on - x->coeffs[2 * i + 0] = fqmul(a->coeffs[4 * i + 1], zetas[64 + i]); - x->coeffs[2 * i + 1] = fqmul(a->coeffs[4 * i + 3], -zetas[64 + i]); - } + for (i = 0; i < MLKEM_N / 4; i++) + __loop__(invariant(i >= 0 && i <= MLKEM_N / 4)) + { + x->coeffs[2 * i + 0] = fqmul(a->coeffs[4 * i + 1], zetas[64 + i]); + x->coeffs[2 * i + 1] = fqmul(a->coeffs[4 * i + 3], -zetas[64 + i]); + } POLY_BOUND(x, MLKEM_Q); } #else /* MLKEM_USE_NATIVE_POLY_MULCACHE_COMPUTE */ -void poly_mulcache_compute(poly_mulcache *x, const poly *a) { +void poly_mulcache_compute(poly_mulcache *x, const poly *a) +{ poly_mulcache_compute_native(x, a); POLY_BOUND(x, MLKEM_Q); } diff --git a/mlkem/poly.h b/mlkem/poly.h index 3a05442f9..bf6f62507 100644 --- a/mlkem/poly.h +++ b/mlkem/poly.h @@ -20,7 +20,8 @@ * Elements of R_q = Z_q[X]/(X^n + 1). Represents polynomial * coeffs[0] + X*coeffs[1] + X^2*coeffs[2] + ... + X^{n-1}*coeffs[n-1] */ -typedef struct { +typedef struct +{ int16_t coeffs[MLKEM_N]; } ALIGN poly; @@ -30,7 +31,8 @@ typedef struct { */ // REF-CHANGE: This structure does not exist in the reference // implementation. -typedef struct { +typedef struct +{ int16_t coeffs[MLKEM_N >> 1]; } poly_mulcache; @@ -62,10 +64,11 @@ typedef struct { #pragma CPROVER check push #pragma CPROVER check disable "unsigned-overflow" #endif -static inline uint32_t scalar_compress_d1(uint16_t u) // clang-format off -REQUIRES(u <= MLKEM_Q - 1) -ENSURES(RETURN_VALUE < 2) -ENSURES(RETURN_VALUE == (((uint32_t)u * 2 + MLKEM_Q / 2) / MLKEM_Q) % 2) // clang-format on +static inline uint32_t scalar_compress_d1(uint16_t u) +__contract__( + requires(u <= MLKEM_Q - 1) + ensures(return_value < 2) + ensures(return_value == (((uint32_t)u * 2 + MLKEM_Q / 2) / MLKEM_Q) % 2) ) { uint32_t d0 = u << 1; d0 *= 645083; @@ -94,13 +97,14 @@ ENSURES(RETURN_VALUE == (((uint32_t)u * 2 + MLKEM_Q / 2) / MLKEM_Q) % 2) // cla #pragma CPROVER check push #pragma CPROVER check disable "unsigned-overflow" #endif -static inline uint32_t scalar_compress_d4(uint16_t u) // clang-format off -REQUIRES(u <= MLKEM_Q - 1) -ENSURES(RETURN_VALUE < 16) -ENSURES(RETURN_VALUE == (((uint32_t)u * 16 + MLKEM_Q / 2) / MLKEM_Q) % 16) -{ // clang-format on - uint32_t d0 = (uint32_t)u * 1290160; // 16 * round(2^28 / MLKEM_Q) - return (d0 + (1u << 27)) >> 28; // round(d0/2^28) +static inline uint32_t scalar_compress_d4(uint16_t u) +__contract__( + requires(u <= MLKEM_Q - 1) + ensures(return_value < 16) + ensures(return_value == (((uint32_t)u * 16 + MLKEM_Q / 2) / MLKEM_Q) % 16)) +{ + uint32_t d0 = (uint32_t)u * 1290160; // 16 * round(2^28 / MLKEM_Q) + return (d0 + (1u << 27)) >> 28; // round(d0/2^28) } #ifdef CBMC #pragma CPROVER check pop @@ -117,12 +121,11 @@ ENSURES(RETURN_VALUE == (((uint32_t)u * 16 + MLKEM_Q / 2) / MLKEM_Q) % 16) * Arguments: - u: Unsigned canonical modulus modulo 16 * to be decompressed. ************************************************************/ -static inline uint16_t scalar_decompress_d4(uint32_t u) // clang-format off -REQUIRES(0 <= u && u < 16) -ENSURES(RETURN_VALUE <= (MLKEM_Q - 1)) -{ // clang-format on - return ((u * MLKEM_Q) + 8) / 16; -} +static inline uint16_t scalar_decompress_d4(uint32_t u) +__contract__( + requires(0 <= u && u < 16) + ensures(return_value <= (MLKEM_Q - 1)) +) { return ((u * MLKEM_Q) + 8) / 16; } /************************************************************ * Name: scalar_compress_d5 @@ -141,10 +144,11 @@ ENSURES(RETURN_VALUE <= (MLKEM_Q - 1)) #pragma CPROVER check push #pragma CPROVER check disable "unsigned-overflow" #endif -static inline uint32_t scalar_compress_d5(uint16_t u) // clang-format off -REQUIRES(u <= MLKEM_Q - 1) -ENSURES(RETURN_VALUE < 32) -ENSURES(RETURN_VALUE == (((uint32_t)u * 32 + MLKEM_Q / 2) / MLKEM_Q) % 32) // clang-format on +static inline uint32_t scalar_compress_d5(uint16_t u) +__contract__( + requires(u <= MLKEM_Q - 1) + ensures(return_value < 32) + ensures(return_value == (((uint32_t)u * 32 + MLKEM_Q / 2) / MLKEM_Q) % 32) ) { uint32_t d0 = (uint32_t)u * 1290176; // 2^5 * round(2^27 / MLKEM_Q) return (d0 + (1u << 26)) >> 27; // round(d0/2^27) @@ -164,12 +168,11 @@ ENSURES(RETURN_VALUE == (((uint32_t)u * 32 + MLKEM_Q / 2) / MLKEM_Q) % 32) // c * Arguments: - u: Unsigned canonical modulus modulo 32 * to be decompressed. ************************************************************/ -static inline uint16_t scalar_decompress_d5(uint32_t u) // clang-format off -REQUIRES(0 <= u && u < 32) -ENSURES(RETURN_VALUE <= MLKEM_Q - 1) -{ // clang-format on - return ((u * MLKEM_Q) + 16) / 32; -} +static inline uint16_t scalar_decompress_d5(uint32_t u) +__contract__( + requires(0 <= u && u < 32) + ensures(return_value <= MLKEM_Q - 1) +) { return ((u * MLKEM_Q) + 16) / 32; } /************************************************************ * Name: scalar_compress_d10 @@ -190,11 +193,12 @@ ENSURES(RETURN_VALUE <= MLKEM_Q - 1) #endif // TODO: do the same for the other static inline functions STATIC_INLINE_TESTABLE -uint32_t scalar_compress_d10(uint16_t u) // clang-format off -REQUIRES(u <= MLKEM_Q - 1) -ENSURES(RETURN_VALUE < (1u << 10)) -ENSURES(RETURN_VALUE == (((uint32_t)u * (1u << 10) + MLKEM_Q / 2) / MLKEM_Q) % (1 << 10)) -{ // clang-format on +uint32_t scalar_compress_d10(uint16_t u) +__contract__( + requires(u <= MLKEM_Q - 1) + ensures(return_value < (1u << 10)) + ensures(return_value == (((uint32_t)u * (1u << 10) + MLKEM_Q / 2) / MLKEM_Q) % (1 << 10))) +{ uint64_t d0 = (uint64_t)u * 2642263040; // 2^10 * round(2^32 / MLKEM_Q) d0 = (d0 + ((uint64_t)1u << 32)) >> 33; return (d0 & 0x3FF); @@ -214,12 +218,11 @@ ENSURES(RETURN_VALUE == (((uint32_t)u * (1u << 10) + MLKEM_Q / 2) / MLKEM_Q) % ( * Arguments: - u: Unsigned canonical modulus modulo 16 * to be decompressed. ************************************************************/ -static inline uint16_t scalar_decompress_d10(uint32_t u) // clang-format off -REQUIRES(0 <= u && u < 1024) -ENSURES(RETURN_VALUE <= (MLKEM_Q - 1)) -{ // clang-format on - return ((u * MLKEM_Q) + 512) / 1024; -} +static inline uint16_t scalar_decompress_d10(uint32_t u) +__contract__( + requires(0 <= u && u < 1024) + ensures(return_value <= (MLKEM_Q - 1)) +) { return ((u * MLKEM_Q) + 512) / 1024; } /************************************************************ * Name: scalar_compress_d11 @@ -239,11 +242,12 @@ ENSURES(RETURN_VALUE <= (MLKEM_Q - 1)) #pragma CPROVER check disable "unsigned-overflow" #endif STATIC_INLINE_TESTABLE -uint32_t scalar_compress_d11(uint16_t u) // clang-format off -REQUIRES(u <= MLKEM_Q - 1) -ENSURES(RETURN_VALUE < (1u << 11)) -ENSURES(RETURN_VALUE == (((uint32_t)u * (1u << 11) + MLKEM_Q / 2) / MLKEM_Q) % (1 << 11)) -{ // clang-format on +uint32_t scalar_compress_d11(uint16_t u) +__contract__( + requires(u <= MLKEM_Q - 1) + ensures(return_value < (1u << 11)) + ensures(return_value == (((uint32_t)u * (1u << 11) + MLKEM_Q / 2) / MLKEM_Q) % (1 << 11))) +{ uint64_t d0 = (uint64_t)u * 5284526080; // 2^11 * round(2^33 / MLKEM_Q) d0 = (d0 + ((uint64_t)1u << 32)) >> 33; return (d0 & 0x7FF); @@ -264,12 +268,11 @@ ENSURES(RETURN_VALUE == (((uint32_t)u * (1u << 11) + MLKEM_Q / 2) / MLKEM_Q) % ( * to be decompressed. ************************************************************/ STATIC_INLINE_TESTABLE -uint16_t scalar_decompress_d11(uint32_t u) // clang-format off -REQUIRES(0 <= u && u < 2048) -ENSURES(RETURN_VALUE <= (MLKEM_Q - 1)) -{ // clang-format on - return ((u * MLKEM_Q) + 1024) / 2048; -} +uint16_t scalar_decompress_d11(uint32_t u) +__contract__( + requires(0 <= u && u < 2048) + ensures(return_value <= (MLKEM_Q - 1)) +) { return ((u * MLKEM_Q) + 1024) / 2048; } /************************************************************ * Name: scalar_signed_to_unsigned_q @@ -290,22 +293,22 @@ ENSURES(RETURN_VALUE <= (MLKEM_Q - 1)) * Arguments: c: signed coefficient to be converted ************************************************************/ STATIC_INLINE_TESTABLE -uint16_t scalar_signed_to_unsigned_q(int16_t c) // clang-format off -REQUIRES(c >= -(MLKEM_Q - 1) && c <= (MLKEM_Q - 1)) -ENSURES(RETURN_VALUE >= 0 && RETURN_VALUE <= (MLKEM_Q - 1)) -ENSURES(RETURN_VALUE == (int32_t)c + (((int32_t)c < 0) * MLKEM_Q)) -{ // clang-format on +uint16_t scalar_signed_to_unsigned_q(int16_t c) +__contract__( + requires(c >= -(MLKEM_Q - 1) && c <= (MLKEM_Q - 1)) + ensures(return_value >= 0 && return_value <= (MLKEM_Q - 1)) + ensures(return_value == (int32_t)c + (((int32_t)c < 0) * MLKEM_Q))) +{ // Add Q if c is negative, but in constant time cmov_int16(&c, c + MLKEM_Q, c < 0); - ASSERT(c >= 0, "scalar_signed_to_unsigned_q result lower bound"); - ASSERT(c < MLKEM_Q, "scalar_signed_to_unsigned_q result upper bound"); + cassert(c >= 0, "scalar_signed_to_unsigned_q result lower bound"); + cassert(c < MLKEM_Q, "scalar_signed_to_unsigned_q result upper bound"); // and therefore cast to uint16_t is safe. return (uint16_t)c; } - #define poly_compress_du MLKEM_NAMESPACE(poly_compress_du) /************************************************* * Name: poly_compress_du @@ -319,14 +322,13 @@ ENSURES(RETURN_VALUE == (int32_t)c + (((int32_t)c < 0) * MLKEM_Q)) * Coefficients must be unsigned canonical, * i.e. in [0,1,..,MLKEM_Q-1]. **************************************************/ -void poly_compress_du(uint8_t r[MLKEM_POLYCOMPRESSEDBYTES_DU], - const poly *a) // clang-format off -REQUIRES(IS_FRESH(r, MLKEM_POLYCOMPRESSEDBYTES_DU)) -REQUIRES(IS_FRESH(a, sizeof(poly))) -REQUIRES(ARRAY_BOUND(a->coeffs, 0, (MLKEM_N - 1), 0, (MLKEM_Q - 1))) -ASSIGNS(OBJECT_UPTO(r, MLKEM_POLYCOMPRESSEDBYTES_DU)); -// clang-format on - +void poly_compress_du(uint8_t r[MLKEM_POLYCOMPRESSEDBYTES_DU], const poly *a) +__contract__( + requires(memory_no_alias(r, MLKEM_POLYCOMPRESSEDBYTES_DU)) + requires(memory_no_alias(a, sizeof(poly))) + requires(array_bound(a->coeffs, 0, (MLKEM_N - 1), 0, (MLKEM_Q - 1))) + assigns(memory_slice(r, MLKEM_POLYCOMPRESSEDBYTES_DU)) +); #define poly_decompress_du MLKEM_NAMESPACE(poly_decompress_du) /************************************************* @@ -343,13 +345,13 @@ ASSIGNS(OBJECT_UPTO(r, MLKEM_POLYCOMPRESSEDBYTES_DU)); * (non-negative and smaller than MLKEM_Q). * **************************************************/ -void poly_decompress_du( - poly *r, const uint8_t a[MLKEM_POLYCOMPRESSEDBYTES_DU]) // clang-format off -REQUIRES(IS_FRESH(a, MLKEM_POLYCOMPRESSEDBYTES_DU)) -REQUIRES(IS_FRESH(r, sizeof(poly))) -ASSIGNS(OBJECT_UPTO(r, sizeof(poly))) -ENSURES(ARRAY_BOUND(r->coeffs, 0, (MLKEM_N - 1), 0, (MLKEM_Q - 1))); -// clang-format on +void poly_decompress_du(poly *r, const uint8_t a[MLKEM_POLYCOMPRESSEDBYTES_DU]) +__contract__( + requires(memory_no_alias(a, MLKEM_POLYCOMPRESSEDBYTES_DU)) + requires(memory_no_alias(r, sizeof(poly))) + assigns(memory_slice(r, sizeof(poly))) + ensures(array_bound(r->coeffs, 0, (MLKEM_N - 1), 0, (MLKEM_Q - 1))) +); #define poly_compress_dv MLKEM_NAMESPACE(poly_compress_dv) /************************************************* @@ -364,13 +366,13 @@ ENSURES(ARRAY_BOUND(r->coeffs, 0, (MLKEM_N - 1), 0, (MLKEM_Q - 1))); * Coefficients must be unsigned canonical, * i.e. in [0,1,..,MLKEM_Q-1]. **************************************************/ -void poly_compress_dv(uint8_t r[MLKEM_POLYCOMPRESSEDBYTES_DV], - const poly *a) // clang-format off -REQUIRES(IS_FRESH(r, MLKEM_POLYCOMPRESSEDBYTES_DV)) -REQUIRES(IS_FRESH(a, sizeof(poly))) -REQUIRES(ARRAY_BOUND(a->coeffs, 0, (MLKEM_N - 1), 0, (MLKEM_Q - 1))) -ASSIGNS(OBJECT_WHOLE(r)); -// clang-format on +void poly_compress_dv(uint8_t r[MLKEM_POLYCOMPRESSEDBYTES_DV], const poly *a) +__contract__( + requires(memory_no_alias(r, MLKEM_POLYCOMPRESSEDBYTES_DV)) + requires(memory_no_alias(a, sizeof(poly))) + requires(array_bound(a->coeffs, 0, (MLKEM_N - 1), 0, (MLKEM_Q - 1))) + assigns(object_whole(r)) +); #define poly_decompress_dv MLKEM_NAMESPACE(poly_decompress_dv) /************************************************* @@ -388,13 +390,13 @@ ASSIGNS(OBJECT_WHOLE(r)); * (non-negative and smaller than MLKEM_Q). * **************************************************/ -void poly_decompress_dv( - poly *r, const uint8_t a[MLKEM_POLYCOMPRESSEDBYTES_DV]) // clang-format off -REQUIRES(IS_FRESH(a, MLKEM_POLYCOMPRESSEDBYTES_DV)) -REQUIRES(IS_FRESH(r, sizeof(poly))) -ASSIGNS(OBJECT_WHOLE(r)) -ENSURES(ARRAY_BOUND(r->coeffs, 0, (MLKEM_N - 1), 0, (MLKEM_Q - 1))); -// clang-format on +void poly_decompress_dv(poly *r, const uint8_t a[MLKEM_POLYCOMPRESSEDBYTES_DV]) +__contract__( + requires(memory_no_alias(a, MLKEM_POLYCOMPRESSEDBYTES_DV)) + requires(memory_no_alias(r, sizeof(poly))) + assigns(object_whole(r)) + ensures(array_bound(r->coeffs, 0, (MLKEM_N - 1), 0, (MLKEM_Q - 1))) +); #define poly_tobytes MLKEM_NAMESPACE(poly_tobytes) /************************************************* @@ -411,13 +413,13 @@ ENSURES(ARRAY_BOUND(r->coeffs, 0, (MLKEM_N - 1), 0, (MLKEM_Q - 1))); * - r: pointer to output byte array * (of MLKEM_POLYBYTES bytes) **************************************************/ -void poly_tobytes(uint8_t r[MLKEM_POLYBYTES], - const poly *a) // clang-format off -REQUIRES(IS_FRESH(r, MLKEM_POLYBYTES)) -REQUIRES(IS_FRESH(a, sizeof(poly))) -REQUIRES(ARRAY_BOUND(a->coeffs, 0, (MLKEM_N - 1), 0, (MLKEM_Q - 1))) -ASSIGNS(OBJECT_WHOLE(r)); -// clang-format on +void poly_tobytes(uint8_t r[MLKEM_POLYBYTES], const poly *a) +__contract__( + requires(memory_no_alias(r, MLKEM_POLYBYTES)) + requires(memory_no_alias(a, sizeof(poly))) + requires(array_bound(a->coeffs, 0, (MLKEM_N - 1), 0, (MLKEM_Q - 1))) + assigns(object_whole(r)) +); #define poly_frombytes MLKEM_NAMESPACE(poly_frombytes) @@ -434,13 +436,13 @@ ASSIGNS(OBJECT_WHOLE(r)); * each coefficient unsigned and in the range * 0 .. 4095 **************************************************/ -void poly_frombytes(poly *r, - const uint8_t a[MLKEM_POLYBYTES]) // clang-format off -REQUIRES(IS_FRESH(a, MLKEM_POLYBYTES)) -REQUIRES(IS_FRESH(r, sizeof(poly))) -ASSIGNS(OBJECT_UPTO(r, sizeof(poly))) -ENSURES(ARRAY_BOUND(r->coeffs, 0, (MLKEM_N - 1), 0, 4095)); -// clang-format on +void poly_frombytes(poly *r, const uint8_t a[MLKEM_POLYBYTES]) +__contract__( + requires(memory_no_alias(a, MLKEM_POLYBYTES)) + requires(memory_no_alias(r, sizeof(poly))) + assigns(memory_slice(r, sizeof(poly))) + ensures(array_bound(r->coeffs, 0, (MLKEM_N - 1), 0, 4095)) +); #define poly_frommsg MLKEM_NAMESPACE(poly_frommsg) @@ -452,14 +454,13 @@ ENSURES(ARRAY_BOUND(r->coeffs, 0, (MLKEM_N - 1), 0, 4095)); * 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_BOUND(r->coeffs, 0, (MLKEM_N - 1), 0, (MLKEM_Q - 1))); -// clang-format on - +void poly_frommsg(poly *r, const uint8_t msg[MLKEM_INDCPA_MSGBYTES]) +__contract__( + requires(memory_no_alias(msg, MLKEM_INDCPA_MSGBYTES)) + requires(memory_no_alias(r, sizeof(poly))) + assigns(object_whole(r)) + ensures(array_bound(r->coeffs, 0, (MLKEM_N - 1), 0, (MLKEM_Q - 1))) +); #define poly_tomsg MLKEM_NAMESPACE(poly_tomsg) /************************************************* @@ -471,15 +472,13 @@ ENSURES(ARRAY_BOUND(r->coeffs, 0, (MLKEM_N - 1), 0, (MLKEM_Q - 1))); * - const poly *r: pointer to input polynomial * Coefficients must be unsigned canonical **************************************************/ -void poly_tomsg(uint8_t msg[MLKEM_INDCPA_MSGBYTES], - const poly *r) // clang-format off -REQUIRES(IS_FRESH(msg, MLKEM_INDCPA_MSGBYTES)) -REQUIRES(IS_FRESH(r, sizeof(poly))) -REQUIRES(ARRAY_BOUND(r->coeffs, 0, (MLKEM_N - 1), 0, (MLKEM_Q - 1))) -ASSIGNS(OBJECT_WHOLE(msg)); -// clang-format on - - +void poly_tomsg(uint8_t msg[MLKEM_INDCPA_MSGBYTES], const poly *r) +__contract__( + requires(memory_no_alias(msg, MLKEM_INDCPA_MSGBYTES)) + requires(memory_no_alias(r, sizeof(poly))) + requires(array_bound(r->coeffs, 0, (MLKEM_N - 1), 0, (MLKEM_Q - 1))) + assigns(object_whole(msg)) +); #define poly_getnoise_eta1_4x MLKEM_NAMESPACE(poly_getnoise_eta1_4x) /************************************************* @@ -496,37 +495,61 @@ ASSIGNS(OBJECT_WHOLE(msg)); **************************************************/ void poly_getnoise_eta1_4x(poly *r0, poly *r1, poly *r2, poly *r3, const uint8_t seed[MLKEM_SYMBYTES], uint8_t nonce0, - uint8_t nonce1, uint8_t nonce2, - uint8_t nonce3) // clang-format off -REQUIRES(IS_FRESH(seed, MLKEM_SYMBYTES)) + uint8_t nonce1, uint8_t nonce2, uint8_t nonce3) /* Depending on MLKEM_K, the pointers passed to this function belong - to the same objects, so we cannot use IS_FRESH for r0-r3. + to the same objects, so we cannot use memory_no_alias for r0-r3. - NOTE: Somehow it is important to use IS_FRESH() first in the - conjunctions defining each case. + NOTE: Somehow it is important to use memory_no_alias() first in the + conjunctions defining each case. */ #if MLKEM_K == 2 -REQUIRES( /* Case A: r0, r1 consecutive, r2, r3 consecutive */ - (IS_FRESH(r0, 2 * sizeof(poly)) && IS_FRESH(r2, 2 * sizeof(poly)) && - r1 == r0 + 1 && r3 == r2 + 1 && !SAME_OBJECT(r0, r2))) +__contract__( + requires(memory_no_alias(seed, MLKEM_SYMBYTES)) + requires( /* Case A: r0, r1 consecutive, r2, r3 consecutive */ + (memory_no_alias(r0, 2 * sizeof(poly)) && memory_no_alias(r2, 2 * sizeof(poly)) && + r1 == r0 + 1 && r3 == r2 + 1 && !same_object(r0, r2))) + assigns(memory_slice(r0, sizeof(poly))) + assigns(memory_slice(r1, sizeof(poly))) + assigns(memory_slice(r2, sizeof(poly))) + assigns(memory_slice(r3, sizeof(poly))) + ensures( + array_abs_bound(r0->coeffs,0, MLKEM_N - 1, MLKEM_ETA1) + && array_abs_bound(r1->coeffs,0, MLKEM_N - 1, MLKEM_ETA1) + && array_abs_bound(r2->coeffs,0, MLKEM_N - 1, MLKEM_ETA1) + && array_abs_bound(r3->coeffs,0, MLKEM_N - 1, MLKEM_ETA1)); +); #elif MLKEM_K == 4 -REQUIRES( /* Case B: r0, r1, r2, r3 consecutive */ - (IS_FRESH(r0, 4 * sizeof(poly)) && r1 == r0 + 1 && r2 == r0 + 2 && r3 == r0 + 3)) +__contract__( + requires(memory_no_alias(seed, MLKEM_SYMBYTES)) + requires( /* Case B: r0, r1, r2, r3 consecutive */ + (memory_no_alias(r0, 4 * sizeof(poly)) && r1 == r0 + 1 && r2 == r0 + 2 && r3 == r0 + 3)) + assigns(memory_slice(r0, sizeof(poly))) + assigns(memory_slice(r1, sizeof(poly))) + assigns(memory_slice(r2, sizeof(poly))) + assigns(memory_slice(r3, sizeof(poly))) + ensures( + array_abs_bound(r0->coeffs,0, MLKEM_N - 1, MLKEM_ETA1) + && array_abs_bound(r1->coeffs,0, MLKEM_N - 1, MLKEM_ETA1) + && array_abs_bound(r2->coeffs,0, MLKEM_N - 1, MLKEM_ETA1) + && array_abs_bound(r3->coeffs,0, MLKEM_N - 1, MLKEM_ETA1)); +); #elif MLKEM_K == 3 -REQUIRES( /* Case C: r0, r1, r2 consecutive */ - (IS_FRESH(r0, 3 * sizeof(poly)) && IS_FRESH(r3, 1 * sizeof(poly)) && - r1 == r0 + 1 && r2 == r0 + 2 && !SAME_OBJECT(r3, r0))) -#endif -ASSIGNS(OBJECT_UPTO(r0, sizeof(poly))) -ASSIGNS(OBJECT_UPTO(r1, sizeof(poly))) -ASSIGNS(OBJECT_UPTO(r2, sizeof(poly))) -ASSIGNS(OBJECT_UPTO(r3, sizeof(poly))) -ENSURES( - ARRAY_ABS_BOUND(r0->coeffs,0, MLKEM_N - 1, MLKEM_ETA1) - && ARRAY_ABS_BOUND(r1->coeffs,0, MLKEM_N - 1, MLKEM_ETA1) - && ARRAY_ABS_BOUND(r2->coeffs,0, MLKEM_N - 1, MLKEM_ETA1) - && ARRAY_ABS_BOUND(r3->coeffs,0, MLKEM_N - 1, MLKEM_ETA1)); -// clang-format on +__contract__( + requires(memory_no_alias(seed, MLKEM_SYMBYTES)) + requires( /* Case C: r0, r1, r2 consecutive */ + (memory_no_alias(r0, 3 * sizeof(poly)) && memory_no_alias(r3, 1 * sizeof(poly)) && + r1 == r0 + 1 && r2 == r0 + 2 && !same_object(r3, r0))) + assigns(memory_slice(r0, sizeof(poly))) + assigns(memory_slice(r1, sizeof(poly))) + assigns(memory_slice(r2, sizeof(poly))) + assigns(memory_slice(r3, sizeof(poly))) + ensures( + array_abs_bound(r0->coeffs,0, MLKEM_N - 1, MLKEM_ETA1) + && array_abs_bound(r1->coeffs,0, MLKEM_N - 1, MLKEM_ETA1) + && array_abs_bound(r2->coeffs,0, MLKEM_N - 1, MLKEM_ETA1) + && array_abs_bound(r3->coeffs,0, MLKEM_N - 1, MLKEM_ETA1)); +); +#endif /* MLKEM_K */ #if MLKEM_ETA1 == MLKEM_ETA2 // We only require poly_getnoise_eta2_4x for ml-kem-768 and ml-kem-1024 @@ -549,12 +572,13 @@ ENSURES( * - uint8_t nonce: one-byte input nonce **************************************************/ void poly_getnoise_eta2(poly *r, const uint8_t seed[MLKEM_SYMBYTES], - uint8_t nonce) // clang-format off -REQUIRES(IS_FRESH(r, sizeof(poly))) -REQUIRES(IS_FRESH(seed, MLKEM_SYMBYTES)) -ASSIGNS(OBJECT_WHOLE(r)) -ENSURES(ARRAY_ABS_BOUND(r->coeffs, 0, MLKEM_N - 1, MLKEM_ETA2)); -// clang-format on + uint8_t nonce) +__contract__( + requires(memory_no_alias(r, sizeof(poly))) + requires(memory_no_alias(seed, MLKEM_SYMBYTES)) + assigns(object_whole(r)) + ensures(array_abs_bound(r->coeffs, 0, MLKEM_N - 1, MLKEM_ETA2)) +); #define poly_getnoise_eta1122_4x MLKEM_NAMESPACE(poly_getnoise_eta1122_4x) /************************************************* @@ -572,17 +596,18 @@ ENSURES(ARRAY_ABS_BOUND(r->coeffs, 0, MLKEM_N - 1, MLKEM_ETA2)); void poly_getnoise_eta1122_4x(poly *r0, poly *r1, poly *r2, poly *r3, const uint8_t seed[MLKEM_SYMBYTES], uint8_t nonce0, uint8_t nonce1, uint8_t nonce2, - uint8_t nonce3) // clang-format off -REQUIRES( /* r0, r1 consecutive, r2, r3 consecutive */ - (IS_FRESH(r0, 2 * sizeof(poly)) && IS_FRESH(r2, 2 * sizeof(poly)) && - r1 == r0 + 1 && r3 == r2 + 1 && !SAME_OBJECT(r0, r2))) -REQUIRES(IS_FRESH(seed, MLKEM_SYMBYTES)) -ASSIGNS(OBJECT_WHOLE(r0), OBJECT_WHOLE(r1), OBJECT_WHOLE(r2), OBJECT_WHOLE(r3)) -ENSURES(ARRAY_ABS_BOUND(r0->coeffs,0, MLKEM_N - 1, MLKEM_ETA1) - && ARRAY_ABS_BOUND(r1->coeffs,0, MLKEM_N - 1, MLKEM_ETA1) - && ARRAY_ABS_BOUND(r2->coeffs,0, MLKEM_N - 1, MLKEM_ETA2) - && ARRAY_ABS_BOUND(r3->coeffs,0, MLKEM_N - 1, MLKEM_ETA2)); -// clang-format on + uint8_t nonce3) +__contract__( + requires( /* r0, r1 consecutive, r2, r3 consecutive */ + (memory_no_alias(r0, 2 * sizeof(poly)) && memory_no_alias(r2, 2 * sizeof(poly)) && + r1 == r0 + 1 && r3 == r2 + 1 && !same_object(r0, r2))) + requires(memory_no_alias(seed, MLKEM_SYMBYTES)) + assigns(object_whole(r0), object_whole(r1), object_whole(r2), object_whole(r3)) + ensures(array_abs_bound(r0->coeffs,0, MLKEM_N - 1, MLKEM_ETA1) + && array_abs_bound(r1->coeffs,0, MLKEM_N - 1, MLKEM_ETA1) + && array_abs_bound(r2->coeffs,0, MLKEM_N - 1, MLKEM_ETA2) + && array_abs_bound(r3->coeffs,0, MLKEM_N - 1, MLKEM_ETA2)); +); #define poly_basemul_montgomery_cached \ MLKEM_NAMESPACE(poly_basemul_montgomery_cached) @@ -605,18 +630,17 @@ ENSURES(ARRAY_ABS_BOUND(r0->coeffs,0, MLKEM_N - 1, MLKEM_ETA1) * for second input polynomial. Can be computed * via poly_mulcache_compute(). **************************************************/ - -void poly_basemul_montgomery_cached( - poly *r, const poly *a, const poly *b, - const poly_mulcache *b_cache) // clang-format off -REQUIRES(IS_FRESH(r, sizeof(poly))) -REQUIRES(IS_FRESH(a, sizeof(poly))) -REQUIRES(IS_FRESH(b, sizeof(poly))) -REQUIRES(IS_FRESH(b_cache, sizeof(poly_mulcache))) -REQUIRES(ARRAY_ABS_BOUND(a->coeffs, 0, MLKEM_N - 1, (MLKEM_Q - 1))) -ASSIGNS(OBJECT_WHOLE(r)) -ENSURES(ARRAY_ABS_BOUND(r->coeffs, 0, MLKEM_N - 1, (3 * HALF_Q - 1))); -// clang-format on +void poly_basemul_montgomery_cached(poly *r, const poly *a, const poly *b, + const poly_mulcache *b_cache) +__contract__( + requires(memory_no_alias(r, sizeof(poly))) + requires(memory_no_alias(a, sizeof(poly))) + requires(memory_no_alias(b, sizeof(poly))) + requires(memory_no_alias(b_cache, sizeof(poly_mulcache))) + requires(array_abs_bound(a->coeffs, 0, MLKEM_N - 1, (MLKEM_Q - 1))) + assigns(object_whole(r)) + ensures(array_abs_bound(r->coeffs, 0, MLKEM_N - 1, (3 * HALF_Q - 1))) +); #define poly_tomont MLKEM_NAMESPACE(poly_tomont) /************************************************* @@ -629,11 +653,12 @@ ENSURES(ARRAY_ABS_BOUND(r->coeffs, 0, MLKEM_N - 1, (3 * HALF_Q - 1))); * * Arguments: - poly *r: pointer to input/output polynomial **************************************************/ -void poly_tomont(poly *r) // clang-format off -REQUIRES(IS_FRESH(r, sizeof(poly))) -ASSIGNS(OBJECT_UPTO(r, sizeof(poly))) -ENSURES(ARRAY_ABS_BOUND(r->coeffs, 0, MLKEM_N - 1, (MLKEM_Q - 1))); -// clang-format on +void poly_tomont(poly *r) +__contract__( + requires(memory_no_alias(r, sizeof(poly))) + assigns(memory_slice(r, sizeof(poly))) + ensures(array_abs_bound(r->coeffs, 0, MLKEM_N - 1, (MLKEM_Q - 1))) +); // REF-CHANGE: This function does not exist in the reference implementation #define poly_mulcache_compute MLKEM_NAMESPACE(poly_mulcache_compute) @@ -657,11 +682,12 @@ ENSURES(ARRAY_ABS_BOUND(r->coeffs, 0, MLKEM_N - 1, (MLKEM_Q - 1))); // NOTE: The default C implementation of this function populates // the mulcache with values in (-q,q), but this is not needed for the // higher level safety proofs, and thus not part of the spec. -void poly_mulcache_compute(poly_mulcache *x, const poly *a) // clang-format off -REQUIRES(IS_FRESH(x, sizeof(poly_mulcache))) -REQUIRES(IS_FRESH(a, sizeof(poly))) -ASSIGNS(OBJECT_WHOLE(x)); -// clang-format on +void poly_mulcache_compute(poly_mulcache *x, const poly *a) +__contract__( + requires(memory_no_alias(x, sizeof(poly_mulcache))) + requires(memory_no_alias(a, sizeof(poly))) + assigns(object_whole(x)) +); #define poly_reduce MLKEM_NAMESPACE(poly_reduce) /************************************************* @@ -679,11 +705,12 @@ ASSIGNS(OBJECT_WHOLE(x)); // signed canonical output data. Unsigned canonical // outputs are better suited to the only remaining // use of poly_reduce() in the context of (de)serialization. -void poly_reduce(poly *r) // clang-format off -REQUIRES(IS_FRESH(r, sizeof(poly))) -ASSIGNS(OBJECT_UPTO(r, sizeof(poly))) -ENSURES(ARRAY_BOUND(r->coeffs, 0, MLKEM_N - 1, 0, (MLKEM_Q - 1))); -// clang-format on +void poly_reduce(poly *r) +__contract__( + requires(memory_no_alias(r, sizeof(poly))) + assigns(memory_slice(r, sizeof(poly))) + ensures(array_bound(r->coeffs, 0, MLKEM_N - 1, 0, (MLKEM_Q - 1))) +); #define poly_add MLKEM_NAMESPACE(poly_add) /************************************************************ @@ -702,14 +729,15 @@ ENSURES(ARRAY_BOUND(r->coeffs, 0, MLKEM_N - 1, 0, (MLKEM_Q - 1))); // REF-CHANGE: // The reference implementation uses a 3-argument poly_add. // We specialize to the accumulator form to avoid reasoning about aliasing. -void poly_add(poly *r, const poly *b) // clang-format off -REQUIRES(IS_FRESH(r, sizeof(poly))) -REQUIRES(IS_FRESH(b, sizeof(poly))) -REQUIRES(FORALL(int, k0, 0, MLKEM_N - 1, (int32_t) r->coeffs[k0] + b->coeffs[k0] <= INT16_MAX)) -REQUIRES(FORALL(int, k1, 0, MLKEM_N - 1, (int32_t) r->coeffs[k1] + b->coeffs[k1] >= INT16_MIN)) -ENSURES(FORALL(int, k, 0, MLKEM_N - 1, r->coeffs[k] == OLD(*r).coeffs[k] + b->coeffs[k])) -ASSIGNS(OBJECT_UPTO(r, sizeof(poly))); -// clang-format on +void poly_add(poly *r, const poly *b) +__contract__( + requires(memory_no_alias(r, sizeof(poly))) + requires(memory_no_alias(b, sizeof(poly))) + requires(forall(int, k0, 0, MLKEM_N - 1, (int32_t) r->coeffs[k0] + b->coeffs[k0] <= INT16_MAX)) + requires(forall(int, k1, 0, MLKEM_N - 1, (int32_t) r->coeffs[k1] + b->coeffs[k1] >= INT16_MIN)) + ensures(forall(int, k, 0, MLKEM_N - 1, r->coeffs[k] == old(*r).coeffs[k] + b->coeffs[k])) + assigns(memory_slice(r, sizeof(poly))) +); #define poly_sub MLKEM_NAMESPACE(poly_sub) /************************************************* @@ -724,13 +752,14 @@ ASSIGNS(OBJECT_UPTO(r, sizeof(poly))); // REF-CHANGE: // The reference implementation uses a 3-argument poly_sub. // We specialize to the accumulator form to avoid reasoning about aliasing. -void poly_sub(poly *r, const poly *b) // clang-format off -REQUIRES(IS_FRESH(r, sizeof(poly))) -REQUIRES(IS_FRESH(b, sizeof(poly))) -REQUIRES(FORALL(int, k0, 0, MLKEM_N - 1, (int32_t) r->coeffs[k0] - b->coeffs[k0] <= INT16_MAX)) -REQUIRES(FORALL(int, k1, 0, MLKEM_N - 1, (int32_t) r->coeffs[k1] - b->coeffs[k1] >= INT16_MIN)) -ENSURES(FORALL(int, k, 0, MLKEM_N - 1, r->coeffs[k] == OLD(*r).coeffs[k] - b->coeffs[k])) -ASSIGNS(OBJECT_WHOLE(r)); -// clang-format on +void poly_sub(poly *r, const poly *b) +__contract__( + requires(memory_no_alias(r, sizeof(poly))) + requires(memory_no_alias(b, sizeof(poly))) + requires(forall(int, k0, 0, MLKEM_N - 1, (int32_t) r->coeffs[k0] - b->coeffs[k0] <= INT16_MAX)) + requires(forall(int, k1, 0, MLKEM_N - 1, (int32_t) r->coeffs[k1] - b->coeffs[k1] >= INT16_MIN)) + ensures(forall(int, k, 0, MLKEM_N - 1, r->coeffs[k] == old(*r).coeffs[k] - b->coeffs[k])) + assigns(object_whole(r)) +); #endif diff --git a/mlkem/polyvec.c b/mlkem/polyvec.c index cd504271a..769d8d918 100644 --- a/mlkem/polyvec.c +++ b/mlkem/polyvec.c @@ -10,49 +10,61 @@ #include "debug/debug.h" void polyvec_compress_du(uint8_t r[MLKEM_POLYVECCOMPRESSEDBYTES_DU], - const polyvec *a) { + const polyvec *a) +{ unsigned int i; POLYVEC_UBOUND(a, MLKEM_Q); - for (i = 0; i < MLKEM_K; i++) { + for (i = 0; i < MLKEM_K; i++) + { poly_compress_du(r + i * MLKEM_POLYCOMPRESSEDBYTES_DU, &a->vec[i]); } } void polyvec_decompress_du(polyvec *r, - const uint8_t a[MLKEM_POLYVECCOMPRESSEDBYTES_DU]) { + const uint8_t a[MLKEM_POLYVECCOMPRESSEDBYTES_DU]) +{ unsigned int i; - for (i = 0; i < MLKEM_K; i++) { + for (i = 0; i < MLKEM_K; i++) + { poly_decompress_du(&r->vec[i], a + i * MLKEM_POLYCOMPRESSEDBYTES_DU); } POLYVEC_UBOUND(r, MLKEM_Q); } -void polyvec_tobytes(uint8_t r[MLKEM_POLYVECBYTES], const polyvec *a) { +void polyvec_tobytes(uint8_t r[MLKEM_POLYVECBYTES], const polyvec *a) +{ unsigned int i; - for (i = 0; i < MLKEM_K; i++) { + for (i = 0; i < MLKEM_K; i++) + { poly_tobytes(r + i * MLKEM_POLYBYTES, &a->vec[i]); } } -void polyvec_frombytes(polyvec *r, const uint8_t a[MLKEM_POLYVECBYTES]) { +void polyvec_frombytes(polyvec *r, const uint8_t a[MLKEM_POLYVECBYTES]) +{ int i; - for (i = 0; i < MLKEM_K; i++) { + for (i = 0; i < MLKEM_K; i++) + { poly_frombytes(&r->vec[i], a + i * MLKEM_POLYBYTES); } } -void polyvec_ntt(polyvec *r) { +void polyvec_ntt(polyvec *r) +{ unsigned int i; - for (i = 0; i < MLKEM_K; i++) { + for (i = 0; i < MLKEM_K; i++) + { poly_ntt(&r->vec[i]); } } -void polyvec_invntt_tomont(polyvec *r) { +void polyvec_invntt_tomont(polyvec *r) +{ unsigned int i; - for (i = 0; i < MLKEM_K; i++) { + for (i = 0; i < MLKEM_K; i++) + { poly_invntt_tomont(&r->vec[i]); } } @@ -78,7 +90,8 @@ void polyvec_invntt_tomont(polyvec *r) { #if !defined(MLKEM_USE_NATIVE_POLYVEC_BASEMUL_ACC_MONTGOMERY_CACHED) void polyvec_basemul_acc_montgomery_cached(poly *r, const polyvec *a, const polyvec *b, - const polyvec_mulcache *b_cache) { + const polyvec_mulcache *b_cache) +{ POLYVEC_BOUND(a, MLKEM_Q); POLYVEC_BOUND(b, NTT_BOUND); POLYVEC_BOUND(b_cache, MLKEM_Q); @@ -87,7 +100,8 @@ void polyvec_basemul_acc_montgomery_cached(poly *r, const polyvec *a, poly t; poly_basemul_montgomery_cached(r, &a->vec[0], &b->vec[0], &b_cache->vec[0]); - for (i = 1; i < MLKEM_K; i++) { + for (i = 1; i < MLKEM_K; i++) + { poly_basemul_montgomery_cached(&t, &a->vec[i], &b->vec[i], &b_cache->vec[i]); poly_add(r, &t); @@ -97,15 +111,17 @@ void polyvec_basemul_acc_montgomery_cached(poly *r, const polyvec *a, // Those bounds are true for the C implementation, but not needed // in the higher level bounds reasoning. It is thus best to omit // them from the spec to not unnecessarily constraint native implementations. - ASSERT(ARRAY_ABS_BOUND(r->coeffs, 0, MLKEM_N - 1, MLKEM_K * (3 * HALF_Q - 1)), - "polyvec_basemul_acc_montgomery_cached output bounds"); + cassert( + array_abs_bound(r->coeffs, 0, MLKEM_N - 1, MLKEM_K * (3 * HALF_Q - 1)), + "polyvec_basemul_acc_montgomery_cached output bounds"); // TODO: Integrate CBMC assertion into POLY_BOUND if CBMC is set POLY_BOUND(r, MLKEM_K * 3 * HALF_Q); } #else /* !MLKEM_USE_NATIVE_POLYVEC_BASEMUL_ACC_MONTGOMERY_CACHED */ void polyvec_basemul_acc_montgomery_cached(poly *r, const polyvec *a, const polyvec *b, - const polyvec_mulcache *b_cache) { + const polyvec_mulcache *b_cache) +{ POLYVEC_BOUND(a, MLKEM_Q); POLYVEC_BOUND(b, NTT_BOUND); POLYVEC_BOUND(b_cache, MLKEM_Q); @@ -123,8 +139,8 @@ void polyvec_basemul_acc_montgomery_cached(poly *r, const polyvec *a, * - const polyvec *a: pointer to first input vector of polynomials * - const polyvec *b: pointer to second input vector of polynomials **************************************************/ -void polyvec_basemul_acc_montgomery(poly *r, const polyvec *a, - const polyvec *b) { +void polyvec_basemul_acc_montgomery(poly *r, const polyvec *a, const polyvec *b) +{ polyvec_mulcache b_cache; polyvec_mulcache_compute(&b_cache, b); polyvec_basemul_acc_montgomery_cached(r, a, b, &b_cache); @@ -140,9 +156,11 @@ void polyvec_basemul_acc_montgomery(poly *r, const polyvec *a, * Arguments: - polyvec_mulcache *x: pointer to output cache. * - const poly *a: pointer to input polynomial **************************************************/ -void polyvec_mulcache_compute(polyvec_mulcache *x, const polyvec *a) { +void polyvec_mulcache_compute(polyvec_mulcache *x, const polyvec *a) +{ unsigned int i; - for (i = 0; i < MLKEM_K; i++) { + for (i = 0; i < MLKEM_K; i++) + { poly_mulcache_compute(&x->vec[i], &a->vec[i]); } } @@ -157,23 +175,29 @@ void polyvec_mulcache_compute(polyvec_mulcache *x, const polyvec *a) { * * Arguments: - polyvec *r: pointer to input/output polynomial **************************************************/ -void polyvec_reduce(polyvec *r) { +void polyvec_reduce(polyvec *r) +{ unsigned int i; - for (i = 0; i < MLKEM_K; i++) { + for (i = 0; i < MLKEM_K; i++) + { poly_reduce(&r->vec[i]); } } -void polyvec_add(polyvec *r, const polyvec *b) { +void polyvec_add(polyvec *r, const polyvec *b) +{ int i; - for (i = 0; i < MLKEM_K; i++) { + for (i = 0; i < MLKEM_K; i++) + { poly_add(&r->vec[i], &b->vec[i]); } } -void polyvec_tomont(polyvec *r) { +void polyvec_tomont(polyvec *r) +{ unsigned int i; - for (i = 0; i < MLKEM_K; i++) { + for (i = 0; i < MLKEM_K; i++) + { poly_tomont(&r->vec[i]); } } diff --git a/mlkem/polyvec.h b/mlkem/polyvec.h index 8ec57bdad..1072aef91 100644 --- a/mlkem/polyvec.h +++ b/mlkem/polyvec.h @@ -7,12 +7,14 @@ #include "params.h" #include "poly.h" -typedef struct { +typedef struct +{ poly vec[MLKEM_K]; } ALIGN polyvec; // REF-CHANGE: This struct does not exist in the reference implementation -typedef struct { +typedef struct +{ poly_mulcache vec[MLKEM_K]; } polyvec_mulcache; @@ -29,13 +31,14 @@ typedef struct { * i.e. in [0,1,..,MLKEM_Q-1]. **************************************************/ void polyvec_compress_du(uint8_t r[MLKEM_POLYVECCOMPRESSEDBYTES_DU], - const polyvec *a) // clang-format off -REQUIRES(IS_FRESH(r, MLKEM_POLYVECCOMPRESSEDBYTES_DU)) -REQUIRES(IS_FRESH(a, sizeof(polyvec))) -REQUIRES(FORALL(int, k0, 0, MLKEM_K - 1, - ARRAY_BOUND(a->vec[k0].coeffs, 0, (MLKEM_N - 1), 0, (MLKEM_Q - 1)))) -ASSIGNS(OBJECT_WHOLE(r)); -// clang-format on + const polyvec *a) +__contract__( + requires(memory_no_alias(r, MLKEM_POLYVECCOMPRESSEDBYTES_DU)) + requires(memory_no_alias(a, sizeof(polyvec))) + requires(forall(int, k0, 0, MLKEM_K - 1, + array_bound(a->vec[k0].coeffs, 0, (MLKEM_N - 1), 0, (MLKEM_Q - 1)))) + assigns(object_whole(r)) +); #define polyvec_decompress_du MLKEM_NAMESPACE(polyvec_decompress_du) /************************************************* @@ -49,15 +52,15 @@ ASSIGNS(OBJECT_WHOLE(r)); * - const uint8_t *a: pointer to input byte array * (of length MLKEM_POLYVECCOMPRESSEDBYTES_DU) **************************************************/ -void polyvec_decompress_du( - polyvec *r, - const uint8_t a[MLKEM_POLYVECCOMPRESSEDBYTES_DU]) // clang-format off -REQUIRES(IS_FRESH(a, MLKEM_POLYVECCOMPRESSEDBYTES_DU)) -REQUIRES(IS_FRESH(r, sizeof(polyvec))) -ASSIGNS(OBJECT_WHOLE(r)) -ENSURES(FORALL(int, k0, 0, MLKEM_K - 1, - ARRAY_BOUND(r->vec[k0].coeffs, 0, (MLKEM_N - 1), 0, (MLKEM_Q - 1)))); -// clang-format on +void polyvec_decompress_du(polyvec *r, + const uint8_t a[MLKEM_POLYVECCOMPRESSEDBYTES_DU]) +__contract__( + requires(memory_no_alias(a, MLKEM_POLYVECCOMPRESSEDBYTES_DU)) + requires(memory_no_alias(r, sizeof(polyvec))) + assigns(object_whole(r)) + ensures(forall(int, k0, 0, MLKEM_K - 1, + array_bound(r->vec[k0].coeffs, 0, (MLKEM_N - 1), 0, (MLKEM_Q - 1)))) +); #define polyvec_tobytes MLKEM_NAMESPACE(polyvec_tobytes) /************************************************* @@ -70,14 +73,14 @@ ENSURES(FORALL(int, k0, 0, MLKEM_K - 1, * - const polyvec *a: pointer to input vector of polynomials * Each polynomial must have coefficients in [0,..,q-1]. **************************************************/ -void polyvec_tobytes(uint8_t r[MLKEM_POLYVECBYTES], - const polyvec *a) // clang-format off -REQUIRES(IS_FRESH(a, sizeof(polyvec))) -REQUIRES(IS_FRESH(r, MLKEM_POLYVECBYTES)) -REQUIRES(FORALL(int, k0, 0, MLKEM_K - 1, - ARRAY_BOUND(a->vec[k0].coeffs, 0, (MLKEM_N - 1), 0, (MLKEM_Q - 1)))) -ASSIGNS(OBJECT_WHOLE(r)); -// clang-format on +void polyvec_tobytes(uint8_t r[MLKEM_POLYVECBYTES], const polyvec *a) +__contract__( + requires(memory_no_alias(a, sizeof(polyvec))) + requires(memory_no_alias(r, MLKEM_POLYVECBYTES)) + requires(forall(int, k0, 0, MLKEM_K - 1, + array_bound(a->vec[k0].coeffs, 0, (MLKEM_N - 1), 0, (MLKEM_Q - 1)))) + assigns(object_whole(r)) +); #define polyvec_frombytes MLKEM_NAMESPACE(polyvec_frombytes) /************************************************* @@ -91,14 +94,14 @@ ASSIGNS(OBJECT_WHOLE(r)); * normalized to [0,..,q-1]. * - uint8_t *r: pointer to input byte array **************************************************/ -void polyvec_frombytes(polyvec *r, - const uint8_t a[MLKEM_POLYVECBYTES]) // clang-format off -REQUIRES(IS_FRESH(r, sizeof(polyvec))) -REQUIRES(IS_FRESH(a, MLKEM_POLYVECBYTES)) -ASSIGNS(OBJECT_WHOLE(r)) -ENSURES(FORALL(int, k0, 0, MLKEM_K - 1, - ARRAY_BOUND(r->vec[k0].coeffs, 0, (MLKEM_N - 1), 0, 4095))); -// clang-format on +void polyvec_frombytes(polyvec *r, const uint8_t a[MLKEM_POLYVECBYTES]) +__contract__( + requires(memory_no_alias(r, sizeof(polyvec))) + requires(memory_no_alias(a, MLKEM_POLYVECBYTES)) + assigns(object_whole(r)) + ensures(forall(int, k0, 0, MLKEM_K - 1, + array_bound(r->vec[k0].coeffs, 0, (MLKEM_N - 1), 0, 4095))) +); #define polyvec_ntt MLKEM_NAMESPACE(polyvec_ntt) /************************************************* @@ -115,14 +118,15 @@ ENSURES(FORALL(int, k0, 0, MLKEM_K - 1, * Arguments: - polyvec *r: pointer to in/output vector of polynomials * **************************************************/ -void polyvec_ntt(polyvec *r) // clang-format off -REQUIRES(IS_FRESH(r, sizeof(polyvec))) -REQUIRES(FORALL(int, j, 0, MLKEM_K - 1, - ARRAY_ABS_BOUND(r->vec[j].coeffs, 0, MLKEM_N - 1, (MLKEM_Q - 1)))) -ASSIGNS(OBJECT_WHOLE(r)) -ENSURES(FORALL(int, j, 0, MLKEM_K - 1, - ARRAY_ABS_BOUND(r->vec[j].coeffs, 0, MLKEM_N - 1, (NTT_BOUND - 1)))); -// clang-format on +void polyvec_ntt(polyvec *r) +__contract__( + requires(memory_no_alias(r, sizeof(polyvec))) + requires(forall(int, j, 0, MLKEM_K - 1, + array_abs_bound(r->vec[j].coeffs, 0, MLKEM_N - 1, (MLKEM_Q - 1)))) + assigns(object_whole(r)) + ensures(forall(int, j, 0, MLKEM_K - 1, + array_abs_bound(r->vec[j].coeffs, 0, MLKEM_N - 1, (NTT_BOUND - 1)))) +); #define polyvec_invntt_tomont MLKEM_NAMESPACE(polyvec_invntt_tomont) /************************************************* @@ -140,12 +144,13 @@ ENSURES(FORALL(int, j, 0, MLKEM_K - 1, * * Arguments: - polyvec *r: pointer to in/output vector of polynomials **************************************************/ -void polyvec_invntt_tomont(polyvec *r) // clang-format off -REQUIRES(IS_FRESH(r, sizeof(polyvec))) -ASSIGNS(OBJECT_WHOLE(r)) -ENSURES(FORALL(int, j, 0, MLKEM_K - 1, - ARRAY_ABS_BOUND(r->vec[j].coeffs, 0, MLKEM_N - 1, (INVNTT_BOUND - 1)))); -// clang-format on +void polyvec_invntt_tomont(polyvec *r) +__contract__( + requires(memory_no_alias(r, sizeof(polyvec))) + assigns(object_whole(r)) + ensures(forall(int, j, 0, MLKEM_K - 1, + array_abs_bound(r->vec[j].coeffs, 0, MLKEM_N - 1, (INVNTT_BOUND - 1)))) +); #define polyvec_basemul_acc_montgomery \ MLKEM_NAMESPACE(polyvec_basemul_acc_montgomery) @@ -172,18 +177,19 @@ void polyvec_basemul_acc_montgomery(poly *r, const polyvec *a, * for second input polynomial vector. Can be computed * via polyvec_mulcache_compute(). **************************************************/ -void polyvec_basemul_acc_montgomery_cached( - poly *r, const polyvec *a, const polyvec *b, - const polyvec_mulcache *b_cache) // clang-format off -REQUIRES(IS_FRESH(r, sizeof(poly))) -REQUIRES(IS_FRESH(a, sizeof(polyvec))) -REQUIRES(IS_FRESH(b, sizeof(polyvec))) -REQUIRES(IS_FRESH(b_cache, sizeof(polyvec_mulcache))) +void polyvec_basemul_acc_montgomery_cached(poly *r, const polyvec *a, + const polyvec *b, + const polyvec_mulcache *b_cache) +__contract__( + requires(memory_no_alias(r, sizeof(poly))) + requires(memory_no_alias(a, sizeof(polyvec))) + requires(memory_no_alias(b, sizeof(polyvec))) + requires(memory_no_alias(b_cache, sizeof(polyvec_mulcache))) // Input is coefficient-wise < q in absolute value -REQUIRES(FORALL(int, k1, 0, MLKEM_K - 1, - ARRAY_ABS_BOUND(a->vec[k1].coeffs, 0, MLKEM_N - 1, (MLKEM_Q - 1)))) -ASSIGNS(OBJECT_UPTO(r, sizeof(poly))); -// clang-format on + requires(forall(int, k1, 0, MLKEM_K - 1, + array_abs_bound(a->vec[k1].coeffs, 0, MLKEM_N - 1, (MLKEM_Q - 1)))) + assigns(memory_slice(r, sizeof(poly))) +); // REF-CHANGE: This function does not exist in the reference implementation #define polyvec_mulcache_compute MLKEM_NAMESPACE(polyvec_mulcache_compute) @@ -210,12 +216,12 @@ ASSIGNS(OBJECT_UPTO(r, sizeof(poly))); // NOTE: The default C implementation of this function populates // the mulcache with values in (-q,q), but this is not needed for the // higher level safety proofs, and thus not part of the spec. -void polyvec_mulcache_compute(polyvec_mulcache *x, - const polyvec *a) // clang-format off -REQUIRES(IS_FRESH(x, sizeof(polyvec_mulcache))) -REQUIRES(IS_FRESH(a, sizeof(polyvec))) -ASSIGNS(OBJECT_WHOLE(x)); -// clang-format on +void polyvec_mulcache_compute(polyvec_mulcache *x, const polyvec *a) +__contract__( + requires(memory_no_alias(x, sizeof(polyvec_mulcache))) + requires(memory_no_alias(a, sizeof(polyvec))) + assigns(object_whole(x)) +); #define polyvec_reduce MLKEM_NAMESPACE(polyvec_reduce) /************************************************* @@ -232,12 +238,13 @@ ASSIGNS(OBJECT_WHOLE(x)); // signed canonical output data. Unsigned canonical // outputs are better suited to the only remaining // use of poly_reduce() in the context of (de)serialization. -void polyvec_reduce(polyvec *r) // clang-format off -REQUIRES(IS_FRESH(r, sizeof(polyvec))) -ASSIGNS(OBJECT_WHOLE(r)) -ENSURES(FORALL(int, k0, 0, MLKEM_K - 1, - ARRAY_BOUND(r->vec[k0].coeffs, 0, MLKEM_N - 1, 0, (MLKEM_Q - 1)))); -// clang-format on +void polyvec_reduce(polyvec *r) +__contract__( + requires(memory_no_alias(r, sizeof(polyvec))) + assigns(object_whole(r)) + ensures(forall(int, k0, 0, MLKEM_K - 1, + array_bound(r->vec[k0].coeffs, 0, MLKEM_N - 1, 0, (MLKEM_Q - 1)))) +); #define polyvec_add MLKEM_NAMESPACE(polyvec_add) /************************************************* @@ -254,19 +261,20 @@ ENSURES(FORALL(int, k0, 0, MLKEM_K - 1, * * The coefficients returned in *r are in int16_t which is sufficient * to prove type-safety of calling units. Therefore, no stronger - * ENSURES clause is required on this function. + * ensures clause is required on this function. **************************************************/ -void polyvec_add(polyvec *r, const polyvec *b) // clang-format off -REQUIRES(IS_FRESH(r, sizeof(polyvec))) -REQUIRES(IS_FRESH(b, sizeof(polyvec))) -REQUIRES(FORALL(int, j0, 0, MLKEM_K - 1, - FORALL(int, k0, 0, MLKEM_N - 1, +void polyvec_add(polyvec *r, const polyvec *b) +__contract__( + requires(memory_no_alias(r, sizeof(polyvec))) + requires(memory_no_alias(b, sizeof(polyvec))) + requires(forall(int, j0, 0, MLKEM_K - 1, + forall(int, k0, 0, MLKEM_N - 1, (int32_t)r->vec[j0].coeffs[k0] + b->vec[j0].coeffs[k0] <= INT16_MAX))) -REQUIRES(FORALL(int, j1, 0, MLKEM_K - 1, - FORALL(int, k1, 0, MLKEM_N - 1, + requires(forall(int, j1, 0, MLKEM_K - 1, + forall(int, k1, 0, MLKEM_N - 1, (int32_t)r->vec[j1].coeffs[k1] + b->vec[j1].coeffs[k1] >= INT16_MIN))) -ASSIGNS(OBJECT_WHOLE(r)); -// clang-format on + assigns(object_whole(r)) +); #define polyvec_tomont MLKEM_NAMESPACE(polyvec_tomont) /************************************************* @@ -278,12 +286,13 @@ ASSIGNS(OBJECT_WHOLE(r)); * Bounds: Output < q in absolute value. * **************************************************/ -void polyvec_tomont(polyvec *r) // clang-format off -REQUIRES(IS_FRESH(r, sizeof(polyvec))) -ASSIGNS(OBJECT_UPTO(r, sizeof(polyvec))) -ASSIGNS(OBJECT_WHOLE(r)) -ENSURES(FORALL(int, j, 0, MLKEM_K - 1, - ARRAY_ABS_BOUND(r->vec[j].coeffs, 0, MLKEM_N - 1, (MLKEM_Q - 1)))); -// clang-format on +void polyvec_tomont(polyvec *r) +__contract__( + requires(memory_no_alias(r, sizeof(polyvec))) + assigns(memory_slice(r, sizeof(polyvec))) + assigns(object_whole(r)) + ensures(forall(int, j, 0, MLKEM_K - 1, + array_abs_bound(r->vec[j].coeffs, 0, MLKEM_N - 1, (MLKEM_Q - 1)))) +); #endif diff --git a/mlkem/randombytes.h b/mlkem/randombytes.h index c1ed34b82..046795e17 100644 --- a/mlkem/randombytes.h +++ b/mlkem/randombytes.h @@ -8,9 +8,10 @@ #include "cbmc.h" -void randombytes(uint8_t *out, size_t outlen) // clang-format off -REQUIRES(IS_FRESH(out, outlen)) -ASSIGNS(OBJECT_UPTO(out, outlen)); -// clang-format on +void randombytes(uint8_t *out, size_t outlen) +__contract__( + requires(memory_no_alias(out, outlen)) + assigns(memory_slice(out, outlen)) +); #endif diff --git a/mlkem/reduce.c b/mlkem/reduce.c index 8b296923c..cac77880c 100644 --- a/mlkem/reduce.c +++ b/mlkem/reduce.c @@ -20,7 +20,8 @@ static const uint32_t QINV = 62209; // q^-1 mod 2^16 #pragma CPROVER check push #pragma CPROVER check disable "conversion" #endif -static inline int16_t cast_uint16_to_int16(uint16_t x) { +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)) @@ -58,7 +59,8 @@ static inline int16_t cast_uint16_to_int16(uint16_t x) { * < q (C/2^16 + 1/2). **************************************************/ ALWAYS_INLINE -static inline int16_t montgomery_reduce_generic(int32_t a) { +static inline int16_t montgomery_reduce_generic(int32_t a) +{ // Bounds on paper // // - Case |a| < q * C, for some C @@ -89,7 +91,8 @@ static inline int16_t montgomery_reduce_generic(int32_t a) { return (int16_t)r; } -int16_t montgomery_reduce(int32_t a) { +int16_t montgomery_reduce(int32_t a) +{ SCALAR_BOUND(a, 2 * MLKEM_Q * 32768, "montgomery_reduce input"); int16_t res = montgomery_reduce_generic(a); @@ -98,7 +101,8 @@ int16_t montgomery_reduce(int32_t a) { return res; } -int16_t fqmul(int16_t a, int16_t b) { +int16_t fqmul(int16_t a, int16_t b) +{ SCALAR_BOUND(b, HALF_Q, "fqmul input"); int16_t res = montgomery_reduce((int32_t)a * (int32_t)b); @@ -124,7 +128,8 @@ static const int32_t barrett_multiplier = * * Returns: integer in {-(q-1)/2,...,(q-1)/2} congruent to a modulo q. **************************************************/ -int16_t barrett_reduce(int16_t a) { +int16_t barrett_reduce(int16_t a) +{ // Compute round_to_nearest(a/MLKEM_Q) using the multiplier // above and shift by BPOWER places. // diff --git a/mlkem/reduce.h b/mlkem/reduce.h index 7b034226e..64521ebed 100644 --- a/mlkem/reduce.h +++ b/mlkem/reduce.h @@ -23,16 +23,18 @@ * smaller than 3/2 q in absolute value. **************************************************/ #define montgomery_reduce MLKEM_NAMESPACE(montgomery_reduce) -int16_t montgomery_reduce(int32_t a) // clang-format off -REQUIRES(a > -(2 * MLKEM_Q * 32768)) -REQUIRES(a < (2 * MLKEM_Q * 32768)) -ENSURES(RETURN_VALUE > -(3 * HALF_Q) && RETURN_VALUE < (3 * HALF_Q)); -// clang-format on +int16_t montgomery_reduce(int32_t a) +__contract__( + requires(a > -(2 * MLKEM_Q * 32768)) + requires(a < (2 * MLKEM_Q * 32768)) + ensures(return_value > -(3 * HALF_Q) && return_value < (3 * HALF_Q)) +); #define barrett_reduce MLKEM_NAMESPACE(barrett_reduce) -int16_t barrett_reduce(int16_t a) // clang-format off -ENSURES(RETURN_VALUE > -HALF_Q && RETURN_VALUE < HALF_Q); -// clang-format on +int16_t barrett_reduce(int16_t a) +__contract__( + ensures(return_value > -HALF_Q && return_value < HALF_Q) +); /************************************************* * Name: fqmul @@ -49,12 +51,12 @@ ENSURES(RETURN_VALUE > -HALF_Q && RETURN_VALUE < HALF_Q); * **************************************************/ #define fqmul MLKEM_NAMESPACE(fqmul) - -int16_t fqmul(int16_t a, int16_t b) // clang-format off -REQUIRES(b > -HALF_Q) -REQUIRES(b < HALF_Q) -ENSURES(RETURN_VALUE > -MLKEM_Q && RETURN_VALUE < MLKEM_Q); -// clang-format on +int16_t fqmul(int16_t a, int16_t b) +__contract__( + requires(b > -HALF_Q) + requires(b < HALF_Q) + ensures(return_value > -MLKEM_Q && return_value < MLKEM_Q) +); #endif diff --git a/mlkem/rej_uniform.c b/mlkem/rej_uniform.c index a2ca68fb6..18e7bc36b 100644 --- a/mlkem/rej_uniform.c +++ b/mlkem/rej_uniform.c @@ -36,40 +36,46 @@ **************************************************/ static unsigned int rej_uniform_scalar(int16_t *r, unsigned int target, unsigned int offset, const uint8_t *buf, - unsigned int buflen) { + unsigned int buflen) +{ unsigned int ctr, pos; uint16_t val0, val1; ctr = offset; pos = 0; // pos + 3 cannot overflow due to the assumption buflen <= 4096 - while (ctr < target && pos + 3 <= buflen) // clang-format off - INVARIANT(offset <= ctr && ctr <= target && pos <= buflen) - INVARIANT(ctr > 0 ==> ARRAY_BOUND(r, 0, ctr - 1, 0, (MLKEM_Q - 1))) // clang-format on - { - val0 = ((buf[pos + 0] >> 0) | ((uint16_t)buf[pos + 1] << 8)) & 0xFFF; - val1 = ((buf[pos + 1] >> 4) | ((uint16_t)buf[pos + 2] << 4)) & 0xFFF; - pos += 3; + while (ctr < target && pos + 3 <= buflen) + __loop__( + invariant(offset <= ctr && ctr <= target && pos <= buflen) + invariant(ctr > 0 ==> array_bound(r, 0, ctr - 1, 0, (MLKEM_Q - 1)))) + { + val0 = ((buf[pos + 0] >> 0) | ((uint16_t)buf[pos + 1] << 8)) & 0xFFF; + val1 = ((buf[pos + 1] >> 4) | ((uint16_t)buf[pos + 2] << 4)) & 0xFFF; + pos += 3; - if (val0 < MLKEM_Q) { - r[ctr++] = val0; - } - if (ctr < target && val1 < MLKEM_Q) { - r[ctr++] = val1; - } + if (val0 < MLKEM_Q) + { + r[ctr++] = val0; + } + if (ctr < target && val1 < MLKEM_Q) + { + r[ctr++] = val1; } + } return ctr; } #if !defined(MLKEM_USE_NATIVE_REJ_UNIFORM) unsigned int rej_uniform(int16_t *r, unsigned int target, unsigned int offset, - const uint8_t *buf, unsigned int buflen) { + const uint8_t *buf, unsigned int buflen) +{ return rej_uniform_scalar(r, target, offset, buf, buflen); } #else /* MLKEM_USE_NATIVE_REJ_UNIFORM */ unsigned int rej_uniform(int16_t *r, unsigned int target, unsigned int offset, - const uint8_t *buf, unsigned int buflen) { + const uint8_t *buf, unsigned int buflen) +{ int ret; // Sample from large buffer with full lane as much as possible. diff --git a/mlkem/rej_uniform.h b/mlkem/rej_uniform.h index 6a669a2bf..dd8e13fb1 100644 --- a/mlkem/rej_uniform.h +++ b/mlkem/rej_uniform.h @@ -44,14 +44,14 @@ // buffer. This avoids shifting the buffer base in the caller, which appears // tricky to reason about. unsigned int rej_uniform(int16_t *r, unsigned int target, unsigned int offset, - const uint8_t *buf, - unsigned int buflen) // clang-format off -REQUIRES(offset <= target && target <= 4096 && buflen <= 4096 && buflen % 3 == 0) -REQUIRES(IS_FRESH(r, sizeof(int16_t) * target)) -REQUIRES(IS_FRESH(buf, buflen)) -REQUIRES(offset > 0 ==> ARRAY_BOUND(r, 0, offset - 1, 0, (MLKEM_Q - 1))) -ASSIGNS(OBJECT_UPTO(r, sizeof(int16_t) * target)) -ENSURES(offset <= RETURN_VALUE && RETURN_VALUE <= target) -ENSURES(RETURN_VALUE > 0 ==> ARRAY_BOUND(r, 0, RETURN_VALUE - 1, 0, (MLKEM_Q - 1))); -// clang-format on + const uint8_t *buf, unsigned int buflen) +__contract__( + requires(offset <= target && target <= 4096 && buflen <= 4096 && buflen % 3 == 0) + requires(memory_no_alias(r, sizeof(int16_t) * target)) + requires(memory_no_alias(buf, buflen)) + requires(offset > 0 ==> array_bound(r, 0, offset - 1, 0, (MLKEM_Q - 1))) + assigns(memory_slice(r, sizeof(int16_t) * target)) + ensures(offset <= return_value && return_value <= target) + ensures(return_value > 0 ==> array_bound(r, 0, return_value - 1, 0, (MLKEM_Q - 1))) +); #endif diff --git a/mlkem/symmetric-shake.c b/mlkem/symmetric-shake.c index 56079349e..cfc03c0c0 100644 --- a/mlkem/symmetric-shake.c +++ b/mlkem/symmetric-shake.c @@ -8,7 +8,8 @@ #include "symmetric.h" void mlkem_shake256_prf(uint8_t *out, size_t outlen, - const uint8_t key[MLKEM_SYMBYTES], uint8_t nonce) { + const uint8_t key[MLKEM_SYMBYTES], uint8_t nonce) +{ uint8_t extkey[MLKEM_SYMBYTES + 1]; memcpy(extkey, key, MLKEM_SYMBYTES); @@ -19,7 +20,8 @@ void mlkem_shake256_prf(uint8_t *out, size_t outlen, void mlkem_shake256_rkprf(uint8_t out[MLKEM_SSBYTES], const uint8_t key[MLKEM_SYMBYTES], - const uint8_t input[MLKEM_CIPHERTEXTBYTES]) { + const uint8_t input[MLKEM_CIPHERTEXTBYTES]) +{ shake256incctx s; shake256_inc_init(&s); diff --git a/mlkem/symmetric.h b/mlkem/symmetric.h index e497565b9..39382c423 100644 --- a/mlkem/symmetric.h +++ b/mlkem/symmetric.h @@ -29,12 +29,12 @@ * out and key may NOT be aliased. **************************************************/ void mlkem_shake256_prf(uint8_t *out, size_t outlen, - const uint8_t key[MLKEM_SYMBYTES], - uint8_t nonce) // clang-format off -REQUIRES(IS_FRESH(out, outlen)) -REQUIRES(IS_FRESH(key, MLKEM_SYMBYTES)) -ASSIGNS(OBJECT_UPTO(out, outlen)); -// clang-format on + const uint8_t key[MLKEM_SYMBYTES], uint8_t nonce) +__contract__( + requires(memory_no_alias(out, outlen)) + requires(memory_no_alias(key, MLKEM_SYMBYTES)) + assigns(memory_slice(out, outlen)) +); #define mlkem_shake256_rkprf MLKEM_NAMESPACE(mlkem_shake256_rkprf) /************************************************* @@ -53,14 +53,15 @@ ASSIGNS(OBJECT_UPTO(out, outlen)); * * out, key, and input may NOT be aliased. **************************************************/ -void mlkem_shake256_rkprf( - uint8_t out[MLKEM_SSBYTES], const uint8_t key[MLKEM_SYMBYTES], - const uint8_t input[MLKEM_CIPHERTEXTBYTES]) // clang-format off -REQUIRES(IS_FRESH(out, MLKEM_SSBYTES)) -REQUIRES(IS_FRESH(key, MLKEM_SYMBYTES)) -REQUIRES(IS_FRESH(input, MLKEM_CIPHERTEXTBYTES)) -ASSIGNS(OBJECT_UPTO(out, MLKEM_SSBYTES)); -// clang-format on +void mlkem_shake256_rkprf(uint8_t out[MLKEM_SSBYTES], + const uint8_t key[MLKEM_SYMBYTES], + const uint8_t input[MLKEM_CIPHERTEXTBYTES]) +__contract__( + requires(memory_no_alias(out, MLKEM_SSBYTES)) + requires(memory_no_alias(key, MLKEM_SYMBYTES)) + requires(memory_no_alias(input, MLKEM_CIPHERTEXTBYTES)) + assigns(memory_slice(out, MLKEM_SSBYTES)) +); // Macros denoting FIPS-203 specific Hash functions diff --git a/mlkem/verify.c b/mlkem/verify.c index 9d5a3fdda..c60222e61 100644 --- a/mlkem/verify.c +++ b/mlkem/verify.c @@ -15,7 +15,8 @@ // You MUST NOT compile this file using link time optimization. // -int verify(const uint8_t *a, const uint8_t *b, const size_t len) { +int verify(const uint8_t *a, const uint8_t *b, const size_t len) +{ uint8_t r = 0; uint64_t u; @@ -24,12 +25,13 @@ int verify(const uint8_t *a, const uint8_t *b, const size_t len) { // can yield -1 as required. const int ilen = (int)len; - for (int i = 0; i < ilen; i++) // clang-format off - INVARIANT(i >= 0 && i <= ilen) - INVARIANT((r == 0) == (FORALL(int, k, 0, (i - 1), (a[k] == b[k])))) // clang-format on - { - r |= a[i] ^ b[i]; - } + for (int i = 0; i < ilen; i++) + __loop__( + invariant(i >= 0 && i <= ilen) + invariant((r == 0) == (forall(int, k, 0, (i - 1), (a[k] == b[k]))))) + { + r |= a[i] ^ b[i]; + } #ifdef CBMC #pragma CPROVER check push @@ -43,16 +45,16 @@ int verify(const uint8_t *a, const uint8_t *b, const size_t len) { return (int)u; } -void cmov(uint8_t *r, const uint8_t *x, size_t len, uint8_t b) { +void cmov(uint8_t *r, const uint8_t *x, size_t len, uint8_t b) +{ size_t i; b = (-b) & 0xFF; - for (i = 0; i < len; i++) // clang-format off - INVARIANT(i <= len) - // clang-format on - { - r[i] ^= b & (r[i] ^ x[i]); - } + for (i = 0; i < len; i++) + __loop__(invariant(i <= len)) + { + r[i] ^= b & (r[i] ^ x[i]); + } } /************************************************* @@ -61,7 +63,8 @@ void cmov(uint8_t *r, const uint8_t *x, size_t len, uint8_t b) { * Constant-time implementation. Relies on basic * properties of bitwise ^ or and &. **************************************************/ -void cmov_int16(int16_t *r, const int16_t v, const uint16_t b) { +void cmov_int16(int16_t *r, const int16_t v, const uint16_t b) +{ // CBMC issues false alarms here for the implicit conversions between // uint16_t and int, so disable "conversion-check" here for now. #pragma CPROVER check push diff --git a/mlkem/verify.h b/mlkem/verify.h index d9b565fc9..b58680515 100644 --- a/mlkem/verify.h +++ b/mlkem/verify.h @@ -21,13 +21,13 @@ * * Returns 0 if the byte arrays are equal, 1 otherwise **************************************************/ -int verify(const uint8_t *a, const uint8_t *b, - const size_t len) // clang-format off -REQUIRES(IS_FRESH(a, len)) -REQUIRES(IS_FRESH(b, len)) -REQUIRES(len <= INT_MAX) -ENSURES(RETURN_VALUE == (1 - FORALL(int, i, 0, ((int)len - 1), (a[i] == b[i])))); -// clang-format on +int verify(const uint8_t *a, const uint8_t *b, const size_t len) +__contract__( + requires(memory_no_alias(a, len)) + requires(memory_no_alias(b, len)) + requires(len <= INT_MAX) + ensures(return_value == (1 - forall(int, i, 0, ((int)len - 1), (a[i] == b[i])))) +); #define cmov MLKEM_NAMESPACE(cmov) /************************************************* @@ -43,13 +43,13 @@ ENSURES(RETURN_VALUE == (1 - FORALL(int, i, 0, ((int)len - 1), (a[i] == b[i])))) * size_t len: Amount of bytes to be copied * uint8_t b: Condition bit; has to be in {0,1} **************************************************/ -void cmov(uint8_t *r, const uint8_t *x, size_t len, - uint8_t b) // clang-format off -REQUIRES(IS_FRESH(r, len)) -REQUIRES(IS_FRESH(x, len)) -REQUIRES(b == 0 || b == 1) -ASSIGNS(OBJECT_UPTO(r, len)); -// clang-format on +void cmov(uint8_t *r, const uint8_t *x, size_t len, uint8_t b) +__contract__( + requires(memory_no_alias(r, len)) + requires(memory_no_alias(x, len)) + requires(b == 0 || b == 1) + assigns(memory_slice(r, len)) +); #define cmov_int16 MLKEM_NAMESPACE(cmov_int16) /************************************************* @@ -63,13 +63,12 @@ ASSIGNS(OBJECT_UPTO(r, len)); * int16_t v: input int16_t. Must not be NULL * uint16_t b: Condition bit; has to be in {0,1} **************************************************/ - -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_UPTO(r, sizeof(int16_t))) -ENSURES(*r == (b ? v : OLD(*r))); -// clang-format on +void cmov_int16(int16_t *r, const int16_t v, const uint16_t b) +__contract__( + requires(b == 0 || b == 1) + requires(memory_no_alias(r, sizeof(int16_t))) + assigns(memory_slice(r, sizeof(int16_t))) + ensures(*r == (b ? v : old(*r))) +); #endif diff --git a/test/acvp_mlkem.c b/test/acvp_mlkem.c index f9fb5ad5e..d87ab562d 100644 --- a/test/acvp_mlkem.c +++ b/test/acvp_mlkem.c @@ -12,48 +12,73 @@ #define DECAPS_USAGE "acvp_mlkem{lvl} encapDecap VAL decaps dk=HEX c=HEX" #define KEYGEN_USAGE "acvp_mlkem{lvl} keyGen AFT z=HEX d=HEX" -typedef enum { encapDecap, keyGen } acvp_mode; - -typedef enum { AFT, VAL } acvp_type; - -typedef enum { encapsulation, decapsulation } acvp_encapDecap_function; +typedef enum +{ + encapDecap, + keyGen +} acvp_mode; + +typedef enum +{ + AFT, + VAL +} acvp_type; + +typedef enum +{ + encapsulation, + decapsulation +} acvp_encapDecap_function; /* Decode hex character [0-9A-Fa-f] into 0-15 */ -static unsigned char decode_hex_char(char hex) { - if (hex >= '0' && hex <= '9') { +static unsigned char decode_hex_char(char hex) +{ + if (hex >= '0' && hex <= '9') + { return (unsigned char)(hex - '0'); - } else if (hex >= 'A' && hex <= 'F') { + } + else if (hex >= 'A' && hex <= 'F') + { return 10 + (unsigned char)(hex - 'A'); - } else if (hex >= 'a' && hex <= 'f') { + } + else if (hex >= 'a' && hex <= 'f') + { return 10 + (unsigned char)(hex - 'a'); - } else { + } + else + { return 0xFF; } } static int decode_hex(const char *prefix, unsigned char *out, size_t out_len, - const char *hex) { + const char *hex) +{ size_t hex_len = strlen(hex); size_t prefix_len = strlen(prefix); // Check that hex starts with `prefix=` // Use memcmp, not strcmp if (hex_len < prefix_len + 1 || memcmp(prefix, hex, prefix_len) != 0 || - hex[prefix_len] != '=') { + hex[prefix_len] != '=') + { goto hex_usage; } hex += prefix_len + 1; hex_len -= prefix_len + 1; - if (hex_len != 2 * out_len) { + if (hex_len != 2 * out_len) + { goto hex_usage; } - for (size_t i = 0; i < out_len; i++, hex += 2, out++) { + for (size_t i = 0; i < out_len; i++, hex += 2, out++) + { unsigned hex0 = decode_hex_char(hex[0]); unsigned hex1 = decode_hex_char(hex[1]); - if (hex0 == 0xFF || hex1 == 0xFF) { + if (hex0 == 0xFF || hex1 == 0xFF) + { goto hex_usage; } @@ -70,11 +95,14 @@ static int decode_hex(const char *prefix, unsigned char *out, size_t out_len, return 1; } -static void print_hex(const char *name, const unsigned char *raw, size_t len) { - if (name != NULL) { +static void print_hex(const char *name, const unsigned char *raw, size_t len) +{ + if (name != NULL) + { printf("%s=", name); } - for (; len > 0; len--, raw++) { + for (; len > 0; len--, raw++) + { printf("%02X", *raw); } printf("\n"); @@ -82,7 +110,8 @@ static void print_hex(const char *name, const unsigned char *raw, size_t len) { static void acvp_mlkem_encapDecp_AFT_encapsulation( unsigned char const ek[MLKEM_INDCPA_PUBLICKEYBYTES], - unsigned char const m[MLKEM_SYMBYTES]) { + unsigned char const m[MLKEM_SYMBYTES]) +{ unsigned char ct[MLKEM_CIPHERTEXTBYTES]; unsigned char ss[MLKEM_SSBYTES]; @@ -94,7 +123,8 @@ static void acvp_mlkem_encapDecp_AFT_encapsulation( static void acvp_mlkem_encapDecp_VAL_decapsulation( unsigned char const dk[MLKEM_SECRETKEYBYTES], - unsigned char const c[MLKEM_CIPHERTEXTBYTES]) { + unsigned char const c[MLKEM_CIPHERTEXTBYTES]) +{ unsigned char ss[MLKEM_SSBYTES]; crypto_kem_dec(ss, c, dk); @@ -103,7 +133,8 @@ static void acvp_mlkem_encapDecp_VAL_decapsulation( } static void acvp_mlkem_keyGen_AFT(unsigned char const z[MLKEM_SYMBYTES], - unsigned char const d[MLKEM_SYMBYTES]) { + unsigned char const d[MLKEM_SYMBYTES]) +{ unsigned char ek[MLKEM_INDCPA_PUBLICKEYBYTES]; unsigned char dk[MLKEM_SECRETKEYBYTES]; @@ -117,77 +148,104 @@ static void acvp_mlkem_keyGen_AFT(unsigned char const z[MLKEM_SYMBYTES], print_hex("dk", dk, sizeof(dk)); } -int main(int argc, char *argv[]) { - if (argc == 0) { +int main(int argc, char *argv[]) +{ + if (argc == 0) + { goto usage; } argc--, argv++; /* Parse mode: "encapDecap" or "keyGen" */ - if (argc == 0) { + if (argc == 0) + { goto usage; } acvp_mode mode; - if (strcmp(*argv, "encapDecap") == 0) { + if (strcmp(*argv, "encapDecap") == 0) + { mode = encapDecap; - } else if (strcmp(*argv, "keyGen") == 0) { + } + else if (strcmp(*argv, "keyGen") == 0) + { mode = keyGen; - } else { + } + else + { goto usage; } argc--, argv++; /* Parse test type: "AFT" (Algorithm Functional Test) or "VAL" (Validation) */ - if (argc == 0) { + if (argc == 0) + { goto usage; } acvp_type type; - if (strcmp(*argv, "AFT") == 0) { + if (strcmp(*argv, "AFT") == 0) + { type = AFT; - } else if (strcmp(*argv, "VAL") == 0) { + } + else if (strcmp(*argv, "VAL") == 0) + { type = VAL; - } else { + } + else + { goto usage; } argc--, argv++; /* Case: encapDecap */ - switch (mode) { - case encapDecap: { + switch (mode) + { + case encapDecap: + { /* Parse function: "encapsulation" or "decapsulation" */ - if (argc == 0) { + if (argc == 0) + { goto usage; } acvp_encapDecap_function encapDecap_function; - if (strcmp(*argv, "encapsulation") == 0) { + if (strcmp(*argv, "encapsulation") == 0) + { encapDecap_function = encapsulation; - } else if (strcmp(*argv, "decapsulation") == 0) { + } + else if (strcmp(*argv, "decapsulation") == 0) + { encapDecap_function = decapsulation; - } else { + } + else + { goto usage; } argc--, argv++; - switch (encapDecap_function) { - case encapsulation: { + switch (encapDecap_function) + { + case encapsulation: + { /* Encapsulation only for "AFT" */ - if (type != AFT) { + if (type != AFT) + { goto encaps_usage; } /* Parse ek */ unsigned char ek[MLKEM_INDCPA_PUBLICKEYBYTES]; - if (argc == 0 || decode_hex("ek", ek, sizeof(ek), *argv) != 0) { + if (argc == 0 || decode_hex("ek", ek, sizeof(ek), *argv) != 0) + { goto encaps_usage; } argc--, argv++; /* Parse m */ unsigned char m[MLKEM_SYMBYTES]; - if (argc == 0 || decode_hex("m", m, sizeof(m), *argv) != 0) { + if (argc == 0 || decode_hex("m", m, sizeof(m), *argv) != 0) + { goto encaps_usage; } argc--, argv++; @@ -196,22 +254,26 @@ int main(int argc, char *argv[]) { acvp_mlkem_encapDecp_AFT_encapsulation(ek, m); break; } - case decapsulation: { + case decapsulation: + { /* Decapsulation only for "VAL" */ - if (type != VAL) { + if (type != VAL) + { goto decaps_usage; } /* Parse dk */ unsigned char dk[MLKEM_SECRETKEYBYTES]; - if (argc == 0 || decode_hex("dk", dk, sizeof(dk), *argv) != 0) { + if (argc == 0 || decode_hex("dk", dk, sizeof(dk), *argv) != 0) + { goto decaps_usage; } argc--, argv++; /* Parse c */ unsigned char c[MLKEM_CIPHERTEXTBYTES]; - if (argc == 0 || decode_hex("c", c, sizeof(c), *argv) != 0) { + if (argc == 0 || decode_hex("c", c, sizeof(c), *argv) != 0) + { goto decaps_usage; } argc--, argv++; @@ -223,22 +285,26 @@ int main(int argc, char *argv[]) { } break; } - case keyGen: { + case keyGen: + { /* keyGen only for "AFT" */ - if (type != AFT) { + if (type != AFT) + { goto keygen_usage; } /* Parse z */ unsigned char z[MLKEM_SYMBYTES]; - if (argc == 0 || decode_hex("z", z, sizeof(z), *argv) != 0) { + if (argc == 0 || decode_hex("z", z, sizeof(z), *argv) != 0) + { goto keygen_usage; } argc--, argv++; /* Parse d */ unsigned char d[MLKEM_SYMBYTES]; - if (argc == 0 || decode_hex("d", d, sizeof(d), *argv) != 0) { + if (argc == 0 || decode_hex("d", d, sizeof(d), *argv) != 0) + { goto keygen_usage; } argc--, argv++; diff --git a/test/bench_components_mlkem.c b/test/bench_components_mlkem.c index 5f40311be..ccb209694 100644 --- a/test/bench_components_mlkem.c +++ b/test/bench_components_mlkem.c @@ -21,23 +21,27 @@ #define NITERERATIONS 300 #define NTESTS 200 -static int cmp_uint64_t(const void *a, const void *b) { +static int cmp_uint64_t(const void *a, const void *b) +{ return (int)((*((const uint64_t *)a)) - (*((const uint64_t *)b))); } #define BENCH(txt, code) \ - for (i = 0; i < NTESTS; i++) { \ + for (i = 0; i < NTESTS; i++) \ + { \ randombytes((uint8_t *)data0, sizeof(data0)); \ randombytes((uint8_t *)data1, sizeof(data1)); \ randombytes((uint8_t *)data2, sizeof(data2)); \ randombytes((uint8_t *)data3, sizeof(data3)); \ randombytes((uint8_t *)data4, sizeof(data4)); \ - for (j = 0; j < NWARMUP; j++) { \ + for (j = 0; j < NWARMUP; j++) \ + { \ code; \ } \ \ t0 = get_cyclecounter(); \ - for (j = 0; j < NITERERATIONS; j++) { \ + for (j = 0; j < NITERERATIONS; j++) \ + { \ code; \ } \ t1 = get_cyclecounter(); \ @@ -46,7 +50,8 @@ static int cmp_uint64_t(const void *a, const void *b) { qsort((cyc), NTESTS, sizeof(uint64_t), cmp_uint64_t); \ printf(txt " cycles=%" PRIu64 "\n", (cyc)[NTESTS >> 1] / NITERERATIONS); -static int bench(void) { +static int bench(void) +{ ALIGN uint64_t data0[1024]; ALIGN uint64_t data1[1024]; ALIGN uint64_t data2[1024]; @@ -212,7 +217,8 @@ static int bench(void) { return 0; } -int main(void) { +int main(void) +{ enable_cyclecounter(); bench(); disable_cyclecounter(); diff --git a/test/bench_mlkem.c b/test/bench_mlkem.c index ceb528365..0846acdba 100644 --- a/test/bench_mlkem.c +++ b/test/bench_mlkem.c @@ -13,31 +13,36 @@ #define NITERATIONS 300 #define NTESTS 500 -static int cmp_uint64_t(const void *a, const void *b) { +static int cmp_uint64_t(const void *a, const void *b) +{ return (int)((*((const uint64_t *)a)) - (*((const uint64_t *)b))); } -static void print_median(const char *txt, uint64_t cyc[NTESTS]) { +static void print_median(const char *txt, uint64_t cyc[NTESTS]) +{ printf("%10s cycles = %" PRIu64 "\n", txt, cyc[NTESTS >> 1] / NITERATIONS); } static int percentiles[] = {1, 10, 20, 30, 40, 50, 60, 70, 80, 90, 99}; -static void print_percentile_legend(void) { +static void print_percentile_legend(void) +{ printf("%21s", "percentile"); for (unsigned i = 0; i < sizeof(percentiles) / sizeof(percentiles[0]); i++) printf("%7d", percentiles[i]); printf("\n"); } -static void print_percentiles(const char *txt, uint64_t cyc[NTESTS]) { +static void print_percentiles(const char *txt, uint64_t cyc[NTESTS]) +{ printf("%10s percentiles:", txt); for (unsigned i = 0; i < sizeof(percentiles) / sizeof(percentiles[0]); i++) printf("%7" PRIu64, (cyc)[NTESTS * percentiles[i] / 100] / NITERATIONS); printf("\n"); } -static int bench(void) { +static int bench(void) +{ uint8_t pk[CRYPTO_PUBLICKEYBYTES]; uint8_t sk[CRYPTO_SECRETKEYBYTES]; uint8_t ct[CRYPTO_CIPHERTEXTBYTES]; @@ -50,17 +55,20 @@ static int bench(void) { uint64_t t0, t1; - for (i = 0; i < NTESTS; i++) { + for (i = 0; i < NTESTS; i++) + { randombytes(kg_rand, 2 * CRYPTO_BYTES); randombytes(enc_rand, CRYPTO_BYTES); // Key-pair generation - for (j = 0; j < NWARMUP; j++) { + for (j = 0; j < NWARMUP; j++) + { crypto_kem_keypair_derand(pk, sk, kg_rand); } t0 = get_cyclecounter(); - for (j = 0; j < NITERATIONS; j++) { + for (j = 0; j < NITERATIONS; j++) + { crypto_kem_keypair_derand(pk, sk, kg_rand); } t1 = get_cyclecounter(); @@ -68,29 +76,34 @@ static int bench(void) { // Encapsulation - for (j = 0; j < NWARMUP; j++) { + for (j = 0; j < NWARMUP; j++) + { crypto_kem_enc_derand(ct, key_a, pk, enc_rand); } t0 = get_cyclecounter(); - for (j = 0; j < NITERATIONS; j++) { + for (j = 0; j < NITERATIONS; j++) + { crypto_kem_enc_derand(ct, key_a, pk, enc_rand); } t1 = get_cyclecounter(); cycles_enc[i] = t1 - t0; // Decapsulation - for (j = 0; j < NWARMUP; j++) { + for (j = 0; j < NWARMUP; j++) + { crypto_kem_dec(key_b, ct, sk); } t0 = get_cyclecounter(); - for (j = 0; j < NITERATIONS; j++) { + for (j = 0; j < NITERATIONS; j++) + { crypto_kem_dec(key_b, ct, sk); } t1 = get_cyclecounter(); cycles_dec[i] = t1 - t0; - if (memcmp(key_a, key_b, CRYPTO_BYTES)) { + if (memcmp(key_a, key_b, CRYPTO_BYTES)) + { printf("ERROR keys\n"); return 1; } @@ -115,7 +128,8 @@ static int bench(void) { return 0; } -int main(void) { +int main(void) +{ enable_cyclecounter(); bench(); disable_cyclecounter(); diff --git a/test/gen_KAT.c b/test/gen_KAT.c index 6e941d9e0..ead07d4fe 100644 --- a/test/gen_KAT.c +++ b/test/gen_KAT.c @@ -9,22 +9,26 @@ #define NTESTS 10000 -static void print_hex(const char *label, const uint8_t *data, size_t size) { +static void print_hex(const char *label, const uint8_t *data, size_t size) +{ printf("%s = ", label); - for (size_t i = 0; i < size; i++) { + for (size_t i = 0; i < size; i++) + { printf("%02x", data[i]); } printf("\n"); } static void shake256_absorb(shake256incctx *state, const uint8_t *input, - size_t inlen) { + size_t inlen) +{ shake256_inc_init(state); shake256_inc_absorb(state, input, inlen); shake256_inc_finalize(state); } -int main(void) { +int main(void) +{ ALIGN uint8_t coins[3 * MLKEM_SYMBYTES]; ALIGN uint8_t pk[CRYPTO_PUBLICKEYBYTES]; ALIGN uint8_t sk[CRYPTO_SECRETKEYBYTES]; @@ -42,7 +46,8 @@ int main(void) { shake256incctx state; shake256_absorb(&state, seed, sizeof(seed)); - for (unsigned int i = 0; i < NTESTS; i++) { + for (unsigned int i = 0; i < NTESTS; i++) + { shake256_inc_squeeze(coins, sizeof(coins), &state); crypto_kem_keypair_derand(pk, sk, coins); @@ -54,7 +59,8 @@ int main(void) { crypto_kem_dec(ss2, ct, sk); - if (memcmp(ss1, ss2, sizeof(ss1))) { + if (memcmp(ss1, ss2, sizeof(ss1))) + { fprintf(stderr, "ERROR\n"); return -1; } diff --git a/test/gen_NISTKAT.c b/test/gen_NISTKAT.c index 36280d332..b6295c37c 100644 --- a/test/gen_NISTKAT.c +++ b/test/gen_NISTKAT.c @@ -8,31 +8,37 @@ #include "nistrng.h" #include "randombytes.h" -static void fprintBstr(FILE *fp, const char *S, const uint8_t *A, size_t L) { +static void fprintBstr(FILE *fp, const char *S, const uint8_t *A, size_t L) +{ size_t i; fprintf(fp, "%s", S); - for (i = 0; i < L; i++) { + for (i = 0; i < L; i++) + { fprintf(fp, "%02X", A[i]); } - if (L == 0) { + if (L == 0) + { fprintf(fp, "00"); } fprintf(fp, "\n"); } -static void randombytes_nth(uint8_t *seed, size_t nth, size_t len) { +static void randombytes_nth(uint8_t *seed, size_t nth, size_t len) +{ uint8_t entropy_input[48] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47}; nist_kat_init(entropy_input, NULL, 256); - for (size_t i = 0; i < nth + 1; i++) { + for (size_t i = 0; i < nth + 1; i++) + { randombytes(seed, len); } } -int main(void) { +int main(void) +{ uint8_t seed[48] ALIGN; FILE *fh = stdout; uint8_t public_key[CRYPTO_PUBLICKEYBYTES] ALIGN; @@ -46,7 +52,8 @@ int main(void) { fprintf(fh, "# %s\n\n", CRYPTO_ALGNAME); - do { + do + { fprintf(fh, "count = %d\n", count); randombytes_nth(seed, count, 48); fprintBstr(fh, "seed = ", seed, 48); @@ -54,7 +61,8 @@ int main(void) { nist_kat_init(seed, NULL, 256); rc = crypto_kem_keypair(public_key, secret_key); - if (rc != 0) { + if (rc != 0) + { fprintf(stderr, "[kat_kem] %s ERROR: crypto_kem_keypair failed!\n", CRYPTO_ALGNAME); return -1; @@ -63,7 +71,8 @@ int main(void) { fprintBstr(fh, "sk = ", secret_key, CRYPTO_SECRETKEYBYTES); rc = crypto_kem_enc(ciphertext, shared_secret_e, public_key); - if (rc != 0) { + if (rc != 0) + { fprintf(stderr, "[kat_kem] %s ERROR: crypto_kem_enc failed!\n", CRYPTO_ALGNAME); return -2; @@ -73,14 +82,16 @@ int main(void) { fprintf(fh, "\n"); rc = crypto_kem_dec(shared_secret_d, ciphertext, secret_key); - if (rc != 0) { + if (rc != 0) + { fprintf(stderr, "[kat_kem] %s ERROR: crypto_kem_dec failed!\n", CRYPTO_ALGNAME); return -3; } rc = memcmp(shared_secret_e, shared_secret_d, CRYPTO_BYTES); - if (rc != 0) { + if (rc != 0) + { fprintf(stderr, "[kat_kem] %s ERROR: shared secrets are not equal\n", CRYPTO_ALGNAME); return -4; diff --git a/test/hal/hal.c b/test/hal/hal.c index eadde0bf1..aec2d94cd 100644 --- a/test/hal/hal.c +++ b/test/hal/hal.c @@ -41,7 +41,8 @@ void enable_cyclecounter(void) {} void disable_cyclecounter(void) {} -uint64_t get_cyclecounter(void) { +uint64_t get_cyclecounter(void) +{ uint64_t result; __asm__ volatile("rdtsc; shlq $32,%%rdx; orq %%rdx,%%rax" @@ -54,7 +55,8 @@ uint64_t get_cyclecounter(void) { #elif defined(__AARCH64EL__) || defined(_M_ARM64) -void enable_cyclecounter(void) { +void enable_cyclecounter(void) +{ uint64_t tmp; __asm __volatile( "mrs %[tmp], pmcr_el0\n" @@ -66,7 +68,8 @@ void enable_cyclecounter(void) { : [tmp] "=r"(tmp)); } -void disable_cyclecounter(void) { +void disable_cyclecounter(void) +{ uint64_t tmp; __asm __volatile( "mov %[tmp], #0x3f\n" @@ -75,7 +78,8 @@ void disable_cyclecounter(void) { : [tmp] "=r"(tmp)); } -uint64_t get_cyclecounter(void) { +uint64_t get_cyclecounter(void) +{ uint64_t retval; __asm __volatile("mrs %[retval], pmccntr_el0\n" : [retval] "=r"(retval)); return retval; @@ -97,7 +101,8 @@ uint64_t get_cyclecounter(void) { #include static int perf_fd = 0; -void enable_cyclecounter(void) { +void enable_cyclecounter(void) +{ struct perf_event_attr pe; memset(&pe, 0, sizeof(struct perf_event_attr)); pe.type = PERF_TYPE_HARDWARE; @@ -113,19 +118,24 @@ void enable_cyclecounter(void) { ioctl(perf_fd, PERF_EVENT_IOC_ENABLE, 0); } -void disable_cyclecounter(void) { +void disable_cyclecounter(void) +{ ioctl(perf_fd, PERF_EVENT_IOC_DISABLE, 0); close(perf_fd); } -uint64_t get_cyclecounter(void) { +uint64_t get_cyclecounter(void) +{ long long cpu_cycles; ioctl(perf_fd, PERF_EVENT_IOC_DISABLE, 0); ssize_t read_count = read(perf_fd, &cpu_cycles, sizeof(cpu_cycles)); - if (read_count < 0) { + if (read_count < 0) + { perror("read"); exit(EXIT_FAILURE); - } else if (read_count == 0) { + } + else if (read_count == 0) + { /* Should not happen */ printf("perf counter empty\n"); exit(EXIT_FAILURE); @@ -197,39 +207,47 @@ uint64_t g_counters[COUNTERS_COUNT]; uint64_t g_config[COUNTERS_COUNT]; -static void configure_rdtsc(void) { - if (kpc_force_all_ctrs_set(1)) { +static void configure_rdtsc(void) +{ + if (kpc_force_all_ctrs_set(1)) + { printf("kpc_force_all_ctrs_set failed\n"); return; } - if (kpc_set_counting(KPC_MASK)) { + if (kpc_set_counting(KPC_MASK)) + { printf("kpc_set_counting failed\n"); return; } - if (kpc_set_thread_counting(KPC_MASK)) { + if (kpc_set_thread_counting(KPC_MASK)) + { printf("kpc_set_thread_counting failed\n"); return; } - if (kpc_set_config(KPC_MASK, g_config)) { + if (kpc_set_config(KPC_MASK, g_config)) + { printf("kpc_set_config failed\n"); return; } } -static void init_rdtsc(void) { +static void init_rdtsc(void) +{ void *kperf = dlopen( "/System/Library/PrivateFrameworks/kperf.framework/Versions/A/kperf", RTLD_LAZY); - if (!kperf) { + if (!kperf) + { printf("kperf = %p\n", kperf); return; } #define F(ret, name, ...) \ name = (name##proc *)(dlsym(kperf, #name)); \ - if (!name) { \ + if (!name) \ + { \ printf("%s = %p\n", #name, (void *)name); \ return; \ } @@ -239,12 +257,16 @@ static void init_rdtsc(void) { g_config[0] = CPMU_CORE_CYCLE | CFGWORD_EL0A64EN_MASK; } -void enable_cyclecounter(void) { +void enable_cyclecounter(void) +{ int test_high_perf_cores = 1; - if (test_high_perf_cores) { + if (test_high_perf_cores) + { pthread_set_qos_class_self_np(QOS_CLASS_USER_INTERACTIVE, 0); - } else { + } + else + { pthread_set_qos_class_self_np(QOS_CLASS_BACKGROUND, 0); } init_rdtsc(); @@ -253,8 +275,10 @@ void enable_cyclecounter(void) { void disable_cyclecounter(void) { return; } -uint64_t get_cyclecounter(void) { - if (kpc_get_thread_counters(0, COUNTERS_COUNT, g_counters)) { +uint64_t get_cyclecounter(void) +{ + if (kpc_get_thread_counters(0, COUNTERS_COUNT, g_counters)) + { printf("kpc_get_thread_counters failed\n"); return 1; } diff --git a/test/nistrng/aes.c b/test/nistrng/aes.c index d32f02c6d..e15ae6a6a 100644 --- a/test/nistrng/aes.c +++ b/test/nistrng/aes.c @@ -34,40 +34,46 @@ #include "aes.h" -static inline uint32_t br_dec32le(const unsigned char *src) { +static inline uint32_t br_dec32le(const unsigned char *src) +{ return (uint32_t)src[0] | ((uint32_t)src[1] << 8) | ((uint32_t)src[2] << 16) | ((uint32_t)src[3] << 24); } -static void br_range_dec32le(uint32_t *v, size_t num, - const unsigned char *src) { - while (num-- > 0) { +static void br_range_dec32le(uint32_t *v, size_t num, const unsigned char *src) +{ + while (num-- > 0) + { *v++ = br_dec32le(src); src += 4; } } -static inline uint32_t br_swap32(uint32_t x) { +static inline uint32_t br_swap32(uint32_t x) +{ x = ((x & (uint32_t)0x00FF00FF) << 8) | ((x >> 8) & (uint32_t)0x00FF00FF); return (x << 16) | (x >> 16); } -static inline void br_enc32le(unsigned char *dst, uint32_t x) { +static inline void br_enc32le(unsigned char *dst, uint32_t x) +{ dst[0] = (unsigned char)x; dst[1] = (unsigned char)(x >> 8); dst[2] = (unsigned char)(x >> 16); dst[3] = (unsigned char)(x >> 24); } -static void br_range_enc32le(unsigned char *dst, const uint32_t *v, - size_t num) { - while (num-- > 0) { +static void br_range_enc32le(unsigned char *dst, const uint32_t *v, size_t num) +{ + while (num-- > 0) + { br_enc32le(dst, *v++); dst += 4; } } -static void br_aes_ct64_bitslice_Sbox(uint64_t *q) { +static void br_aes_ct64_bitslice_Sbox(uint64_t *q) +{ /* * This S-box implementation is a straightforward translation of * the circuit described by Boyar and Peralta in "A new @@ -241,9 +247,11 @@ static void br_aes_ct64_bitslice_Sbox(uint64_t *q) { q[0] = s7; } -static void br_aes_ct64_ortho(uint64_t *q) { +static void br_aes_ct64_ortho(uint64_t *q) +{ #define SWAPN(cl, ch, s, x, y) \ - do { \ + do \ + { \ uint64_t a, b; \ a = (x); \ b = (y); \ @@ -272,7 +280,8 @@ static void br_aes_ct64_ortho(uint64_t *q) { } static void br_aes_ct64_interleave_in(uint64_t *q0, uint64_t *q1, - const uint32_t *w) { + const uint32_t *w) +{ uint64_t x0, x1, x2, x3; x0 = w[0]; @@ -299,7 +308,8 @@ static void br_aes_ct64_interleave_in(uint64_t *q0, uint64_t *q1, *q1 = x1 | (x3 << 8); } -static void br_aes_ct64_interleave_out(uint32_t *w, uint64_t q0, uint64_t q1) { +static void br_aes_ct64_interleave_out(uint32_t *w, uint64_t q0, uint64_t q1) +{ uint64_t x0, x1, x2, x3; x0 = q0 & (uint64_t)0x00FF00FF00FF00FF; @@ -323,7 +333,8 @@ static void br_aes_ct64_interleave_out(uint32_t *w, uint64_t q0, uint64_t q1) { static const unsigned char Rcon[] = {0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1B, 0x36}; -static uint32_t sub_word(uint32_t x) { +static uint32_t sub_word(uint32_t x) +{ uint64_t q[8]; memset(q, 0, sizeof q); @@ -335,7 +346,8 @@ static uint32_t sub_word(uint32_t x) { } static void br_aes_ct64_keysched(uint64_t *comp_skey, const unsigned char *key, - unsigned int key_len) { + unsigned int key_len) +{ unsigned int i, j, k, nk, nkf; uint32_t tmp; uint32_t skey[60]; @@ -345,22 +357,28 @@ static void br_aes_ct64_keysched(uint64_t *comp_skey, const unsigned char *key, nkf = ((nrounds + 1) << 2); br_range_dec32le(skey, (key_len >> 2), key); tmp = skey[(key_len >> 2) - 1]; - for (i = nk, j = 0, k = 0; i < nkf; i++) { - if (j == 0) { + for (i = nk, j = 0, k = 0; i < nkf; i++) + { + if (j == 0) + { tmp = (tmp << 24) | (tmp >> 8); tmp = sub_word(tmp) ^ Rcon[k]; - } else if (nk > 6 && j == 4) { + } + else if (nk > 6 && j == 4) + { tmp = sub_word(tmp); } tmp ^= skey[i - nk]; skey[i] = tmp; - if (++j == nk) { + if (++j == nk) + { j = 0; k++; } } - for (i = 0, j = 0; i < nkf; i += 4, j += 2) { + for (i = 0, j = 0; i < nkf; i += 4, j += 2) + { uint64_t q[8]; br_aes_ct64_interleave_in(&q[0], &q[4], skey + i); @@ -383,11 +401,13 @@ static void br_aes_ct64_keysched(uint64_t *comp_skey, const unsigned char *key, } static void br_aes_ct64_skey_expand(uint64_t *skey, const uint64_t *comp_skey, - unsigned int nrounds) { + unsigned int nrounds) +{ unsigned u, v, n; n = (nrounds + 1) << 1; - for (u = 0, v = 0; u < n; u++, v += 4) { + for (u = 0, v = 0; u < n; u++, v += 4) + { uint64_t x0, x1, x2, x3; x0 = x1 = x2 = x3 = comp_skey[u]; @@ -405,7 +425,8 @@ static void br_aes_ct64_skey_expand(uint64_t *skey, const uint64_t *comp_skey, } } -static inline void add_round_key(uint64_t *q, const uint64_t *sk) { +static inline void add_round_key(uint64_t *q, const uint64_t *sk) +{ q[0] ^= sk[0]; q[1] ^= sk[1]; q[2] ^= sk[2]; @@ -416,10 +437,12 @@ static inline void add_round_key(uint64_t *q, const uint64_t *sk) { q[7] ^= sk[7]; } -static inline void shift_rows(uint64_t *q) { +static inline void shift_rows(uint64_t *q) +{ int i; - for (i = 0; i < 8; i++) { + for (i = 0; i < 8; i++) + { uint64_t x; x = q[i]; @@ -435,7 +458,8 @@ static inline void shift_rows(uint64_t *q) { static inline uint64_t rotr32(uint64_t x) { return (x << 32) | (x >> 32); } -static inline void mix_columns(uint64_t *q) { +static inline void mix_columns(uint64_t *q) +{ uint64_t q0, q1, q2, q3, q4, q5, q6, q7; uint64_t r0, r1, r2, r3, r4, r5, r6, r7; @@ -466,25 +490,29 @@ static inline void mix_columns(uint64_t *q) { q[7] = q6 ^ r6 ^ r7 ^ rotr32(q7 ^ r7); } -static void inc4_be(uint32_t *x) { +static void inc4_be(uint32_t *x) +{ uint32_t t = br_swap32(*x) + 4; *x = br_swap32(t); } static void aes_ecb4x(unsigned char out[64], const uint32_t ivw[16], - const uint64_t *sk_exp, unsigned int nrounds) { + const uint64_t *sk_exp, unsigned int nrounds) +{ uint32_t w[16]; uint64_t q[8]; unsigned int i; memcpy(w, ivw, sizeof(w)); - for (i = 0; i < 4; i++) { + for (i = 0; i < 4; i++) + { br_aes_ct64_interleave_in(&q[i], &q[i + 4], w + (i << 2)); } br_aes_ct64_ortho(q); add_round_key(q, sk_exp); - for (i = 1; i < nrounds; i++) { + for (i = 1; i < nrounds; i++) + { br_aes_ct64_bitslice_Sbox(q); shift_rows(q); mix_columns(q); @@ -495,14 +523,16 @@ static void aes_ecb4x(unsigned char out[64], const uint32_t ivw[16], add_round_key(q, sk_exp + 8 * nrounds); br_aes_ct64_ortho(q); - for (i = 0; i < 4; i++) { + for (i = 0; i < 4; i++) + { br_aes_ct64_interleave_out(w + (i << 2), q[i], q[i + 4]); } br_range_enc32le(out, w, 16); } static void aes_ctr4x(unsigned char out[64], uint32_t ivw[16], - const uint64_t *sk_exp, unsigned int nrounds) { + const uint64_t *sk_exp, unsigned int nrounds) +{ aes_ecb4x(out, ivw, sk_exp, nrounds); /* Increase counter for next 4 blocks */ @@ -513,11 +543,13 @@ static void aes_ctr4x(unsigned char out[64], uint32_t ivw[16], } static void aes_ecb(unsigned char *out, const unsigned char *in, size_t nblocks, - const uint64_t *rkeys, unsigned int nrounds) { + const uint64_t *rkeys, unsigned int nrounds) +{ uint32_t blocks[16]; unsigned char t[64]; - while (nblocks >= 4) { + while (nblocks >= 4) + { br_range_dec32le(blocks, 16, in); aes_ecb4x(out, blocks, rkeys, nrounds); nblocks -= 4; @@ -525,7 +557,8 @@ static void aes_ecb(unsigned char *out, const unsigned char *in, size_t nblocks, out += 64; } - if (nblocks) { + if (nblocks) + { br_range_dec32le(blocks, nblocks * 4, in); aes_ecb4x(t, blocks, rkeys, nrounds); memcpy(out, t, nblocks * 16); @@ -533,7 +566,8 @@ static void aes_ecb(unsigned char *out, const unsigned char *in, size_t nblocks, } static void aes_ctr(unsigned char *out, size_t outlen, const unsigned char *iv, - const uint64_t *rkeys, unsigned int nrounds) { + const uint64_t *rkeys, unsigned int nrounds) +{ uint32_t ivw[16]; size_t i; uint32_t cc = 0; @@ -547,25 +581,30 @@ static void aes_ctr(unsigned char *out, size_t outlen, const unsigned char *iv, ivw[11] = br_swap32(cc + 2); ivw[15] = br_swap32(cc + 3); - while (outlen > 64) { + while (outlen > 64) + { aes_ctr4x(out, ivw, rkeys, nrounds); out += 64; outlen -= 64; } - if (outlen > 0) { + if (outlen > 0) + { unsigned char tmp[64]; aes_ctr4x(tmp, ivw, rkeys, nrounds); - for (i = 0; i < outlen; i++) { + for (i = 0; i < outlen; i++) + { out[i] = tmp[i]; } } } -void aes128_ecb_keyexp(aes128ctx *r, const unsigned char *key) { +void aes128_ecb_keyexp(aes128ctx *r, const unsigned char *key) +{ uint64_t skey[22]; r->sk_exp = malloc(sizeof(uint64_t) * PQC_AES128_STATESIZE); - if (r->sk_exp == NULL) { + if (r->sk_exp == NULL) + { exit(111); } @@ -573,14 +612,17 @@ void aes128_ecb_keyexp(aes128ctx *r, const unsigned char *key) { br_aes_ct64_skey_expand(r->sk_exp, skey, 10); } -void aes128_ctr_keyexp(aes128ctx *r, const unsigned char *key) { +void aes128_ctr_keyexp(aes128ctx *r, const unsigned char *key) +{ aes128_ecb_keyexp(r, key); } -void aes192_ecb_keyexp(aes192ctx *r, const unsigned char *key) { +void aes192_ecb_keyexp(aes192ctx *r, const unsigned char *key) +{ uint64_t skey[26]; r->sk_exp = malloc(sizeof(uint64_t) * PQC_AES192_STATESIZE); - if (r->sk_exp == NULL) { + if (r->sk_exp == NULL) + { exit(111); } @@ -588,14 +630,17 @@ void aes192_ecb_keyexp(aes192ctx *r, const unsigned char *key) { br_aes_ct64_skey_expand(r->sk_exp, skey, 12); } -void aes192_ctr_keyexp(aes192ctx *r, const unsigned char *key) { +void aes192_ctr_keyexp(aes192ctx *r, const unsigned char *key) +{ aes192_ecb_keyexp(r, key); } -void aes256_ecb_keyexp(aes256ctx *r, const unsigned char *key) { +void aes256_ecb_keyexp(aes256ctx *r, const unsigned char *key) +{ uint64_t skey[30]; r->sk_exp = malloc(sizeof(uint64_t) * PQC_AES256_STATESIZE); - if (r->sk_exp == NULL) { + if (r->sk_exp == NULL) + { exit(111); } @@ -603,37 +648,44 @@ void aes256_ecb_keyexp(aes256ctx *r, const unsigned char *key) { br_aes_ct64_skey_expand(r->sk_exp, skey, 14); } -void aes256_ctr_keyexp(aes256ctx *r, const unsigned char *key) { +void aes256_ctr_keyexp(aes256ctx *r, const unsigned char *key) +{ aes256_ecb_keyexp(r, key); } void aes128_ecb(unsigned char *out, const unsigned char *in, size_t nblocks, - const aes128ctx *ctx) { + const aes128ctx *ctx) +{ aes_ecb(out, in, nblocks, ctx->sk_exp, 10); } void aes128_ctr(unsigned char *out, size_t outlen, const unsigned char *iv, - const aes128ctx *ctx) { + const aes128ctx *ctx) +{ aes_ctr(out, outlen, iv, ctx->sk_exp, 10); } void aes192_ecb(unsigned char *out, const unsigned char *in, size_t nblocks, - const aes192ctx *ctx) { + const aes192ctx *ctx) +{ aes_ecb(out, in, nblocks, ctx->sk_exp, 12); } void aes192_ctr(unsigned char *out, size_t outlen, const unsigned char *iv, - const aes192ctx *ctx) { + const aes192ctx *ctx) +{ aes_ctr(out, outlen, iv, ctx->sk_exp, 12); } void aes256_ecb(unsigned char *out, const unsigned char *in, size_t nblocks, - const aes256ctx *ctx) { + const aes256ctx *ctx) +{ aes_ecb(out, in, nblocks, ctx->sk_exp, 14); } void aes256_ctr(unsigned char *out, size_t outlen, const unsigned char *iv, - const aes256ctx *ctx) { + const aes256ctx *ctx) +{ aes_ctr(out, outlen, iv, ctx->sk_exp, 14); } diff --git a/test/nistrng/aes.h b/test/nistrng/aes.h index e939261c8..8a4f7721b 100644 --- a/test/nistrng/aes.h +++ b/test/nistrng/aes.h @@ -15,17 +15,20 @@ // We've put these states on the heap to make sure ctx_release is used. #define PQC_AES128_STATESIZE 88 -typedef struct { +typedef struct +{ uint64_t *sk_exp; } aes128ctx; #define PQC_AES192_STATESIZE 104 -typedef struct { +typedef struct +{ uint64_t *sk_exp; } aes192ctx; #define PQC_AES256_STATESIZE 120 -typedef struct { +typedef struct +{ uint64_t *sk_exp; } aes256ctx; diff --git a/test/nistrng/rng.c b/test/nistrng/rng.c index 9f0f9f3ea..81ebf235c 100644 --- a/test/nistrng/rng.c +++ b/test/nistrng/rng.c @@ -8,7 +8,8 @@ #include "aes.h" #include "nistrng.h" -typedef struct { +typedef struct +{ unsigned char key[AES256_KEYBYTES]; unsigned char ctr[AES_BLOCKBYTES]; } nistkatctx; @@ -17,18 +18,22 @@ static nistkatctx ctx; static void _aes256_ecb(unsigned char key[AES256_KEYBYTES], unsigned char ctr[AES_BLOCKBYTES], - unsigned char buffer[AES_BLOCKBYTES]) { + unsigned char buffer[AES_BLOCKBYTES]) +{ aes256ctx aesctx; aes256_ecb_keyexp(&aesctx, key); aes256_ecb(buffer, ctr, 1, &aesctx); aes256_ctx_release(&aesctx); } -static void aes256_block_update(uint8_t block[AES_BLOCKBYTES]) { - for (int j = AES_BLOCKBYTES - 1; j >= 0; j--) { +static void aes256_block_update(uint8_t block[AES_BLOCKBYTES]) +{ + for (int j = AES_BLOCKBYTES - 1; j >= 0; j--) + { ctx.ctr[j]++; - if (ctx.ctr[j] != 0x00) { + if (ctx.ctr[j] != 0x00) + { break; } } @@ -37,16 +42,20 @@ static void aes256_block_update(uint8_t block[AES_BLOCKBYTES]) { } static void nistkat_update(const unsigned char *provided_data, - unsigned char *key, unsigned char *ctr) { + unsigned char *key, unsigned char *ctr) +{ int len = AES256_KEYBYTES + AES_BLOCKBYTES; uint8_t tmp[len]; - for (int i = 0; i < len / AES_BLOCKBYTES; i++) { + for (int i = 0; i < len / AES_BLOCKBYTES; i++) + { aes256_block_update(tmp + AES_BLOCKBYTES * i); } - if (provided_data) { - for (int i = 0; i < len; i++) { + if (provided_data) + { + for (int i = 0; i < len; i++) + { tmp[i] ^= provided_data[i]; } } @@ -59,14 +68,17 @@ void nist_kat_init( unsigned char entropy_input[AES256_KEYBYTES + AES_BLOCKBYTES], const unsigned char personalization_string[AES256_KEYBYTES + AES_BLOCKBYTES], - int security_strength) { + int security_strength) +{ int len = AES256_KEYBYTES + AES_BLOCKBYTES; uint8_t seed_material[len]; (void)security_strength; memcpy(seed_material, entropy_input, len); - if (personalization_string) { - for (int i = 0; i < len; i++) { + if (personalization_string) + { + for (int i = 0; i < len; i++) + { seed_material[i] ^= personalization_string[i]; } } @@ -75,18 +87,21 @@ void nist_kat_init( nistkat_update(seed_material, ctx.key, ctx.ctr); } -void randombytes(uint8_t *buf, size_t n) { +void randombytes(uint8_t *buf, size_t n) +{ uint8_t block[AES_BLOCKBYTES]; size_t nb = n / AES_BLOCKBYTES; size_t tail = n % AES_BLOCKBYTES; - for (size_t i = 0; i < nb; i++) { + for (size_t i = 0; i < nb; i++) + { aes256_block_update(block); memcpy(buf + i * AES_BLOCKBYTES, block, AES_BLOCKBYTES); } - if (tail > 0) { + if (tail > 0) + { aes256_block_update(block); memcpy(buf + nb * AES_BLOCKBYTES, block, tail); } diff --git a/test/notrandombytes/notrandombytes.c b/test/notrandombytes/notrandombytes.c index 96fad3fa5..182c2ec55 100644 --- a/test/notrandombytes/notrandombytes.c +++ b/test/notrandombytes/notrandombytes.c @@ -22,7 +22,8 @@ static int32_t outleft = 0; #define ROTATE(x, b) (((x) << (b)) | ((x) >> (32 - (b)))) #define MUSH(i, b) x = t[i] += (((x ^ seed[i]) + sum) ^ ROTATE(x, b)); -static void surf(void) { +static void surf(void) +{ uint32_t t[12]; uint32_t x; uint32_t sum = 0; @@ -30,15 +31,19 @@ static void surf(void) { int32_t i; int32_t loop; - for (i = 0; i < 12; ++i) { + for (i = 0; i < 12; ++i) + { t[i] = in[i] ^ seed[12 + i]; } - for (i = 0; i < 8; ++i) { + for (i = 0; i < 8; ++i) + { out[i] = seed[24 + i]; } x = t[11]; - for (loop = 0; loop < 2; ++loop) { - for (r = 0; r < 16; ++r) { + for (loop = 0; loop < 2; ++loop) + { + for (r = 0; r < 16; ++r) + { sum += 0x9e3779b9; MUSH(0, 5) MUSH(1, 7) @@ -53,18 +58,25 @@ static void surf(void) { MUSH(10, 9) MUSH(11, 13) } - for (i = 0; i < 8; ++i) { + for (i = 0; i < 8; ++i) + { out[i] ^= t[i + 4]; } } } -void randombytes(uint8_t *buf, size_t n) { - while (n > 0) { - if (!outleft) { - if (!++in[0]) { - if (!++in[1]) { - if (!++in[2]) { +void randombytes(uint8_t *buf, size_t n) +{ + while (n > 0) + { + if (!outleft) + { + if (!++in[0]) + { + if (!++in[1]) + { + if (!++in[2]) + { ++in[3]; } } diff --git a/test/test_mlkem.c b/test/test_mlkem.c index 1fed073af..5a094f88b 100644 --- a/test/test_mlkem.c +++ b/test/test_mlkem.c @@ -8,7 +8,8 @@ #define NTESTS 1000 -static int test_keys(void) { +static int test_keys(void) +{ uint8_t pk[CRYPTO_PUBLICKEYBYTES]; uint8_t sk[CRYPTO_SECRETKEYBYTES]; uint8_t ct[CRYPTO_CIPHERTEXTBYTES]; @@ -24,7 +25,8 @@ static int test_keys(void) { // Alice uses Bobs response to get her shared key crypto_kem_dec(key_a, ct, sk); - if (memcmp(key_a, key_b, CRYPTO_BYTES)) { + if (memcmp(key_a, key_b, CRYPTO_BYTES)) + { printf("ERROR keys\n"); return 1; } @@ -32,7 +34,8 @@ static int test_keys(void) { return 0; } -static int test_invalid_pk(void) { +static int test_invalid_pk(void) +{ uint8_t pk[CRYPTO_PUBLICKEYBYTES]; uint8_t sk[CRYPTO_SECRETKEYBYTES]; uint8_t ct[CRYPTO_CIPHERTEXTBYTES]; @@ -44,7 +47,8 @@ static int test_invalid_pk(void) { // Bob derives a secret key and creates a response rc = crypto_kem_enc(ct, key_b, pk); - if (rc) { + if (rc) + { printf("ERROR test_invalid_pk\n"); return 1; } @@ -55,14 +59,16 @@ static int test_invalid_pk(void) { // Bob derives a secret key and creates a response rc = crypto_kem_enc(ct, key_b, pk); - if (!rc) { + if (!rc) + { printf("ERROR test_invalid_pk\n"); return 1; } return 0; } -static int test_invalid_sk_a(void) { +static int test_invalid_sk_a(void) +{ uint8_t pk[CRYPTO_PUBLICKEYBYTES]; uint8_t sk[CRYPTO_SECRETKEYBYTES]; uint8_t ct[CRYPTO_CIPHERTEXTBYTES]; @@ -82,12 +88,14 @@ static int test_invalid_sk_a(void) { // Alice uses Bobs response to get her shared key // This should fail due to wrong sk rc = crypto_kem_dec(key_a, ct, sk); - if (rc) { + if (rc) + { printf("ERROR test_invalid_sk_a\n"); return 1; } - if (!memcmp(key_a, key_b, CRYPTO_BYTES)) { + if (!memcmp(key_a, key_b, CRYPTO_BYTES)) + { printf("ERROR invalid sk\n"); return 1; } @@ -95,7 +103,8 @@ static int test_invalid_sk_a(void) { return 0; } -static int test_invalid_sk_b(void) { +static int test_invalid_sk_b(void) +{ uint8_t pk[CRYPTO_PUBLICKEYBYTES]; uint8_t sk[CRYPTO_SECRETKEYBYTES]; uint8_t ct[CRYPTO_CIPHERTEXTBYTES]; @@ -115,7 +124,8 @@ static int test_invalid_sk_b(void) { // Alice uses Bobs response to get her shared key // This should fail due to the input validation rc = crypto_kem_dec(key_a, ct, sk); - if (!rc) { + if (!rc) + { printf("ERROR test_invalid_sk_b\n"); return 1; } @@ -123,7 +133,8 @@ static int test_invalid_sk_b(void) { return 0; } -static int test_invalid_ciphertext(void) { +static int test_invalid_ciphertext(void) +{ uint8_t pk[CRYPTO_PUBLICKEYBYTES]; uint8_t sk[CRYPTO_SECRETKEYBYTES]; uint8_t ct[CRYPTO_CIPHERTEXTBYTES]; @@ -132,7 +143,8 @@ static int test_invalid_ciphertext(void) { uint8_t b; size_t pos; - do { + do + { randombytes(&b, sizeof(uint8_t)); } while (!b); randombytes((uint8_t *)&pos, sizeof(size_t)); @@ -149,7 +161,8 @@ static int test_invalid_ciphertext(void) { // Alice uses Bobs response to get her shared key crypto_kem_dec(key_a, ct, sk); - if (!memcmp(key_a, key_b, CRYPTO_BYTES)) { + if (!memcmp(key_a, key_b, CRYPTO_BYTES)) + { printf("ERROR invalid ciphertext\n"); return 1; } @@ -157,17 +170,20 @@ static int test_invalid_ciphertext(void) { return 0; } -int main(void) { +int main(void) +{ unsigned int i; int r; - for (i = 0; i < NTESTS; i++) { + for (i = 0; i < NTESTS; i++) + { r = test_keys(); r |= test_invalid_pk(); r |= test_invalid_sk_a(); r |= test_invalid_sk_b(); r |= test_invalid_ciphertext(); - if (r) { + if (r) + { return 1; } }