Skip to content

Commit ad7a6f9

Browse files
authored
Merge pull request #901 from pq-code-package/readme_update
Update and extend README's on formal verification
2 parents 95c035d + 3c4bd36 commit ad7a6f9

File tree

4 files changed

+116
-33
lines changed

4 files changed

+116
-33
lines changed

README.md

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,12 @@
1313
mlkem-native is a secure, fast, and portable C90 implementation of [ML-KEM](https://doi.org/10.6028/NIST.FIPS.203).
1414
It is a fork of the ML-KEM [reference implementation](https://github.com/pq-crystals/kyber/tree/main/ref).
1515

16+
Large parts of mlkem-native are formally verified: All C code in [mlkem/*](mlkem) and [mlkem/fips202/*](mlkem/fips202) is verified
17+
using [CBMC](https://github.com/diffblue/cbmc) to be free of various classes of undefined behaviour. [HOL-Light](https://github.com/jrh13/hol-light) is used to verify
18+
the functional correctness of core AArch64 assembly routines.
19+
1620
mlkem-native includes native backends for AArch64 and AVX2, offering competitive performance on most Arm, Intel, and AMD platforms
17-
(see [benchmarks](https://pq-code-package.github.io/mlkem-native/dev/bench/)). The frontend and the C backend (i.e., all C code in [mlkem/*](mlkem) and [mlkem/fips202/*](mlkem/fips202)) are verified
18-
using [CBMC](https://github.com/diffblue/cbmc) to be free of various classes of undefined behaviour. In particular, there are no out of
19-
bounds accesses, nor integer overflows during optimized modular arithmetic.
20-
[HOL-Light](https://github.com/jrh13/hol-light) is used to verify the functional correctness of core AArch64 assembly routines.
21+
(see [benchmarks](https://pq-code-package.github.io/mlkem-native/dev/bench/)).
2122

2223
mlkem-native is supported by the [Post-Quantum Cryptography Alliance](https://pqca.org/) as part of the [Linux Foundation](https://linuxfoundation.org/).
2324

proofs/README.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
[//]: # (SPDX-License-Identifier: CC-BY-4.0)
2+
3+
# Proofs for mlkem-native
4+
5+
This directory contains material related to the formal verification of the source code of mlkem-native.
6+
7+
## C verification: CBMC
8+
9+
We use the [C Bounded Model Checker (CBMC)](https://github.com/diffblue/cbmc) to show the absence of various classes of undefined behaviour in the mlkem-native C source, including out of bounds memory accesses and integer overflows. See [proofs/cbmc](cbmc).
10+
11+
## Assembly verification: HOL-Light
12+
13+
We use the [HOL-Light](https://github.com/jrh13/hol-light) interactive theorem prover alongside the verification infrastructure from [s2n-bignum](https://github.com/awslabs/s2n-bignum) to show the functional correctness of various highly optimized assembly routines in mlkem-native at the object-code level. See [proofs/hol_light/arm](hol_light/arm).

proofs/cbmc/README.md

Lines changed: 37 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,18 +3,46 @@
33
CBMC proofs
44
===========
55

6-
# Overview
6+
This directory contains the infrastructure for running [CBMC](https://github.com/diffblue/cbmc) proofs
7+
for the absence of certain classes of undefined behaviour for parts of the C-code in mlkem-native.
78

8-
This directory contains [CBMC](https://github.com/diffblue/cbmc) proofs for the absence
9-
of certain classes of undefined behaviour for parts of the C-code in mlkem-native.
9+
## Primer
1010

11-
Proofs are organized by functions, with the harnesses and proofs for each function
12-
in a separate directory.
11+
Proofs are organized by functions, with the harnesses for each function in a separate directory.
12+
Specifications are directly embedded inside the mlkem-native C-source as contract and loop annotations;
13+
the CBMC harnesses are boilerplate only and don't add to the specification.
1314

14-
See the [Proof Guide](proof_guide.md) for a walkthrough of how to use CBMC and
15-
develop new proofs.
15+
For example, these are the specification and proof of the `poly_add` function:
16+
```c
17+
void mlk_poly_add(mlk_poly *r, const mlk_poly *b)
18+
__contract__(
19+
requires(memory_no_alias(r, sizeof(mlk_poly)))
20+
requires(memory_no_alias(b, sizeof(mlk_poly)))
21+
requires(forall(k0, 0, MLKEM_N, (int32_t) r->coeffs[k0] + b->coeffs[k0] <= INT16_MAX))
22+
requires(forall(k1, 0, MLKEM_N, (int32_t) r->coeffs[k1] + b->coeffs[k1] >= INT16_MIN))
23+
ensures(forall(k, 0, MLKEM_N, r->coeffs[k] == old(*r).coeffs[k] + b->coeffs[k]))
24+
assigns(memory_slice(r, sizeof(mlk_poly)))
25+
);
1626

17-
# Usage
27+
...
28+
29+
void mlk_poly_add(mlk_poly *r, const mlk_poly *b)
30+
{
31+
unsigned i;
32+
for (i = 0; i < MLKEM_N; i++)
33+
__loop__(
34+
invariant(i <= MLKEM_N)
35+
invariant(forall(k0, i, MLKEM_N, r->coeffs[k0] == loop_entry(*r).coeffs[k0]))
36+
invariant(forall(k1, 0, i, r->coeffs[k1] == loop_entry(*r).coeffs[k1] + b->coeffs[k1])))
37+
{
38+
r->coeffs[i] = r->coeffs[i] + b->coeffs[i];
39+
}
40+
}
41+
```
42+
43+
See the [Proof Guide](proof_guide.md) for a walkthrough of how to use CBMC and develop new proofs.
44+
45+
## Reproducing the proofs
1846
1947
To run all proofs, print a summary at the end and reflect overall
2048
success/failure in the error code, use
@@ -31,6 +59,6 @@ Alternatively, you can use the [tests](../../scripts/tests) script, see
3159
tests cbmc --help
3260
```
3361
34-
# Covered functions
62+
## What is covered?
3563
3664
Each proved function has an eponymous sub-directory of its own. Use [list_proofs.sh](list_proofs.sh) to see the list of functions covered.

proofs/hol_light/arm/README.md

Lines changed: 61 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -9,31 +9,52 @@ prover, utilizing the assembly verification infrastructure from [s2n-bignum](htt
99

1010
Each function is proved in a separate `.ml` file in [proofs/](proofs). Each file
1111
contains the byte code being verified, as well as the specification that is being
12-
proved. Specifications are essentially Hoare triples, with the noteworthy difference
13-
that the program is implicit as the content of memory at the PC; which is asserted to
14-
be the code under verification as part of the precondition.
12+
proved.
1513

16-
## What is covered?
14+
## Primer
1715

18-
At present, this directory contains functional correctness proofs for the following functions:
16+
Proofs are 'post-hoc' in the sense that HOL-Light/s2n-bignum operate on the final object code. In particular, the means by which the code was generated (including the [SLOTHY](https://github.com/slothy-optimizer/slothy/) superoptimizer) need not be trusted.
1917

20-
- ML-KEM Arithmetic:
21-
* AArch64 forward NTT: [mlkem_ntt.S](mlkem/mlkem_ntt.S)
22-
* AArch64 inverse NTT: [mlkem_intt.S](mlkem/mlkem_intt.S)
23-
* AArch64 base multiplications: [mlkem_poly_basemul_acc_montgomery_cached_k2.S](mlkem/mlkem_poly_basemul_acc_montgomery_cached_k2.S) [mlkem_poly_basemul_acc_montgomery_cached_k3.S](mlkem/mlkem_poly_basemul_acc_montgomery_cached_k3.S) [mlkem_poly_basemul_acc_montgomery_cached_k4.S](mlkem/mlkem_poly_basemul_acc_montgomery_cached_k4.S)
24-
* AArch64 conversion to Montgomery form: [mlkem_poly_tomont.S](mlkem/mlkem_poly_tomont.S)
25-
* AArch64 modular reduction: [mlkem_poly_reduce.S](mlkem/mlkem_poly_reduce.S)
26-
* AArch64 'multiplication cache' computation: [mlkem_poly_mulcache_compute.S](mlkem/mlkem_poly_mulcache_compute.S)
27-
- FIPS202:
28-
* Keccak-F1600 using lazy rotations (see [this paper](https://eprint.iacr.org/2022/1243)): [keccak_f1600_x1_scalar.S](mlkem/keccak_f1600_x1_scalar.S)
29-
* Keccak-F1600 using v8.4-A SHA3 instructions: [keccak_f1600_x1_v84a.S](mlkem/keccak_f1600_x1_v84a.S)
30-
* 2-fold Keccak-F1600 using v8.4-A SHA3 instructions: [keccak_f1600_x2_v84a.S](mlkem/keccak_f1600_x2_v84a.S)
31-
* 'Hybrid' 4-fold Keccak-F1600 using scalar and v8-A Neon instructions: [keccak_f1600_x4_v8a_scalar.S](mlkem/keccak_f1600_x4_v8a_scalar.S)
32-
* 'Triple hybrid' 4-fold Keccak-F1600 using scalar, v8-A Neon and v8.4-A+SHA3 Neon instructions:[keccak_f1600_x4_v8a_v84a_scalar.S](mlkem/keccak_f1600_x4_v8a_v84a_scalar.S)
18+
Specifications are essentially [Hoare triples](https://en.wikipedia.org/wiki/Hoare_logic), with the noteworthy difference that the program is implicit as the content of memory at the PC; which is asserted to
19+
be the code under verification as part of the precondition. For example, the following is the specification of the `poly_reduce` function:
3320

34-
The NTT and invNTT functions are super-optimized using [SLOTHY](https://github.com/slothy-optimizer/slothy/).
21+
```ocaml
22+
(* For all (abbreviated by `!` in HOL):
23+
- a: Source pointer
24+
- pc: Current value of Program Counter (PC)
25+
- returnaddress: Return address in the link register *)
26+
`!a x pc returnaddress.
27+
(* Assume that the program and the source pointer don't overlap *)
28+
nonoverlapping (word pc,0x124) (a,512)
29+
==> ensures arm
30+
(* Precondition *)
31+
(\s. (* The memory at the current PC is the byte-code of poly_reduce() *)
32+
aligned_bytes_loaded s (word pc) mlkem_poly_reduce_mc /\
33+
read PC s = word pc /\
34+
(* The return address is stored in the link register (LR) *)
35+
read X30 s = returnaddress /\
36+
(* The source pointer is in X0 *)
37+
C_ARGUMENTS [a] s /\
38+
(* Give a name to the memory contents at the source pointer *)
39+
!i. i < 256
40+
==> read(memory :> bytes16(word_add a (word(2 * i)))) s = x i)
41+
(* Postcondition: Eventually we reach a state where ... *)
42+
(\s.
43+
(* The PC is the original value of the link register *)
44+
read PC s = returnaddress /\
45+
(* The integers represented by the final memory contents
46+
* are the unsigned canonical reductions mod 3329
47+
* of the integers represented by the original memory contents. *)
48+
!i. i < 256
49+
==> ival(read(memory :> bytes16 (word_add a (word(2 * i)))) s) =
50+
ival(x i) rem &3329)
51+
(* Footprint: The program may modify (only) the ABI permitted registers
52+
* and flags, and the memory contents at the source pointer. *)
53+
(MAYCHANGE_REGS_AND_FLAGS_PERMITTED_BY_ABI ,,
54+
MAYCHANGE [memory :> bytes(a,512)])`
55+
```
3556

36-
## Running the proofs
57+
## Reproducing the proofs
3758

3859
To reproduce the proofs, enter the nix shell via
3960

@@ -50,3 +71,23 @@ make -C proofs/hol_light/arm
5071
will build and run the proofs. Note that this make take hours even on powerful machines.
5172

5273
For convenience, you can also use `tests hol_light` which wraps the `make` invocation above; see `tests hol_light --help`.
74+
75+
## What is covered?
76+
77+
At present, this directory contains functional correctness proofs for the following functions:
78+
79+
- ML-KEM Arithmetic:
80+
* AArch64 forward NTT: [mlkem_ntt.S](mlkem/mlkem_ntt.S)
81+
* AArch64 inverse NTT: [mlkem_intt.S](mlkem/mlkem_intt.S)
82+
* AArch64 base multiplications: [mlkem_poly_basemul_acc_montgomery_cached_k2.S](mlkem/mlkem_poly_basemul_acc_montgomery_cached_k2.S) [mlkem_poly_basemul_acc_montgomery_cached_k3.S](mlkem/mlkem_poly_basemul_acc_montgomery_cached_k3.S) [mlkem_poly_basemul_acc_montgomery_cached_k4.S](mlkem/mlkem_poly_basemul_acc_montgomery_cached_k4.S)
83+
* AArch64 conversion to Montgomery form: [mlkem_poly_tomont.S](mlkem/mlkem_poly_tomont.S)
84+
* AArch64 modular reduction: [mlkem_poly_reduce.S](mlkem/mlkem_poly_reduce.S)
85+
* AArch64 'multiplication cache' computation: [mlkem_poly_mulcache_compute.S](mlkem/mlkem_poly_mulcache_compute.S)
86+
- FIPS202:
87+
* Keccak-F1600 using lazy rotations (see [this paper](https://eprint.iacr.org/2022/1243)): [keccak_f1600_x1_scalar.S](mlkem/keccak_f1600_x1_scalar.S)
88+
* Keccak-F1600 using v8.4-A SHA3 instructions: [keccak_f1600_x1_v84a.S](mlkem/keccak_f1600_x1_v84a.S)
89+
* 2-fold Keccak-F1600 using v8.4-A SHA3 instructions: [keccak_f1600_x2_v84a.S](mlkem/keccak_f1600_x2_v84a.S)
90+
* 'Hybrid' 4-fold Keccak-F1600 using scalar and v8-A Neon instructions: [keccak_f1600_x4_v8a_scalar.S](mlkem/keccak_f1600_x4_v8a_scalar.S)
91+
* 'Triple hybrid' 4-fold Keccak-F1600 using scalar, v8-A Neon and v8.4-A+SHA3 Neon instructions:[keccak_f1600_x4_v8a_v84a_scalar.S](mlkem/keccak_f1600_x4_v8a_v84a_scalar.S)
92+
93+
The NTT and invNTT functions are super-optimized using [SLOTHY](https://github.com/slothy-optimizer/slothy/).

0 commit comments

Comments
 (0)