Skip to content

Commit

Permalink
working on suffixes
Browse files Browse the repository at this point in the history
  • Loading branch information
eschorn1 committed Apr 26, 2024
1 parent 713ffbd commit 3fed3a1
Show file tree
Hide file tree
Showing 25 changed files with 208 additions and 191 deletions.
6 changes: 5 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,11 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## 0.1.6 (2024-04-TK)
## 0.2.0 (2024-05-01)

- Removed `_vt` suffix from top-level API as constant-time operation is now confirmed

## 0.1.6 (2024-04-24)

- Additional tests in `validate_keypair_vt()`, implemented second round review feedback

Expand Down
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ workspace = { members = ['ffi'], exclude = ["ct_cm4", "dudect", "fuzz", "wasm"]

[package]
name = "fips203"
version = "0.1.6"
version = "0.2.0"
edition = "2021"
license = "MIT OR Apache-2.0"
description = "FIPS 203 (draft): Module-Lattice-Based Key-Encapsulation Mechanism"
Expand Down
16 changes: 8 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,8 @@ The functionality is extremely simple to use, as demonstrated by the following e
use fips203::ml_kem_512; // Could also be ml_kem_768 or ml_kem_1024.
use fips203::traits::{Decaps, Encaps, KeyGen, SerDes};

// Alice runs `key_gen()` and then serializes the encaps key `ek` for Bob (to bytes).
let (alice_ek, alice_dk) = ml_kem_512::KG::try_keygen_vt().unwrap();
// Alice runs `try_keygen()` and then serializes the encaps key `ek` for Bob (to bytes).
let (alice_ek, alice_dk) = ml_kem_512::KG::try_keygen().unwrap();
let alice_ek_bytes = alice_ek.into_bytes();

// Alice sends the encaps key `ek_bytes` to Bob.
Expand All @@ -37,15 +37,15 @@ let bob_ek_bytes = alice_ek_bytes;
// Bob deserializes the encaps `ek_bytes` and then runs `encaps() to get the shared
// secret `ssk` and ciphertext `ct`. He serializes the ciphertext `ct` for Alice (to bytes).
let bob_ek = ml_kem_512::EncapsKey::try_from_bytes(bob_ek_bytes).unwrap();
let (bob_ssk_bytes, bob_ct) = bob_ek.try_encaps_vt().unwrap();
let (bob_ssk_bytes, bob_ct) = bob_ek.try_encaps().unwrap();
let bob_ct_bytes = bob_ct.into_bytes();

// Bob sends the ciphertext `ct_bytes` to Alice
let alice_ct_bytes = bob_ct_bytes;

// Alice deserializes the ciphertext `ct` and runs `decaps()` with her decaps key
let alice_ct = ml_kem_512::CipherText::try_from_bytes(alice_ct_bytes).unwrap();
let alice_ssk_bytes = alice_dk.try_decaps_vt(&alice_ct).unwrap();
let alice_ssk_bytes = alice_dk.try_decaps(&alice_ct).unwrap();

// Alice and Bob will now have the same secret key
assert_eq!(bob_ssk_bytes, alice_ssk_bytes);
Expand All @@ -57,11 +57,11 @@ The Rust [Documentation][docs-link] lives under each **Module** corresponding to
## Notes

* This crate is fully functional and corresponds to the first initial public draft of FIPS 203.
* Constant-time operation targets the source-code level only, with confirmation via the embedded target and
the `dudect` dynamic tests. While the API uses a suffix of `_vt`, this will be changed in version 0.2.0.
* Constant-time operation targets the source-code level only on MSRV, with confirmation via the
embedded target and the `dudect` dynamic tests.
* Note that FIPS 203 places specific requirements on randomness per section 3.3, hence the exposed `RNG`.
* Requires Rust **1.70** or higher. The minimum supported Rust version may be changed in the future, but
it will be done with a minor version bump (when the major version is larger than 0).
* Requires Rust **1.70** or higher. The minimum supported Rust version (MSRV) may be changed in the future,
but it will be done with a minor version bump (when the major version is larger than 0).
* All on-by-default features of this library are covered by SemVer.
* The FIPS 203 draft standard and this software is experimental -- USE AT YOUR OWN RISK!

Expand Down
20 changes: 10 additions & 10 deletions benches/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,19 +7,19 @@ using fewer reductions. Also, 'u16' arithmetic has a performance penalty.

~~~
April 24, 2024
Intel® Core™ i7-7700K CPU @ 4.20GHz × 8 Circa 2017
Intel® Core™ i7-7700K CPU @ 4.20GHz × 8 Circa 2017 w/ Rust 1.77
$ RUSTFLAGS="-C target-cpu=native" cargo bench
ml_kem_512 KeyGen time: [29.536 µs 29.556 µs 29.585 µs]
ml_kem_768 KeyGen time: [49.028 µs 49.070 µs 49.120 µs]
ml_kem_1024 KeyGen time: [75.570 µs 75.942 µs 76.418 µs]
ml_kem_512 KeyGen time: [28.950 µs 28.988 µs 29.028 µs]
ml_kem_768 KeyGen time: [47.988 µs 48.048 µs 48.104 µs]
ml_kem_1024 KeyGen time: [75.186 µs 75.242 µs 75.315 µs]
ml_kem_512 Encaps time: [30.290 µs 30.303 µs 30.321 µs]
ml_kem_768 Encaps time: [47.582 µs 47.600 µs 47.627 µs]
ml_kem_1024 Encaps time: [69.700 µs 69.741 µs 69.813 µs]
ml_kem_512 Encaps time: [29.574 µs 29.589 µs 29.609 µs]
ml_kem_768 Encaps time: [46.665 µs 46.752 µs 46.889 µs]
ml_kem_1024 Encaps time: [70.703 µs 70.809 µs 70.931 µs]
ml_kem_512 Decaps time: [40.703 µs 40.819 µs 41.022 µs]
ml_kem_768 Decaps time: [63.069 µs 63.108 µs 63.163 µs]
ml_kem_1024 Decaps time: [90.232 µs 90.287 µs 90.375 µs]
ml_kem_512 Decaps time: [39.643 µs 39.671 µs 39.702 µs]
ml_kem_768 Decaps time: [61.060 µs 61.141 µs 61.221 µs]
ml_kem_1024 Decaps time: [87.695 µs 87.770 µs 87.856 µs]
~~~
30 changes: 15 additions & 15 deletions benches/benchmark.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,36 +31,36 @@ impl CryptoRng for TestRng {}
pub fn criterion_benchmark(c: &mut Criterion) {
// Generate intermediate values needed for the actual benchmark functions
let mut bench_rng = TestRng { value: 0 };
let (ek_512, dk_512) = ml_kem_512::KG::try_keygen_with_rng_vt(&mut bench_rng).unwrap();
let (_, ct_512) = ek_512.try_encaps_vt().unwrap();
let (ek_768, dk_768) = ml_kem_768::KG::try_keygen_with_rng_vt(&mut bench_rng).unwrap();
let (_, ct_768) = ek_768.try_encaps_vt().unwrap();
let (ek_1024, dk_1024) = ml_kem_1024::KG::try_keygen_with_rng_vt(&mut bench_rng).unwrap();
let (_, ct_1024) = ek_1024.try_encaps_vt().unwrap();
let (ek_512, dk_512) = ml_kem_512::KG::try_keygen_with_rng(&mut bench_rng).unwrap();
let (_, ct_512) = ek_512.try_encaps().unwrap();
let (ek_768, dk_768) = ml_kem_768::KG::try_keygen_with_rng(&mut bench_rng).unwrap();
let (_, ct_768) = ek_768.try_encaps().unwrap();
let (ek_1024, dk_1024) = ml_kem_1024::KG::try_keygen_with_rng(&mut bench_rng).unwrap();
let (_, ct_1024) = ek_1024.try_encaps().unwrap();

c.bench_function("ml_kem_512 KeyGen", |b| {
b.iter(|| ml_kem_512::KG::try_keygen_with_rng_vt(&mut bench_rng))
b.iter(|| ml_kem_512::KG::try_keygen_with_rng(&mut bench_rng))
});
c.bench_function("ml_kem_768 KeyGen", |b| {
b.iter(|| ml_kem_768::KG::try_keygen_with_rng_vt(&mut bench_rng))
b.iter(|| ml_kem_768::KG::try_keygen_with_rng(&mut bench_rng))
});
c.bench_function("ml_kem_1024 KeyGen", |b| {
b.iter(|| ml_kem_1024::KG::try_keygen_with_rng_vt(&mut bench_rng))
b.iter(|| ml_kem_1024::KG::try_keygen_with_rng(&mut bench_rng))
});

c.bench_function("ml_kem_512 Encaps", |b| {
b.iter(|| ek_512.try_encaps_with_rng_vt(&mut bench_rng))
b.iter(|| ek_512.try_encaps_with_rng(&mut bench_rng))
});
c.bench_function("ml_kem_768 Encaps", |b| {
b.iter(|| ek_768.try_encaps_with_rng_vt(&mut bench_rng))
b.iter(|| ek_768.try_encaps_with_rng(&mut bench_rng))
});
c.bench_function("ml_kem_1024 Encaps", |b| {
b.iter(|| ek_1024.try_encaps_with_rng_vt(&mut bench_rng))
b.iter(|| ek_1024.try_encaps_with_rng(&mut bench_rng))
});

c.bench_function("ml_kem_512 Decaps", |b| b.iter(|| dk_512.try_decaps_vt(&ct_512)));
c.bench_function("ml_kem_768 Decaps", |b| b.iter(|| dk_768.try_decaps_vt(&ct_768)));
c.bench_function("ml_kem_1024 Decaps", |b| b.iter(|| dk_1024.try_decaps_vt(&ct_1024)));
c.bench_function("ml_kem_512 Decaps", |b| b.iter(|| dk_512.try_decaps(&ct_512)));
c.bench_function("ml_kem_768 Decaps", |b| b.iter(|| dk_768.try_decaps(&ct_768)));
c.bench_function("ml_kem_1024 Decaps", |b| b.iter(|| dk_1024.try_decaps(&ct_1024)));
}

criterion_group!(benches, criterion_benchmark);
Expand Down
2 changes: 1 addition & 1 deletion ct_cm4/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "fips203-ct_cm4"
version = "0.1.6"
version = "0.2.0"
license = "MIT OR Apache-2.0"
description = "Cortex-M4 testbench for FIPS 203 (draft) ML-KEM"
authors = ["Eric Schorn <eschorn@integritychain.com>"]
Expand Down
8 changes: 4 additions & 4 deletions ct_cm4/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ impl RngCore for TestRng {

fn next_u64(&mut self) -> u64 { unimplemented!() }

fn fill_bytes(&mut self, out: &mut [u8]) { unimplemented!() }
fn fill_bytes(&mut self, _out: &mut [u8]) { unimplemented!() }

fn try_fill_bytes(&mut self, out: &mut [u8]) -> Result<(), rand_core::Error> {
out.iter_mut().for_each(|b| *b = 0);
Expand Down Expand Up @@ -68,9 +68,9 @@ fn main() -> ! {
let start = DWT::cycle_count();
asm::isb();

let (ek, dk) = ml_kem_512::KG::try_keygen_with_rng_vt(&mut rng).unwrap();
let (ssk1, ct) = ek.try_encaps_with_rng_vt(&mut rng).unwrap();
let ssk2 = dk.try_decaps_vt(&ct).unwrap();
let (ek, dk) = ml_kem_512::KG::try_keygen_with_rng(&mut rng).unwrap();
let (ssk1, ct) = ek.try_encaps_with_rng(&mut rng).unwrap();
let ssk2 = dk.try_decaps(&ct).unwrap();
assert_eq!(ssk1.into_bytes(), ssk2.into_bytes());

asm::isb();
Expand Down
2 changes: 1 addition & 1 deletion dudect/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "fips203-dudect"
version = "0.1.6"
version = "0.2.0"
authors = ["Eric Schorn <eschorn@integritychain.com>"]
publish = false
edition = "2021"
Expand Down
2 changes: 1 addition & 1 deletion dudect/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ See <https://docs.rs/dudect-bencher/latest/dudect_bencher/>
~~~
April 24, 2024
Intel® Core™ i7-7700K CPU @ 4.20GHz × 8 Circa 2017
Intel® Core™ i7-7700K CPU @ 4.20GHz × 8 Circa 2017 Rust 1.70
$ cd dudect # this directory
$ RUSTFLAGS="-C target-cpu=native" cargo run --release -- --continuous full_flow
Expand Down
6 changes: 3 additions & 3 deletions dudect/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,9 +53,9 @@ fn full_flow(runner: &mut CtRunner, mut _rng: &mut BenchRng) {
let mut rng = rng_r.clone();
let mut spare_draw = [0u8; 32];
for _ in 0..ITERATIONS_INNER {
let (ek, dk) = ml_kem_512::KG::try_keygen_with_rng_vt(&mut rng).unwrap(); // uses 2 rng
let (ssk1, ct) = ek.try_encaps_with_rng_vt(&mut rng).unwrap(); // uses 1 rng
let ssk2 = dk.try_decaps_vt(&ct).unwrap();
let (ek, dk) = ml_kem_512::KG::try_keygen_with_rng(&mut rng).unwrap(); // uses 2 rng
let (ssk1, ct) = ek.try_encaps_with_rng(&mut rng).unwrap(); // uses 1 rng
let ssk2 = dk.try_decaps(&ct).unwrap();
assert_eq!(ssk1, ssk2);
let _ = rng.try_fill_bytes(&mut spare_draw).unwrap(); // ease our lives; multiple of 4
}
Expand Down
4 changes: 2 additions & 2 deletions ffi/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "fips203-ffi"
version = "0.1.6"
version = "0.2.0"
edition = "2021"
license = "MIT OR Apache-2.0"
description = "C shared library exposing FIPS 203 (draft): Module-Lattice-Based Key-Encapsulation Mechanism"
Expand All @@ -18,4 +18,4 @@ name = "fips203"

[dependencies.fips203]
path = ".."
version = "0.1.3"
version = "0.2.0"
16 changes: 16 additions & 0 deletions ffi/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,3 +33,19 @@ non-goals are:
# Paths considered but discarded

- Autogenerate stable C headers (e.g. with cbindgen); manually-crafted headers are probably fine, given the simplicity of the API/ABI


# Quick start

~~~
$ cd ffi # this directory
$ cargo build
$ (cd tests && make)
$ python3
>>> from fips203 import ML_KEM_512
>>>
>>> (encapsulation_key, decapsulation_key) = ML_KEM_512.keygen()
>>> (ciphertext, shared_secret_1) = encapsulation_key.encaps()
>>> shared_secret_2 = decapsulation_key.decaps(ciphertext)
>>> assert(shared_secret_1 == shared_secret_2)
~~~
7 changes: 4 additions & 3 deletions ffi/fips203.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,11 @@
produce identical 32-byte shared secrets:
```
from fips203 import ML_KEM_768
from fips203 import ML_KEM_512
(encapsulation_key, decapsulation_key) = ML_KEM_768.keygen()
(encapsulation_key, decapsulation_key) = ML_KEM_512.keygen()
(ciphertext, shared_secret_1) = encapsulation_key.encaps()
shared_secret_2 = decapsulation_key.decaps(ct)
shared_secret_2 = decapsulation_key.decaps(ciphertext)
assert(shared_secret_1 == shared_secret_2)
```
Expand Down Expand Up @@ -255,6 +255,7 @@ class _ML_KEM():
},
}
lib = ctypes.CDLL(ctypes.util.find_library('fips203'))
if not hasattr(lib, 'ml_kem_512_keygen'): lib = ctypes.CDLL("../target/debug/libfips203.so")

# use Any below because i don't know how to specify the type of the FuncPtr
ffi: Dict[int, Dict[str, Any]] = {}
Expand Down
18 changes: 9 additions & 9 deletions ffi/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ pub extern "C" fn ml_kem_512_keygen(
let (Some(encaps_out), Some(decaps_out)) = (encaps_out, decaps_out) else {
return ML_KEM_NULL_PTR_ERROR;
};
let Ok((ek, dk)) = fips203::ml_kem_512::KG::try_keygen_vt() else {
let Ok((ek, dk)) = fips203::ml_kem_512::KG::try_keygen() else {
return ML_KEM_KEYGEN_ERROR;
};

Expand All @@ -61,7 +61,7 @@ pub extern "C" fn ml_kem_512_encaps(
let Ok(ek) = fips203::ml_kem_512::EncapsKey::try_from_bytes(encaps.data) else {
return ML_KEM_DESERIALIZATION_ERROR;
};
let Ok((ssk, ct)) = ek.try_encaps_vt() else {
let Ok((ssk, ct)) = ek.try_encaps() else {
return ML_KEM_ENCAPSULATION_ERROR;
};

Expand All @@ -88,7 +88,7 @@ pub extern "C" fn ml_kem_512_decaps(
let Ok(ct) = fips203::ml_kem_512::CipherText::try_from_bytes(ciphertext.data) else {
return ML_KEM_DESERIALIZATION_ERROR;
};
let Ok(ssk) = dk.try_decaps_vt(&ct) else {
let Ok(ssk) = dk.try_decaps(&ct) else {
return ML_KEM_DECAPSULATION_ERROR;
};

Expand Down Expand Up @@ -120,7 +120,7 @@ pub extern "C" fn ml_kem_768_keygen(
let (Some(encaps_out), Some(decaps_out)) = (encaps_out, decaps_out) else {
return ML_KEM_NULL_PTR_ERROR;
};
let Ok((ek, dk)) = fips203::ml_kem_768::KG::try_keygen_vt() else {
let Ok((ek, dk)) = fips203::ml_kem_768::KG::try_keygen() else {
return ML_KEM_KEYGEN_ERROR;
};

Expand All @@ -144,7 +144,7 @@ pub extern "C" fn ml_kem_768_encaps(
let Ok(ek) = fips203::ml_kem_768::EncapsKey::try_from_bytes(encaps.data) else {
return ML_KEM_DESERIALIZATION_ERROR;
};
let Ok((ssk, ct)) = ek.try_encaps_vt() else {
let Ok((ssk, ct)) = ek.try_encaps() else {
return ML_KEM_ENCAPSULATION_ERROR;
};

Expand All @@ -171,7 +171,7 @@ pub extern "C" fn ml_kem_768_decaps(
let Ok(ct) = fips203::ml_kem_768::CipherText::try_from_bytes(ciphertext.data) else {
return ML_KEM_DESERIALIZATION_ERROR;
};
let Ok(ssk) = dk.try_decaps_vt(&ct) else {
let Ok(ssk) = dk.try_decaps(&ct) else {
return ML_KEM_DECAPSULATION_ERROR;
};

Expand Down Expand Up @@ -204,7 +204,7 @@ pub extern "C" fn ml_kem_1024_keygen(
let (Some(encaps_out), Some(decaps_out)) = (encaps_out, decaps_out) else {
return ML_KEM_NULL_PTR_ERROR;
};
let Ok((ek, dk)) = fips203::ml_kem_1024::KG::try_keygen_vt() else {
let Ok((ek, dk)) = fips203::ml_kem_1024::KG::try_keygen() else {
return ML_KEM_KEYGEN_ERROR;
};

Expand All @@ -228,7 +228,7 @@ pub extern "C" fn ml_kem_1024_encaps(
let Ok(ek) = fips203::ml_kem_1024::EncapsKey::try_from_bytes(encaps.data) else {
return ML_KEM_DESERIALIZATION_ERROR;
};
let Ok((ssk, ct)) = ek.try_encaps_vt() else {
let Ok((ssk, ct)) = ek.try_encaps() else {
return ML_KEM_ENCAPSULATION_ERROR;
};

Expand All @@ -255,7 +255,7 @@ pub extern "C" fn ml_kem_1024_decaps(
let Ok(ct) = fips203::ml_kem_1024::CipherText::try_from_bytes(ciphertext.data) else {
return ML_KEM_DESERIALIZATION_ERROR;
};
let Ok(ssk) = dk.try_decaps_vt(&ct) else {
let Ok(ssk) = dk.try_decaps(&ct) else {
return ML_KEM_DECAPSULATION_ERROR;
};

Expand Down
4 changes: 2 additions & 2 deletions ffi/tests/baseline.c
Original file line number Diff line number Diff line change
Expand Up @@ -105,8 +105,8 @@ int main(int argc, const char **argv) {
for (int i = 0; i < sizeof(decaps_weird.data); i++)
decaps_weird.data[i] = 0xff;
err = MLKEM_decaps (&decaps_weird, &ct, &ssk_a);
if (err != ML_KEM_DECAPSULATION_ERROR) {
fprintf (stderr, "decaps against a tampered decaps_key should have failed with decapsulation error, got %d\n", err);
if (err != ML_KEM_DESERIALIZATION_ERROR) {
fprintf (stderr, "decaps against a tampered decaps_key should have failed with deserialization error, got %d\n", err);
return 1;
}

Expand Down
2 changes: 1 addition & 1 deletion fuzz/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "fips203-fuzz"
version = "0.1.6"
version = "0.2.0"
publish = false
edition = "2021"
rust-version = "1.70"
Expand Down
Loading

0 comments on commit 3fed3a1

Please sign in to comment.