Skip to content

Commit f83fd49

Browse files
mlkem-rust-libcrux PQ code packages update (Tue Jul 9 10:38:18 CEST 2024) - libcrux revision 4f6d0e93f1a5929ebf118a39bf8bfa9a532f8377
Signed-off-by: Franziskus Kiefer <[email protected]>
1 parent f6bf5dd commit f83fd49

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

102 files changed

+34549
-1
lines changed

.gitignore

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,6 @@
22
# (TODO customize .gitignore for project)
33

44
.vscode
5-
.idea
5+
.idea
6+
/target
7+
Cargo.lock

Cargo.toml

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
[package]
2+
name = "libcrux-ml-kem"
3+
version = "0.0.2-alpha.1"
4+
authors = ["Cryspen"]
5+
license = "Apache-2.0"
6+
homepage = "https://github.com/cryspen/libcrux"
7+
edition = "2021"
8+
repository = "https://github.com/cryspen/libcrux"
9+
readme = "Readme.md"
10+
exclude = ["/tests"]
11+
12+
[workspace]
13+
member = ["."]
14+
15+
[dependencies]
16+
rand_core = { version = "0.6" }
17+
libcrux-platform = { version = "0.0.2-alpha.1" }
18+
libcrux-sha3 = { version = "0.0.2-alpha.1" }
19+
libcrux-intrinsics = { version = "0.0.2-alpha.1" }
20+
21+
# This is only required for verification.
22+
# The hax config is set by the hax toolchain.
23+
[target.'cfg(hax)'.dependencies]
24+
hax-lib = { git = "https://github.com/hacspec/hax/" }
25+
26+
[features]
27+
default = ["std", "mlkem512", "mlkem768", "mlkem1024"]
28+
simd128 = ["libcrux-sha3/simd128"]
29+
simd256 = ["libcrux-sha3/simd256"]
30+
mlkem512 = []
31+
mlkem768 = []
32+
mlkem1024 = []
33+
std = []
34+
kyber = []
35+
pre-verification = []
36+
37+
[dev-dependencies]
38+
rand = { version = "0.8" }
39+
serde_json = { version = "1.0" }
40+
serde = { version = "1.0", features = ["derive"] }
41+
hex = { version = "0.4.3", features = ["serde"] }
42+
criterion = "0.5"
43+
44+
[[bench]]
45+
name = "ml-kem"
46+
harness = false
47+
48+
[profile.release]
49+
lto = "fat"
50+
codegen-units = 1
51+
panic = "abort"

benches/ml-kem.rs

