cryprot_ot/
lib.rs

1#![warn(clippy::unwrap_used)]
2//! CryProt-OT implements several [oblivious transfer](https://en.wikipedia.org/wiki/Oblivious_transfer) protocols.
3//!
4//! - base OT: "Simplest OT" [[CO15](https://eprint.iacr.org/2015/267)]
5//! - semi-honest OT extension: optimized [[IKNP03](https://www.iacr.org/archive/crypto2003/27290145/27290145.pdf)]
6//!   protocol
7//! - malicious OT extension: optimized [[KOS15](https://eprint.iacr.org/2015/546.pdf)]
8//!   protocol
9//! - silent OT extension: [[BCG+19](https://eprint.iacr.org/2019/1159)] silent OT
10//!   using [[RRT23](https://eprint.iacr.org/2023/882)] code (semi-honest and malicious
11//!   with [[YWL+20](https://dl.acm.org/doi/pdf/10.1145/3372297.3417276)]
12//!   consistency check)
13//!
14//! This library is heavily inspired by and in parts a port of the C++ [libOTe](https://github.com/osu-crypto/libOTe) library.
15//!
16//! ## Benchmarks
17//! We continously run the benchmark suite in CI witht the results publicly
18//! available on [bencher.dev](https://bencher.dev/perf/cryprot/plots). The raw criterion output, including throughput is
19//! available in the logs of the [bench workflow](https://github.com/robinhundt/CryProt/actions/workflows/bench.yml)
20//! (latest run > benchmarks job > Run Benchmarks step).
21//!
22//! ## OT Extension Benchmarks
23//! Following are benchmark numbers for several OT protocols on a 4-core VM
24//! running on an AMD EPYC 9454P. For up to date benchmarks view the links in
25//! the benchmarks section. Each OT sender/receiver uses one worker thread and
26//! number of cores many background threads for communication (which by default
27//! is also encrypted as part of QUIC).
28//!
29//! | Benchmark                                         | Mean Throughput (million OT/s) |
30//! |--------------------------------------------------|--------------------------|
31//! | Semi-honest R-OT ext. (2^24 R-OTs)       | 51.539                   |
32//! | Malicious R-OT ext. (2^24 R-OTs)         | 33.663                   |
33//! | Semi-Honest Silent C-OT ext. (2^21 C-OTs)          | 4.2306                   |
34//! | Semi-Honest Silent R-OT ext. (2^21 R-OTs)              | 9.5426                   |
35//! | Malicious Silent R-OT ext. (2^21 R-OTs)    | 7.4180                   |
36//!
37//! Silent OT will perform faster for smaller numbers of OTs at slightly
38//! increased communication.
39//!
40//! Our OT implementations should be on par or faster than those in libOTe. In
41//! the future we want to benchmark libOTe on the same hardware for a fair
42//! comparison.
43//!
44//! **Base OT Benchmark:**
45//!
46//! | Benchmark      | Mean Time (ms) |
47//! |---------------|---------------|
48//! | 128 base R-OTs   | 28.001        |
49
50use std::{fmt::Debug, future::Future};
51
52use cryprot_core::{Block, buf::Buf};
53use cryprot_net::Connection;
54use rand::{CryptoRng, Rng, SeedableRng, distr, prelude::Distribution, rngs::StdRng};
55use subtle::Choice;
56
57pub mod adapter;
58pub mod base;
59pub mod extension;
60pub mod noisy_vole;
61pub mod phase;
62pub mod silent_ot;
63
64/// Trait for OT receivers/senders which hold a [`Connection`].
65pub trait Connected {
66    fn connection(&mut self) -> &mut Connection;
67}
68
69impl<C: Connected> Connected for &mut C {
70    fn connection(&mut self) -> &mut Connection {
71        (*self).connection()
72    }
73}
74
75/// A random OT sender.
76pub trait RotSender: Connected + Send {
77    /// The error type returned by send operations.
78    type Error;
79
80    /// Send `count` many random OTs.
81    ///
82    /// For better performance, use [RotSender::send_into] with an existing
83    /// [`Buf`].
84    fn send(
85        &mut self,
86        count: usize,
87    ) -> impl Future<Output = Result<Vec<[Block; 2]>, Self::Error>> + Send {
88        async move {
89            let mut ots = Vec::zeroed(count);
90            self.send_into(&mut ots).await?;
91            Ok(ots)
92        }
93    }
94
95    /// Store OTs in the provided [`Buf`]fer.
96    ///
97    /// Note that implementations might temporarily take ownership of the
98    /// [`Buf`] pointed to by `ots`. If the future returned by this method is
99    /// dropped befire completion, `ots` might point at an empty `Buf`.
100    ///
101    /// For large number of OTs, using
102    /// [`HugePageMemory`](`cryprot_core::alloc::HugePageMemory`) can
103    /// significantly improve performance on Linux systems.
104    fn send_into(
105        &mut self,
106        ots: &mut impl Buf<[Block; 2]>,
107    ) -> impl Future<Output = Result<(), Self::Error>> + Send;
108}
109
110/// A random OT receiver.
111pub trait RotReceiver: Connected + Send {
112    /// The error type returned by receive operations.
113    type Error;
114
115    /// Receive `choices.len()` many random OTs.
116    ///
117    /// For better performance, use [RotReceiver::receive_into] with an existing
118    /// [`Buf`].
119    fn receive(
120        &mut self,
121        choices: &[Choice],
122    ) -> impl Future<Output = Result<Vec<Block>, Self::Error>> + Send {
123        async {
124            let mut ots = Vec::zeroed(choices.len());
125            self.receive_into(&mut ots, choices).await?;
126            Ok(ots)
127        }
128    }
129
130    /// Store OTs in the provided [`Buf`]fer.
131    ///
132    /// Note that implementations might temporarily take ownership of the
133    /// [`Buf`] pointed to by `ots`. If the future returned by this method is
134    /// dropped befire completion, `ots` might point at an empty `Buf`.
135    ///
136    /// For large number of OTs, using
137    /// [`HugePageMemory`](`cryprot_core::alloc::HugePageMemory`) can
138    /// significantly improve performance on Linux systems.
139    fn receive_into(
140        &mut self,
141        ots: &mut impl Buf<Block>,
142        choices: &[Choice],
143    ) -> impl Future<Output = Result<(), Self::Error>> + Send;
144}
145
146impl<S: RotSender> RotSender for &mut S {
147    type Error = S::Error;
148
149    fn send_into(
150        &mut self,
151        ots: &mut impl Buf<[Block; 2]>,
152    ) -> impl Future<Output = Result<(), Self::Error>> + Send {
153        (*self).send_into(ots)
154    }
155}
156
157impl<R: RotReceiver> RotReceiver for &mut R {
158    type Error = R::Error;
159
160    fn receive_into(
161        &mut self,
162        ots: &mut impl Buf<Block>,
163        choices: &[Choice],
164    ) -> impl Future<Output = Result<(), Self::Error>> + Send {
165        (*self).receive_into(ots, choices)
166    }
167}
168
169/// Marker trait for R-OT Senders that are paired with a random choice receiver.
170pub trait RandChoiceRotSender {}
171
172/// Returns a random choice vector alongside OTs.
173pub trait RandChoiceRotReceiver: Connected + Send {
174    type Error;
175
176    /// Receive `count` many random OTs alongside their respective choices.
177    fn rand_choice_receive(
178        &mut self,
179        count: usize,
180    ) -> impl Future<Output = Result<(Vec<Block>, Vec<Choice>), Self::Error>> + Send {
181        async move {
182            let mut ots = Vec::zeroed(count);
183            let choices = self.rand_choice_receive_into(&mut ots).await?;
184            Ok((ots, choices))
185        }
186    }
187
188    /// Receive `ots.len()` many random OTs, stored into the buffer pointed to
189    /// by `ots` and returns the corresponding choices.
190    fn rand_choice_receive_into(
191        &mut self,
192        ots: &mut impl Buf<Block>,
193    ) -> impl Future<Output = Result<Vec<Choice>, Self::Error>> + Send;
194}
195
196/// Adapt any [`RotReceiver`] into a [`RandChoiceRotReceiver`] by securely
197/// sampling the random choices using [`random_choices`].
198impl<R: RotReceiver> RandChoiceRotReceiver for R {
199    type Error = R::Error;
200
201    async fn rand_choice_receive_into(
202        &mut self,
203        ots: &mut impl Buf<Block>,
204    ) -> Result<Vec<Choice>, Self::Error> {
205        let choices = random_choices(ots.len(), &mut StdRng::from_os_rng());
206        self.receive_into(ots, &choices).await?;
207        Ok(choices)
208    }
209}
210
211/// Correlated OT sender (C-OT).
212pub trait CotSender: Connected + Send {
213    type Error;
214
215    /// Random OTs correlated by the `correlation`` function..
216    ///
217    /// The correlation function is passed the index of a C-OT and must output
218    /// the correlation for this C-OT.
219    fn correlated_send<F>(
220        &mut self,
221        count: usize,
222        correlation: F,
223    ) -> impl Future<Output = Result<Vec<Block>, Self::Error>> + Send
224    where
225        F: FnMut(usize) -> Block + Send,
226    {
227        async move {
228            let mut ots = Vec::zeroed(count);
229            self.correlated_send_into(&mut ots, correlation).await?;
230            Ok(ots)
231        }
232    }
233
234    fn correlated_send_into<B, F>(
235        &mut self,
236        ots: &mut B,
237        correlation: F,
238    ) -> impl Future<Output = Result<(), Self::Error>> + Send
239    where
240        B: Buf<Block>,
241        F: FnMut(usize) -> Block + Send;
242}
243
244pub trait CotReceiver: Connected + Send {
245    type Error;
246
247    fn correlated_receive(
248        &mut self,
249        choices: &[Choice],
250    ) -> impl Future<Output = Result<Vec<Block>, Self::Error>> + Send {
251        async {
252            let mut ots = Vec::zeroed(choices.len());
253            self.correlated_receive_into(&mut ots, choices).await?;
254            Ok(ots)
255        }
256    }
257
258    fn correlated_receive_into<B>(
259        &mut self,
260        ots: &mut B,
261        choices: &[Choice],
262    ) -> impl Future<Output = Result<(), Self::Error>> + Send
263    where
264        B: Buf<Block>;
265}
266
267/// Marker trait for OT implementations secure against semi-honest adversaries.
268pub trait SemiHonest {}
269
270/// Marker trait for OT implementations secure against malicious adversaries.
271pub trait Malicious: SemiHonest {}
272
273/// Used to abstract over [`SemiHonestMarker`] or [`MaliciousMarker`]
274pub trait Security: Send + Sync + Debug + Copy + Clone + private::Sealed {
275    const MALICIOUS_SECURITY: bool;
276}
277
278/// Used as a marker type for semi-honest security OT implementation.
279#[derive(Copy, Clone, Debug)]
280pub struct SemiHonestMarker;
281
282impl Security for SemiHonestMarker {
283    const MALICIOUS_SECURITY: bool = false;
284}
285
286/// Used as a marker type for malicious security OT implementation.
287#[derive(Copy, Clone, Debug)]
288pub struct MaliciousMarker;
289
290impl Security for MaliciousMarker {
291    const MALICIOUS_SECURITY: bool = true;
292}
293
294mod private {
295    pub trait Sealed {}
296
297    impl Sealed for super::SemiHonestMarker {}
298
299    impl Sealed for super::MaliciousMarker {}
300}
301
302/// Sample `count` many [`Choice`]es using the provided rng.
303pub fn random_choices<RNG: Rng + CryptoRng>(count: usize, rng: &mut RNG) -> Vec<Choice> {
304    let uniform = distr::Uniform::new(0, 2).expect("correct range");
305    uniform
306        .sample_iter(rng)
307        .take(count)
308        .map(Choice::from)
309        .collect()
310}