Skip to content

Commit 3cc72cf

Browse files
committed
add ML-KEM as an option for base OT
This makes the base OT post-quantum secure by utilizing ML-KEM key encapsulation via https://crates.io/crates/ml-kem. We keep the Simplest OT as default base OT and make ML-KEM optional by adding a compile-time feature, namely `ml-kem-base-ot`. Note that `MlKemOt` is not `trait Malicious` secure (it is only `trait SemiHonest` secure) as the receiver can generate two real decapsulation keys, allowing it to decapsulate both ciphertexts and learn both OT messages. When used in an OT extension protocol, semi-honest base OT is sufficient for the whole protocol to have malicious security.
1 parent bee0b02 commit 3cc72cf

File tree

11 files changed

+470
-19
lines changed

11 files changed

+470
-19
lines changed

.devcontainer/devcontainer.json

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
{
2+
"image": "mcr.microsoft.com/devcontainers/base:ubuntu-24.04",
3+
"features": {
4+
"ghcr.io/devcontainers/features/rust:1": {},
5+
"ghcr.io/devcontainers/features/common-utils:2": {}
6+
},
7+
"customizations": {
8+
"vscode": {
9+
"extensions": [
10+
"rust-lang.rust-analyzer",
11+
"vadimcn.vscode-lldb"
12+
],
13+
"settings": {
14+
"git.allowForcePush": true,
15+
"diffEditor.ignoreTrimWhitespace": false,
16+
"editor.formatOnSave": true
17+
}
18+
}
19+
}
20+
}

Cargo.lock