Lines changed: 165 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,165 @@
1+
use std::hint::black_box;
2+
use std::time::Duration;
3+
4+
use criterion::{criterion_group, criterion_main, BatchSize, Criterion};
5+
use rand_core::OsRng;
6+
use rand_core::RngCore;
7+
8+
use libcrux_ml_kem::mlkem768;
9+
10+
pub fn comparisons_key_generation(c: &mut Criterion) {
11+
let mut rng = OsRng;
12+
let mut group = c.benchmark_group("Kyber768 Key Generation");
13+
group.measurement_time(Duration::from_secs(10));
14+
15+
group.bench_function("libcrux portable (external random)", |b| {
16+
let mut seed = [0; 64];
17+
rng.fill_bytes(&mut seed);
18+
b.iter(|| {
19+
let _kp = mlkem768::generate_key_pair(seed);
20+
})
21+
});
22+
23+
// group.bench_function("libcrux portable (HACL-DRBG)", |b| {
24+
// b.iter(|| {
25+
// let (_secret_key, _public_key) =
26+
// libcrux::kem::key_gen(Algorithm::MlKem768, &mut drbg).unwrap();
27+
// })
28+
// });
29+
30+
// group.bench_function("libcrux portable (OsRng)", |b| {
31+
// b.iter(|| {
32+
// let (_secret_key, _public_key) =
33+
// libcrux::kem::key_gen(Algorithm::MlKem768, &mut rng).unwrap();
34+
// })
35+
// });
36+
37+
// group.bench_function("pqclean reference implementation", |b| {
38+
// b.iter(|| {
39+
// let (_public_key, _secret_key) = pqcrypto_kyber::kyber768::keypair();
40+
// })
41+
// });
42+
}
43+
44+
pub fn comparisons_pk_validation(c: &mut Criterion) {
45+
let mut rng = OsRng;
46+
let mut group = c.benchmark_group("Kyber768 PK Validation");
47+
group.measurement_time(Duration::from_secs(10));
48+
49+
group.bench_function("libcrux portable", |b| {
50+
let mut seed = [0; 64];
51+
rng.fill_bytes(&mut seed);
52+
b.iter_batched(
53+
|| {
54+
let keypair = mlkem768::generate_key_pair(seed);
55+
keypair.public_key().as_slice().into()
56+
},
57+
|public_key| {
58+
let _valid = black_box(mlkem768::validate_public_key(public_key));
59+
},
60+
BatchSize::SmallInput,
61+
)
62+
});
63+
}
64+
65+
pub fn comparisons_encapsulation(c: &mut Criterion) {
66+
let mut group = c.benchmark_group("Kyber768 Encapsulation");
67+
group.measurement_time(Duration::from_secs(10));
68+
69+
group.bench_function("libcrux portable (external random)", |b| {
70+
let mut seed1 = [0; 64];
71+
OsRng.fill_bytes(&mut seed1);
72+
let mut seed2 = [0; 32];
73+
OsRng.fill_bytes(&mut seed2);
74+
b.iter_batched(
75+
|| mlkem768::generate_key_pair(seed1),
76+
|keypair| {
77+
let (_shared_secret, _ciphertext) =
78+
mlkem768::encapsulate(keypair.public_key(), seed2);
79+
},
80+
BatchSize::SmallInput,
81+
)
82+
});
83+
84+
// group.bench_function("libcrux portable", |b| {
85+
// b.iter_batched(
86+
// || {
87+
// let mut drbg = Drbg::new(digest::Algorithm::Sha256).unwrap();
88+
// let (_secret_key, public_key) =
89+
// libcrux::kem::key_gen(Algorithm::MlKem768, &mut drbg).unwrap();
90+
91+
// (drbg, public_key)
92+
// },
93+
// |(mut rng, public_key)| {
94+
// let (_shared_secret, _ciphertext) = public_key.encapsulate(&mut rng).unwrap();
95+
// },
96+
// BatchSize::SmallInput,
97+
// )
98+
// });
99+
100+
// group.bench_function("pqclean reference implementation", |b| {
101+
// b.iter_batched(
102+
// || {
103+
// let (public_key, _secret_key) = pqcrypto_kyber::kyber768::keypair();
104+
105+
// public_key
106+
// },
107+
// |public_key| {
108+
// let (_shared_secret, _ciphertext) =
109+
// pqcrypto_kyber::kyber768::encapsulate(&public_key);
110+
// },
111+
// BatchSize::SmallInput,
112+
// )
113+
// });
114+
}
115+
116+
pub fn comparisons_decapsulation(c: &mut Criterion) {
117+
let mut group = c.benchmark_group("Kyber768 Decapsulation");
118+
group.measurement_time(Duration::from_secs(10));
119+
120+
group.bench_function("libcrux portable", |b| {
121+
let mut seed1 = [0; 64];
122+
OsRng.fill_bytes(&mut seed1);
123+
let mut seed2 = [0; 32];
124+
OsRng.fill_bytes(&mut seed2);
125+
b.iter_batched(
126+
|| {
127+
let keypair = mlkem768::generate_key_pair(seed1);
128+
let (ciphertext, _shared_secret) =
129+
mlkem768::encapsulate(keypair.public_key(), seed2);
130+
(keypair, ciphertext)
131+
},
132+
|(keypair, ciphertext)| {
133+
let _shared_secret = mlkem768::decapsulate(keypair.private_key(), &ciphertext);
134+
},
135+
BatchSize::SmallInput,
136+
)
137+
});
138+
139+
// group.bench_function("pqclean reference implementation", |b| {
140+
// b.iter_batched(
141+
// || {
142+
// let (public_key, secret_key) = pqcrypto_kyber::kyber768::keypair();
143+
// let (_shared_secret, ciphertext) =
144+
// pqcrypto_kyber::kyber768::encapsulate(&public_key);
145+
146+
// (ciphertext, secret_key)
147+
// },
148+
// |(ciphertext, secret_key)| {
149+
// let _shared_secret =
150+
// pqcrypto_kyber::kyber768::decapsulate(&ciphertext, &secret_key);
151+
// },
152+
// BatchSize::SmallInput,
153+
// )
154+
// });
155+
}
156+
157+
pub fn comparisons(c: &mut Criterion) {
158+
comparisons_pk_validation(c);
159+
comparisons_key_generation(c);
160+
comparisons_encapsulation(c);
161+
comparisons_decapsulation(c);
162+
}
163+
164+
criterion_group!(benches, comparisons);
165+
criterion_main!(benches);

build.rs

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
use std::env;
2+
3+
fn main() {
4+
let target_arch = env::var("CARGO_CFG_TARGET_ARCH").unwrap();
5+
let disable_simd128 = read_env("LIBCRUX_DISABLE_SIMD128");
6+
let disable_simd256 = read_env("LIBCRUX_DISABLE_SIMD256");
7+
8+
// Force a simd build. Make sure you know what you're doing.
9+
let enable_simd128 = read_env("LIBCRUX_ENABLE_SIMD128");
10+
let enable_simd256 = read_env("LIBCRUX_ENABLE_SIMD256");
11+
12+
let simd128_possible = target_arch == "aarch64";
13+
if (simd128_possible || enable_simd128) && !disable_simd128 {
14+
// We enable simd128 on all aarch64 builds.
15+
println!("cargo:rustc-cfg=feature=\"simd128\"");
16+
}
17+
let simd126_possible = target_arch == "x86_64";
18+
if (simd126_possible || enable_simd256) && !disable_simd256 {
19+
// We enable simd256 on all x86_64 builds.
20+
// Note that this doesn't mean the required CPU features are available.
21+
// But the compiler will support them and the runtime checks ensure that
22+
// it's only used when available.
23+
//
24+
// We don't enable this on x86 because it seems to generate invalid code.
25+
println!("cargo:rustc-cfg=feature=\"simd256\"");
26+
}
27+
}
28+
29+
fn read_env(key: &str) -> bool {
30+
match env::var(key) {
31+
Ok(s) => s == "1" || s == "y" || s == "Y",
32+
Err(_) => false,
33+
}
34+
}

examples/decapsulate.rs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
use libcrux_ml_kem::{mlkem768, ENCAPS_SEED_SIZE, KEY_GENERATION_SEED_SIZE};
2+
use rand::{rngs::OsRng, RngCore};
3+
4+
fn main() {
5+
let mut randomness = [0u8; KEY_GENERATION_SEED_SIZE];
6+
OsRng.fill_bytes(&mut randomness);
7+
8+
let key_pair = mlkem768::generate_key_pair(randomness);
9+
let mut randomness = [0u8; ENCAPS_SEED_SIZE];
10+
OsRng.fill_bytes(&mut randomness);
11+
let (ct, _ss) = mlkem768::encapsulate(key_pair.public_key(), randomness);
12+
13+
for _ in 0..100_000 {
14+
let _ = mlkem768::decapsulate(key_pair.private_key(), &ct);
15+
}
16+
}

examples/encapsulate.rs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
use libcrux_ml_kem::{mlkem768, ENCAPS_SEED_SIZE, KEY_GENERATION_SEED_SIZE};
2+
use rand::{rngs::OsRng, RngCore};
3+
4+
fn main() {
5+
let mut randomness = [0u8; KEY_GENERATION_SEED_SIZE];
6+
OsRng.fill_bytes(&mut randomness);
7+
8+
let key_pair = mlkem768::generate_key_pair(randomness);
9+
10+
let mut randomness = [0u8; ENCAPS_SEED_SIZE];
11+
for _ in 0..100_000 {
12+
OsRng.fill_bytes(&mut randomness);
13+
let _ = mlkem768::encapsulate(key_pair.public_key(), randomness);
14+
}
15+
}

examples/keygen.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
use libcrux_ml_kem::{mlkem768, KEY_GENERATION_SEED_SIZE};
2+
use rand::{rngs::OsRng, RngCore};
3+
4+
fn main() {
5+
let mut randomness = [0u8; KEY_GENERATION_SEED_SIZE];
6+
for _ in 0..100_000 {
7+
OsRng.fill_bytes(&mut randomness);
8+
let _ = mlkem768::generate_key_pair(randomness);
9+
}
10+
}

src/PERFORMANCE.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
N.B.: All measurements were taken on an M1 MacBook Air with 16 GB of memory.
2+
3+
| | Key Generation (µs) | Encapsulation (µs) | Decapsulation (µs) |
4+
|:----------|----------------------:|---------------------:|---------------------:|
5+
| libcrux | 30.671 | 36.31 | 36.3 |
6+
| BoringSSL | 33.8152 | 28.7323 | 35.2664 |
7+
| CIRCL | 39.785 | 44.517 | 49.626 |
8+
| PQClean | 30.671 | 38.511 | 43.458 |

src/cfg.rs

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
/// Macro to simplify feature gating of verified code that should only be enabled
2+
/// when unverified code is disabled.
3+
macro_rules! cfg_verified {
4+
($($item:item)*) => {
5+
$(
6+
#[cfg(not(feature = "pre-verification"))]
7+
#[allow(missing_docs)]
8+
$item
9+
)*
10+
}
11+
}
12+
13+
/// Macro to simplify `pre-verification` feature gating
14+
macro_rules! cfg_pre_verification {
15+
($($item:item)*) => {
16+
$(
17+
#[cfg(feature = "pre-verification")]
18+
$item
19+
)*
20+
}
21+
}
22+
23+
/// Macro to simplify `kyber` feature gating
24+
#[cfg(feature = "pre-verification")]
25+
macro_rules! cfg_kyber {
26+
($($item:item)*) => {
27+
$(
28+
#[cfg(feature = "kyber")]
29+
$item
30+
)*
31+
}
32+
}

0 commit comments

Comments
 (0)