Lines changed: 67 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ fastdivide = "0.4.2"
3131
futures = "0.3.30"
3232
hybrid-array = { version = "0.4.1", features = ["bytemuck"] }
3333
libc = "0.2.169"
34+
ml-kem = "0.2.2"
3435
ndarray = "0.17.2"
3536
num-traits = "0.2.19"
3637
rand = "0.9.0"
@@ -40,7 +41,8 @@ rayon = "1.10.0"
4041
s2n-quic = "1.37.0"
4142
seq-macro = "=0.3.6"
4243
serde = "1.0.203"
43-
subtle = "2.6.1"
44+
serde_bytes = "0.11.19"
45+
subtle = { version = "2.6.1", features = ["const-generics"] }
4446
thiserror = "2.0.18"
4547
tokio = "1.37.0"
4648
tokio-serde = "0.9.0"

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ The `cryprot` crates implement several **cryp**tographic **prot**ocols and utili
1111
| [`cryprot-net`] | Networking abstractions built atop [s2n-quic](https://docs.rs/s2n-quic/latest/s2n_quic/). | [![crates.io](https://img.shields.io/crates/v/cryprot-net)](https://crates.io/crates/cryprot-net) | [![docs.rs](https://img.shields.io/docsrs/cryprot-net)](https://docs.rs/cryprot-net) |
1212
| [`cryprot-pprf`] | Distributed PPRF implementation used in Silent OT [[BCG+19]](https://eprint.iacr.org/2019/1159), based on [libOTe](https://github.com/osu-crypto/libOTe). | [![crates.io](https://img.shields.io/crates/v/cryprot-pprf)](https://crates.io/crates/cryprot-pprf) | [![docs.rs](https://img.shields.io/docsrs/cryprot-pprf)](https://docs.rs/cryprot-pprf) |
1313
| [`cryprot-codes`] | Expand-convolute linear code [[RRT23]](https://eprint.iacr.org/2023/882), based on [libOTe](https://github.com/osu-crypto/libOTe), used in Silent OT. | [![crates.io](https://img.shields.io/crates/v/cryprot-codes)](https://crates.io/crates/cryprot-codes) | [![docs.rs](https://img.shields.io/docsrs/cryprot-codes)](https://docs.rs/cryprot-codes) |
14-
| [`cryprot-ot`] | Oblivious transfer implementations:<br>• Base OT: "Simplest OT" [[CO15]](https://eprint.iacr.org/2015/267)<br>• OT extensions: [[IKNP03]](https://www.iacr.org/archive/crypto2003/27290145/27290145.pdf)<br>• Malicious OT extension: [[KOS15]](https://eprint.iacr.org/2015/546.pdf)<br>• Silent OT extension: [[BCG+19]](https://eprint.iacr.org/2019/1159) Silent OT using [[RRT23]](https://eprint.iacr.org/2023/882) code and optional [[YWL+20]](https://dl.acm.org/doi/pdf/10.1145/3372297.3417276) consistency check for malicious security. | [![crates.io](https://img.shields.io/crates/v/cryprot-ot)](https://crates.io/crates/cryprot-ot) | [![docs.rs](https://img.shields.io/docsrs/cryprot-ot)](https://docs.rs/cryprot-ot) |
14+
| [`cryprot-ot`] | Oblivious transfer implementations:<br>• Base OT: "Simplest OT" [[CO15]](https://eprint.iacr.org/2015/267)<br>• Base OT (post-quantum, optional): [ML-KEM-768](https://crates.io/crates/ml-kem) based OT [[FIPS 203]](https://csrc.nist.gov/pubs/fips/203/final)<br>• OT extensions: [[IKNP03]](https://www.iacr.org/archive/crypto2003/27290145/27290145.pdf)<br>• Malicious OT extension: [[KOS15]](https://eprint.iacr.org/2015/546.pdf)<br>• Silent OT extension: [[BCG+19]](https://eprint.iacr.org/2019/1159) Silent OT using [[RRT23]](https://eprint.iacr.org/2023/882) code and optional [[YWL+20]](https://dl.acm.org/doi/pdf/10.1145/3372297.3417276) consistency check for malicious security. | [![crates.io](https://img.shields.io/crates/v/cryprot-ot)](https://crates.io/crates/cryprot-ot) | [![docs.rs](https://img.shields.io/docsrs/cryprot-ot)](https://docs.rs/cryprot-ot) |
1515

1616
Documentation for the latest main branch state is available [here](https://robinhundt.github.io/CryProt/cryprot_ot/).
1717
## Platform Support

cryprot-ot/Cargo.toml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,10 @@ version = "0.2.1"
99
authors.workspace = true
1010
repository.workspace = true
1111

12+
[features]
13+
# Use ML-KEM-based OT for base OT.
14+
ml-kem-base-ot = []
15+
1216
[lints]
1317
workspace = true
1418

@@ -25,7 +29,10 @@ cryprot-net.workspace = true
2529
cryprot-pprf.workspace = true
2630
curve25519-dalek = { workspace = true, features = ["rand_core", "serde"] }
2731
futures.workspace = true
32+
ml-kem.workspace = true
2833
rand.workspace = true
34+
serde_bytes.workspace = true
35+
serde = { workspace = true, features = ["derive"] }
2936
subtle.workspace = true
3037
thiserror.workspace = true
3138
tokio = { workspace = true, features = ["io-util"] }

cryprot-ot/README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
Oblivious transfer implementations. Currently implemented are the following:
77

88
- base OT: "Simplest OT" [[CO15](https://eprint.iacr.org/2015/267)]
9+
- base OT (post-quantum, optional): [ML-KEM-768](https://crates.io/crates/ml-kem) based OT [[FIPS 203](https://csrc.nist.gov/pubs/fips/203/final)]
910
- semi-honest OT extension: optimized [[IKNP03](https://www.iacr.org/archive/crypto2003/27290145/27290145.pdf)] protocol
1011
- malicious OT extension: optimized [[KOS15]](https://eprint.iacr.org/2015/546.pdf) protocol
1112
- silent OT extension: [[BCG+19](https://eprint.iacr.org/2019/1159)] silent OT using [[RRT23](https://eprint.iacr.org/2023/882)] code (semi-honest and malicious with [[YWL+20](https://dl.acm.org/doi/pdf/10.1145/3372297.3417276)] consistency check)
@@ -27,7 +28,7 @@ Silent OT will perform faster for smaller numbers of OTs at slightly increased c
2728

2829
Our OT implementations should be on par or faster than those in libOTe. In the future we want to benchmark libOTe on the same hardware for a fair comparison.
2930

30-
**Base OT Benchmark:**
31+
**Base OT Benchmark (Simplest OT):**
3132

3233
| Benchmark | Mean Time (ms) |
3334
|---------------|---------------|

cryprot-ot/benches/bench.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ use cryprot_core::{Block, alloc::HugePageMemory};
88
use cryprot_net::testing::{init_bench_tracing, local_conn};
99
use cryprot_ot::{
1010
CotReceiver, CotSender, RotReceiver, RotSender,
11-
base::SimplestOt,
1211
extension::{
1312
MaliciousOtExtensionReceiver, MaliciousOtExtensionSender, SemiHonestOtExtensionReceiver,
1413
SemiHonestOtExtensionSender,
@@ -18,6 +17,7 @@ use cryprot_ot::{
1817
MaliciousSilentOtReceiver, MaliciousSilentOtSender, SemiHonestSilentOtReceiver,
1918
SemiHonestSilentOtSender,
2019
},
20+
simplest_ot::SimplestOt,
2121
};
2222
use rand::{SeedableRng, rngs::StdRng};
2323
use tokio::runtime::{self, Runtime};

cryprot-ot/src/extension.rs

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -35,10 +35,8 @@ use tokio::{
3535
use tracing::Level;
3636

3737
use crate::{
38-
Connected, CotReceiver, CotSender, Malicious, MaliciousMarker, RotReceiver, RotSender,
39-
Security, SemiHonest, SemiHonestMarker,
40-
adapter::CorrelatedFromRandom,
41-
base::{self, SimplestOt},
38+
BaseOt, BaseOtError, Connected, CotReceiver, CotSender, Malicious, MaliciousMarker,
39+
RotReceiver, RotSender, Security, SemiHonest, SemiHonestMarker, adapter::CorrelatedFromRandom,
4240
phase, random_choices,
4341
};
4442

@@ -49,7 +47,7 @@ pub const DEFAULT_OT_BATCH_SIZE: usize = 2_usize.pow(16);
4947
/// OT extension sender generic over its [`Security`] level.
5048
pub struct OtExtensionSender<S> {
5149
rng: StdRng,
52-
base_ot: SimplestOt,
50+
base_ot: BaseOt,
5351
conn: Connection,
5452
base_rngs: Vec<AesRng>,
5553
base_choices: Vec<Choice>,
@@ -60,7 +58,7 @@ pub struct OtExtensionSender<S> {
6058

6159
/// OT extension receiver generic over its [`Security`] level.
6260
pub struct OtExtensionReceiver<S> {
63-
base_ot: SimplestOt,
61+
base_ot: BaseOt,
6462
conn: Connection,
6563
base_rngs: Vec<[AesRng; 2]>,
6664
batch_size: usize,
@@ -83,7 +81,7 @@ pub type MaliciousOtExtensionReceiver = OtExtensionReceiver<MaliciousMarker>;
8381
#[non_exhaustive]
8482
pub enum Error {
8583
#[error("unable to compute base OTs")]
86-
BaseOT(#[from] base::Error),
84+
BaseOT(#[from] BaseOtError),
8785
#[error("connection error to peer")]
8886
Connection(#[from] ConnectionError),
8987
#[error("error in sending/receiving data")]
@@ -114,7 +112,7 @@ impl<S: Security> OtExtensionSender<S> {
114112
///
115113
/// For an rng seeded with a fixed seed, the output is deterministic.
116114
pub fn new_with_rng(mut conn: Connection, mut rng: StdRng) -> Self {
117-
let base_ot = SimplestOt::new_with_rng(conn.sub_connection(), StdRng::from_rng(&mut rng));
115+
let base_ot = BaseOt::new_with_rng(conn.sub_connection(), StdRng::from_rng(&mut rng));
118116
Self {
119117
rng,
120118
base_ot,
@@ -435,7 +433,7 @@ impl<S: Security> OtExtensionReceiver<S> {
435433
///
436434
/// For an rng seeded with a fixed seed, the output is deterministic.
437435
pub fn new_with_rng(mut conn: Connection, mut rng: StdRng) -> Self {
438-
let base_ot = SimplestOt::new_with_rng(conn.sub_connection(), StdRng::from_rng(&mut rng));
436+
let base_ot = BaseOt::new_with_rng(conn.sub_connection(), StdRng::from_rng(&mut rng));
439437
Self {
440438
rng,
441439
base_ot,

cryprot-ot/src/lib.rs

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
#![warn(clippy::unwrap_used)]
22
//! CryProt-OT implements several [oblivious transfer](https://en.wikipedia.org/wiki/Oblivious_transfer) protocols.
33
//!
4-
//! - base OT: "Simplest OT" [[CO15](https://eprint.iacr.org/2015/267)]
4+
//! - base OT: "Simplest OT" [[CO15](https://eprint.iacr.org/2015/267)] (classical security)
5+
//! - post-quantum base OT: ML-KEM-768 based OT [[MR19](https://eprint.iacr.org/2019/706)] (post-quantum security)
56
//! - semi-honest OT extension: optimized [[IKNP03](https://www.iacr.org/archive/crypto2003/27290145/27290145.pdf)]
67
//! protocol
78
//! - malicious OT extension: optimized [[KOS15](https://eprint.iacr.org/2015/546.pdf)]
@@ -13,6 +14,15 @@
1314
//!
1415
//! This library is heavily inspired by and in parts a port of the C++ [libOTe](https://github.com/osu-crypto/libOTe) library.
1516
//!
17+
//! ## ML-KEM Base OT
18+
//!
19+
//! Enable the `ml-kem-base-ot` feature to use ML-KEM-based OT for the base OT
20+
//! protocol, providing post-quantum security:
21+
//!
22+
//! This replaces the classical "Simplest OT" with an ML-KEM-based construction following
23+
//! FIPS 203 at https://csrc.nist.gov/pubs/fips/203/final, similar to libOTe's `ENABLE_MR_KYBER` option.
24+
//! We use the ML-KEN crate https://crates.io/crates/ml-kem.
25+
//!
1626
//! ## Benchmarks
1727
//! We continously run the benchmark suite in CI witht the results publicly
1828
//! available on [bencher.dev](https://bencher.dev/perf/cryprot/plots). The raw criterion output, including throughput is
@@ -55,11 +65,32 @@ use rand::{CryptoRng, Rng, SeedableRng, distr, prelude::Distribution, rngs::StdR
5565
use subtle::Choice;
5666

5767
pub mod adapter;
58-
pub mod base;
5968
pub mod extension;
69+
pub mod mlkem_ot;
6070
pub mod noisy_vole;
6171
pub mod phase;
6272
pub mod silent_ot;
73+
pub mod simplest_ot;
74+
75+
/// Base OT implementation used by extension protocols.
76+
///
77+
/// When the `ml-kem-base-ot` feature is enabled, use [`mlkem_ot::MlKemOt`]
78+
#[cfg(feature = "ml-kem-base-ot")]
79+
pub type BaseOt = mlkem_ot::MlKemOt;
80+
81+
/// Base OT implementation used by extension protocols.
82+
///
83+
/// When the `ml-kem-base-ot` feature is not enabled, use [`simplest_ot::SimplestOt`].
84+
#[cfg(not(feature = "ml-kem-base-ot"))]
85+
pub type BaseOt = simplest_ot::SimplestOt;
86+
87+
/// Error type for base OT operations.
88+
#[cfg(feature = "ml-kem-base-ot")]
89+
pub type BaseOtError = mlkem_ot::Error;
90+
91+
/// Error type for base OT operations.
92+
#[cfg(not(feature = "ml-kem-base-ot"))]
93+
pub type BaseOtError = simplest_ot::Error;
6394

6495
/// Trait for OT receivers/senders which hold a [`Connection`].
6596
pub trait Connected {

0 commit comments

Comments
 (0)