From cfa42a519ddd936249976ef0d83c7cdc5b8e5d1e Mon Sep 17 00:00:00 2001 From: "sinu.eth" <65924192+sinui0@users.noreply.github.com> Date: Thu, 2 May 2024 19:34:15 -0800 Subject: [PATCH 01/39] feat: PRG stream id (#121) * add stream_id to PRG and update benches * persist counter state --- mpz-core/benches/prg.rs | 22 ++++++--- mpz-core/src/prg.rs | 106 ++++++++++++++++++++++++++++++++++------ 2 files changed, 105 insertions(+), 23 deletions(-) diff --git a/mpz-core/benches/prg.rs b/mpz-core/benches/prg.rs index 76bdaee4..7efd904c 100644 --- a/mpz-core/benches/prg.rs +++ b/mpz-core/benches/prg.rs @@ -1,10 +1,13 @@ -use criterion::{black_box, criterion_group, criterion_main, Criterion}; +use criterion::{black_box, criterion_group, criterion_main, Criterion, Throughput}; use mpz_core::{block::Block, prg::Prg}; use rand_core::RngCore; fn criterion_benchmark(c: &mut Criterion) { - c.bench_function("Prg::byte", move |bench| { + let mut group = c.benchmark_group("prg"); + + group.throughput(Throughput::Bytes(1)); + group.bench_function("byte", move |bench| { let mut prg = Prg::new(); let mut x = 0u8; bench.iter(|| { @@ -13,9 +16,11 @@ fn criterion_benchmark(c: &mut Criterion) { }); }); - c.bench_function("Prg::bytes", move |bench| { + const BYTES_PER: u64 = 16 * 1024; + group.throughput(Throughput::Bytes(BYTES_PER)); + group.bench_function("bytes", move |bench| { let mut prg = Prg::new(); - let mut x = (0..16 * 1024) + let mut x = (0..BYTES_PER) .map(|_| rand::random::()) .collect::>(); bench.iter(|| { @@ -23,7 +28,8 @@ fn criterion_benchmark(c: &mut Criterion) { }); }); - c.bench_function("Prg::block", move |bench| { + group.throughput(Throughput::Elements(1)); + group.bench_function("block", move |bench| { let mut prg = Prg::new(); let mut x = Block::ZERO; bench.iter(|| { @@ -32,9 +38,11 @@ fn criterion_benchmark(c: &mut Criterion) { }); }); - c.bench_function("Prg::blocks", move |bench| { + const BLOCKS_PER: u64 = 16 * 1024; + group.throughput(Throughput::Elements(BLOCKS_PER)); + group.bench_function("blocks", move |bench| { let mut prg = Prg::new(); - let mut x = (0..16 * 1024) + let mut x = (0..BLOCKS_PER) .map(|_| rand::random::()) .collect::>(); bench.iter(|| { diff --git a/mpz-core/src/prg.rs b/mpz-core/src/prg.rs index 0d909f45..9d62587b 100644 --- a/mpz-core/src/prg.rs +++ b/mpz-core/src/prg.rs @@ -1,32 +1,42 @@ //! Implement AES-based PRG. +use std::collections::HashMap; + use crate::{aes::AesEncryptor, Block}; use rand::Rng; use rand_core::{ block::{BlockRng, BlockRngCore}, CryptoRng, RngCore, SeedableRng, }; + /// Struct of PRG Core #[derive(Clone)] struct PrgCore { aes: AesEncryptor, - state: u64, + // Stores the counter for each stream id. + state: HashMap, + stream_id: u64, + counter: u64, } -// This implementation is somehow standard, and is adapted from Swanky. impl BlockRngCore for PrgCore { type Item = u32; type Results = [u32; 4 * AesEncryptor::AES_BLOCK_COUNT]; - // Compute [AES(state)..AES(state+8)] + // Compute 8 encrypted counter blocks at a time. #[inline(always)] fn generate(&mut self, results: &mut Self::Results) { let mut states = [0; AesEncryptor::AES_BLOCK_COUNT].map( #[inline(always)] |_| { - let x = self.state; - self.state += 1; - Block::from(bytemuck::cast::<_, [u8; 16]>([x, 0u64])) + let mut block = [0u8; 16]; + let counter = self.counter; + self.counter += 1; + + block[..8].copy_from_slice(&counter.to_le_bytes()); + block[8..].copy_from_slice(&self.stream_id.to_le_bytes()); + + Block::from(block) }, ); self.aes.encrypt_many_blocks(&mut states); @@ -40,13 +50,24 @@ impl SeedableRng for PrgCore { #[inline(always)] fn from_seed(seed: Self::Seed) -> Self { let aes = AesEncryptor::new(seed); - Self { aes, state: 0u64 } + Self { + aes, + state: Default::default(), + stream_id: 0u64, + counter: 0u64, + } } } impl CryptoRng for PrgCore {} -/// Struct of PRG +/// AES-based PRG. +/// +/// This PRG is based on AES128 used in counter-mode to generate pseudo-random data streams. +/// +/// # Stream ID +/// +/// The PRG is configurable with a stream ID, which can be used to generate distinct streams using the same seed. See [`Prg::set_stream_id`]. #[derive(Clone)] pub struct Prg(BlockRng); @@ -92,8 +113,28 @@ impl Prg { /// New Prg with random seed. #[inline(always)] pub fn new() -> Self { - let seed = rand::random::(); - Prg::from_seed(seed) + Prg::from_seed(rand::random::()) + } + + /// Returns the current counter. + pub fn counter(&self) -> u64 { + self.0.core.counter + } + + /// Returns the stream id. + pub fn stream_id(&self) -> u64 { + self.0.core.stream_id + } + + /// Sets the stream id. + pub fn set_stream_id(&mut self, stream_id: u64) { + let state = &mut self.0.core.state; + state.insert(self.0.core.stream_id, self.0.core.counter); + + let counter = state.get(&stream_id).copied().unwrap_or(0); + + self.0.core.stream_id = stream_id; + self.0.core.counter = counter; } /// Generate a random bool value. @@ -141,10 +182,43 @@ impl Default for Prg { } } -#[test] -fn prg_test() { - let mut prg = Prg::new(); - let mut x = vec![Block::ZERO; 2]; - prg.random_blocks(&mut x); - assert_ne!(x[0], x[1]); +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_prg_ne() { + let mut prg = Prg::new(); + let mut x = vec![Block::ZERO; 2]; + prg.random_blocks(&mut x); + assert_ne!(x[0], x[1]); + } + + #[test] + fn test_prg_streams_are_distinct() { + let mut prg = Prg::from_seed(Block::ZERO); + let mut x = vec![Block::ZERO; 2]; + prg.random_blocks(&mut x); + + let mut y = vec![Block::ZERO; 2]; + prg.set_stream_id(1); + prg.random_blocks(&mut y); + + assert_ne!(x[0], y[0]); + } + + #[test] + fn test_prg_state_persisted() { + let mut prg = Prg::from_seed(Block::ZERO); + let mut x = vec![Block::ZERO; 2]; + prg.random_blocks(&mut x); + + let counter = prg.counter(); + assert_ne!(counter, 0); + + prg.set_stream_id(1); + prg.set_stream_id(0); + + assert_eq!(prg.counter(), counter); + } } From 0e3cd1a08b78e06f1a67f45bd9ed39eb3e90cd05 Mon Sep 17 00:00:00 2001 From: dan Date: Mon, 13 May 2024 09:51:37 +0000 Subject: [PATCH 02/39] test: use deterministic PRG (#127) --- ot/mpz-ot-core/src/ferret/mod.rs | 3 ++- ot/mpz-ot-core/src/ferret/mpcot/mod.rs | 5 +++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/ot/mpz-ot-core/src/ferret/mod.rs b/ot/mpz-ot-core/src/ferret/mod.rs index 9b52fded..4ea60c3f 100644 --- a/ot/mpz-ot-core/src/ferret/mod.rs +++ b/ot/mpz-ot-core/src/ferret/mod.rs @@ -54,6 +54,7 @@ mod tests { ideal_mpcot::{IdealMpcot, MpcotMsgForReceiver, MpcotMsgForSender}, }; use mpz_core::{lpn::LpnParameters, prg::Prg}; + use rand::SeedableRng; const LPN_PARAMETERS_TEST: LpnParameters = LpnParameters { n: 9600, @@ -63,7 +64,7 @@ mod tests { #[test] fn ferret_test() { - let mut prg = Prg::new(); + let mut prg = Prg::from_seed([1u8; 16].into()); let delta = prg.random_block(); let mut ideal_cot = IdealCOT::new_with_delta(delta); let mut ideal_mpcot = IdealMpcot::init_with_delta(delta); diff --git a/ot/mpz-ot-core/src/ferret/mpcot/mod.rs b/ot/mpz-ot-core/src/ferret/mpcot/mod.rs index 565a9ad9..e8c3043c 100644 --- a/ot/mpz-ot-core/src/ferret/mpcot/mod.rs +++ b/ot/mpz-ot-core/src/ferret/mpcot/mod.rs @@ -15,10 +15,11 @@ mod tests { }; use crate::ideal::ideal_spcot::{IdealSpcot, SpcotMsgForReceiver, SpcotMsgForSender}; use mpz_core::prg::Prg; + use rand::SeedableRng; #[test] fn mpcot_general_test() { - let mut prg = Prg::new(); + let mut prg = Prg::from_seed([1u8; 16].into()); let delta = prg.random_block(); let mut ideal_spcot = IdealSpcot::new_with_delta(delta); @@ -94,7 +95,7 @@ mod tests { #[test] fn mpcot_regular_test() { - let mut prg = Prg::new(); + let mut prg = Prg::from_seed([2u8; 16].into()); let delta = prg.random_block(); let mut ideal_spcot = IdealSpcot::new_with_delta(delta); From da429ceb0578e4c802df214d8be9b8a8faf4ae79 Mon Sep 17 00:00:00 2001 From: dan Date: Mon, 13 May 2024 09:52:06 +0000 Subject: [PATCH 03/39] fix: init rng outside of the loop (#128) --- mpz-core/src/lpn.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/mpz-core/src/lpn.rs b/mpz-core/src/lpn.rs index cd99ca3d..2543fdb2 100644 --- a/mpz-core/src/lpn.rs +++ b/mpz-core/src/lpn.rs @@ -145,9 +145,10 @@ impl LpnParameters { assert_eq!(self.n % self.t, 0); let one: Block = bytemuck::cast(1_u128); let mut res = vec![Block::ZERO; self.n]; + let mut rng = thread_rng(); + res.chunks_exact_mut(self.n / self.t).for_each(|x| { x[0] = one; - let mut rng = thread_rng(); x.shuffle(&mut rng); }); res From 3d69944b609e35baec03efb3870ff93b3881d678 Mon Sep 17 00:00:00 2001 From: "sinu.eth" <65924192+sinui0@users.noreply.github.com> Date: Tue, 25 Jun 2024 07:12:34 -0700 Subject: [PATCH 04/39] chore: add rebase action (#166) --- .github/workflows/rebase.yml | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 .github/workflows/rebase.yml diff --git a/.github/workflows/rebase.yml b/.github/workflows/rebase.yml new file mode 100644 index 00000000..26827dbd --- /dev/null +++ b/.github/workflows/rebase.yml @@ -0,0 +1,24 @@ +name: Automatic Rebase +on: + issue_comment: + types: [created] +jobs: + rebase: + name: Rebase + runs-on: ubuntu-latest + if: >- + github.event.issue.pull_request != '' && + contains(github.event.comment.body, '/rebase') && + github.event.comment.author_association == 'MEMBER' + steps: + - name: Checkout the latest code + uses: actions/checkout@v3 + with: + token: ${{ secrets.GITHUB_TOKEN }} + fetch-depth: 0 # otherwise, you will fail to push refs to dest repo + - name: Automatic Rebase + uses: cirrus-actions/rebase@1.8 + with: + autosquash: false + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} From b30fb9b3236a1a2361f5f16d8adf8a84006998c1 Mon Sep 17 00:00:00 2001 From: "sinu.eth" <65924192+sinui0@users.noreply.github.com> Date: Tue, 25 Jun 2024 11:54:34 -0700 Subject: [PATCH 05/39] fix: rebase action condition (#168) * fix: rebase action condition * collapse to single line * add owner and collab conditions --- .github/workflows/rebase.yml | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/.github/workflows/rebase.yml b/.github/workflows/rebase.yml index 26827dbd..e0e55111 100644 --- a/.github/workflows/rebase.yml +++ b/.github/workflows/rebase.yml @@ -7,12 +7,16 @@ jobs: name: Rebase runs-on: ubuntu-latest if: >- - github.event.issue.pull_request != '' && + github.event.issue.pull_request != '' && contains(github.event.comment.body, '/rebase') && - github.event.comment.author_association == 'MEMBER' + ( + github.event.comment.author_association == 'MEMBER' || + github.event.comment.author_association == 'OWNER' || + github.event.comment.author_association == 'COLLABORATOR' + ) steps: - name: Checkout the latest code - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: token: ${{ secrets.GITHUB_TOKEN }} fetch-depth: 0 # otherwise, you will fail to push refs to dest repo From d20e4ccdeb6fef7a831a1b229bcf7383c612b069 Mon Sep 17 00:00:00 2001 From: "sinu.eth" <65924192+sinui0@users.noreply.github.com> Date: Thu, 7 Mar 2024 08:15:39 -0800 Subject: [PATCH 06/39] feat: mpz-common (#107) * feat: mpz-common * reduce visibility of test module * pr feedback --- Cargo.toml | 8 +- mpz-common/Cargo.toml | 19 +++ mpz-common/src/context.rs | 46 +++++ mpz-common/src/executor/mod.rs | 24 +++ mpz-common/src/executor/st.rs | 122 ++++++++++++++ mpz-common/src/id.rs | 52 ++++++ mpz-common/src/lib.rs | 27 +++ mpz-common/src/sync/mod.rs | 295 +++++++++++++++++++++++++++++++++ mpz-common/src/sync/mutex.rs | 107 ++++++++++++ 9 files changed, 698 insertions(+), 2 deletions(-) create mode 100644 mpz-common/Cargo.toml create mode 100644 mpz-common/src/context.rs create mode 100644 mpz-common/src/executor/mod.rs create mode 100644 mpz-common/src/executor/st.rs create mode 100644 mpz-common/src/id.rs create mode 100644 mpz-common/src/lib.rs create mode 100644 mpz-common/src/sync/mod.rs create mode 100644 mpz-common/src/sync/mutex.rs diff --git a/Cargo.toml b/Cargo.toml index e648bad3..baf9d957 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,6 +9,7 @@ members = [ "share-conversion/*", "matrix-transpose", "clmul", + "mpz-common", ] resolver = "2" @@ -20,6 +21,7 @@ resolver = "2" [workspace.dependencies] mpz-core = { path = "mpz-core" } +mpz-common = { path = "mpz-common" } mpz-circuits = { path = "mpz-circuits" } mpz-ot-core = { path = "ot/mpz-ot-core" } mpz-ot = { path = "ot/mpz-ot" } @@ -31,8 +33,8 @@ mpz-fields = { path = "mpz-fields" } clmul = { path = "clmul" } matrix-transpose = { path = "matrix-transpose" } -tlsn-utils = { git = "https://github.com/tlsnotary/tlsn-utils", rev = "51f313d" } -tlsn-utils-aio = { git = "https://github.com/tlsnotary/tlsn-utils", rev = "51f313d" } +tlsn-utils = { git = "https://github.com/tlsnotary/tlsn-utils", rev = "8f2fc9e" } +tlsn-utils-aio = { git = "https://github.com/tlsnotary/tlsn-utils", rev = "8f2fc9e" } # rand rand_chacha = "0.3" @@ -61,6 +63,7 @@ futures = "0.3" futures-util = "0.3" tokio = "1.23" tokio-util = "0.7" +scoped-futures = "0.1.3" # serialization ark-serialize = "0.4" @@ -72,6 +75,7 @@ prost-build = "0.9" bytes = "1" yamux = "0.10" bytemuck = { version = "1.13", features = ["derive"] } +serio = { git = "https://github.com/tlsnotary/tlsn-utils", rev = "8f2fc9e" } # testing prost = "0.9" diff --git a/mpz-common/Cargo.toml b/mpz-common/Cargo.toml new file mode 100644 index 00000000..c8e158a9 --- /dev/null +++ b/mpz-common/Cargo.toml @@ -0,0 +1,19 @@ +[package] +name = "mpz-common" +version = "0.1.0" +edition = "2021" + +[features] +default = ["sync"] +sync = [] +test-utils = [] + +[dependencies] +mpz-core.workspace = true + +futures.workspace = true +async-trait.workspace = true +scoped-futures.workspace = true +thiserror.workspace = true +serio.workspace = true +serde = { workspace = true, features = ["derive"] } diff --git a/mpz-common/src/context.rs b/mpz-common/src/context.rs new file mode 100644 index 00000000..67d74b11 --- /dev/null +++ b/mpz-common/src/context.rs @@ -0,0 +1,46 @@ +use async_trait::async_trait; + +use scoped_futures::ScopedBoxFuture; +use serio::{IoSink, IoStream}; + +use crate::ThreadId; + +/// A thread context. +#[async_trait] +pub trait Context: Send { + /// The type of I/O channel used by the thread. + type Io: IoSink + IoStream + Send + Unpin + 'static; + + /// Returns the thread ID. + fn id(&self) -> &ThreadId; + + /// Returns a mutable reference to the thread's I/O channel. + fn io_mut(&mut self) -> &mut Self::Io; + + /// Forks the thread and executes the provided closures concurrently. + /// + /// Implementations may not be able to fork, in which case the closures are executed + /// sequentially. + async fn join<'a, A, B, RA, RB>(&'a mut self, a: A, b: B) -> (RA, RB) + where + A: for<'b> FnOnce(&'b mut Self) -> ScopedBoxFuture<'a, 'b, RA> + Send + 'a, + B: for<'b> FnOnce(&'b mut Self) -> ScopedBoxFuture<'a, 'b, RB> + Send + 'a, + RA: Send + 'a, + RB: Send + 'a; + + /// Forks the thread and executes the provided closures concurrently, returning an error + /// if one of the closures fails. + /// + /// This method is short circuiting, meaning that it returns as soon as one of the closures + /// fails, potentially canceling the other. + /// + /// Implementations may not be able to fork, in which case the closures are executed + /// sequentially. + async fn try_join<'a, A, B, RA, RB, E>(&'a mut self, a: A, b: B) -> Result<(RA, RB), E> + where + A: for<'b> FnOnce(&'b mut Self) -> ScopedBoxFuture<'a, 'b, Result> + Send + 'a, + B: for<'b> FnOnce(&'b mut Self) -> ScopedBoxFuture<'a, 'b, Result> + Send + 'a, + RA: Send + 'a, + RB: Send + 'a, + E: Send + 'a; +} diff --git a/mpz-common/src/executor/mod.rs b/mpz-common/src/executor/mod.rs new file mode 100644 index 00000000..d5e66b37 --- /dev/null +++ b/mpz-common/src/executor/mod.rs @@ -0,0 +1,24 @@ +//! Executors. + +mod st; + +pub use st::STExecutor; + +#[cfg(any(test, feature = "test-utils"))] +mod test_utils { + use serio::channel::{duplex, MemoryDuplex}; + + use super::*; + + /// Creates a pair of single-threaded executors with memory I/O channels. + pub fn test_st_executor( + io_buffer: usize, + ) -> (STExecutor, STExecutor) { + let (io_0, io_1) = duplex(io_buffer); + + (STExecutor::new(io_0), STExecutor::new(io_1)) + } +} + +#[cfg(any(test, feature = "test-utils"))] +pub use test_utils::*; diff --git a/mpz-common/src/executor/st.rs b/mpz-common/src/executor/st.rs new file mode 100644 index 00000000..bf2e9296 --- /dev/null +++ b/mpz-common/src/executor/st.rs @@ -0,0 +1,122 @@ +use async_trait::async_trait; + +use scoped_futures::ScopedBoxFuture; +use serio::{IoSink, IoStream}; + +use crate::{context::Context, ThreadId}; + +/// A single-threaded executor. +pub struct STExecutor { + id: ThreadId, + io: Io, +} + +impl STExecutor +where + Io: IoSink + IoStream + Send + Unpin + 'static, +{ + /// Creates a new single-threaded executor. + /// + /// # Arguments + /// + /// * `io` - The I/O channel used by the executor. + pub fn new(io: Io) -> Self { + Self { + id: ThreadId::default(), + io, + } + } +} + +#[async_trait] +impl Context for STExecutor +where + Io: IoSink + IoStream + Send + Unpin + 'static, +{ + type Io = Io; + + fn id(&self) -> &ThreadId { + &self.id + } + + fn io_mut(&mut self) -> &mut Self::Io { + &mut self.io + } + + async fn join<'a, A, B, RA, RB>(&'a mut self, a: A, b: B) -> (RA, RB) + where + A: for<'b> FnOnce(&'b mut Self) -> ScopedBoxFuture<'a, 'b, RA> + Send + 'a, + B: for<'b> FnOnce(&'b mut Self) -> ScopedBoxFuture<'a, 'b, RB> + Send + 'a, + RA: Send + 'a, + RB: Send + 'a, + { + let a = a(self).await; + let b = b(self).await; + (a, b) + } + + async fn try_join<'a, A, B, RA, RB, E>(&'a mut self, a: A, b: B) -> Result<(RA, RB), E> + where + A: for<'b> FnOnce(&'b mut Self) -> ScopedBoxFuture<'a, 'b, Result> + Send + 'a, + B: for<'b> FnOnce(&'b mut Self) -> ScopedBoxFuture<'a, 'b, Result> + Send + 'a, + RA: Send + 'a, + RB: Send + 'a, + E: Send + 'a, + { + let a = a(self).await?; + let b = b(self).await?; + Ok((a, b)) + } +} + +#[cfg(test)] +mod tests { + use futures::executor::block_on; + use scoped_futures::ScopedFutureExt; + use serio::channel::duplex; + + use super::*; + + #[derive(Debug, Default)] + struct LifetimeTest { + a: ThreadId, + b: ThreadId, + } + + impl LifetimeTest { + // This test is to ensure that the compiler is satisfied with the lifetimes + // of the async closures passed to `join`. + async fn foo(&mut self, ctx: &mut Ctx) { + let a = &mut self.a; + let b = &mut self.b; + ctx.join( + |ctx| { + async move { + *a = ctx.id().clone(); + } + .scope_boxed() + }, + |ctx| { + async move { + *b = ctx.id().clone(); + } + .scope_boxed() + }, + ) + .await; + + // Make sure we can mutate the fields after borrowing them in the async closures. + self.a = ThreadId::default(); + self.b = ThreadId::default(); + } + } + + #[test] + fn test_st_executor_join() { + let (io, _) = duplex(1); + let mut ctx = STExecutor::new(io); + let mut test = LifetimeTest::default(); + + block_on(test.foo(&mut ctx)); + } +} diff --git a/mpz-common/src/id.rs b/mpz-common/src/id.rs new file mode 100644 index 00000000..97b8ff31 --- /dev/null +++ b/mpz-common/src/id.rs @@ -0,0 +1,52 @@ +use std::sync::Arc; + +/// A logical thread identifier. +/// +/// Every thread is assigned a unique identifier, which can be forked to create a child thread. +#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub struct ThreadId(Arc<[u8]>); + +impl Default for ThreadId { + fn default() -> Self { + Self(vec![0].into()) + } +} + +impl ThreadId { + /// Creates a new thread ID with the provided ID. + #[inline] + pub fn new(id: u8) -> Self { + Self(vec![id].into()) + } + + /// Returns the thread ID as a byte slice. + #[inline] + pub fn as_bytes(&self) -> &[u8] { + &self.0 + } + + /// Increments the thread ID, returning `None` if the ID overflows. + #[inline] + pub fn increment(&self) -> Option { + let mut id = self.0.to_vec(); + id.last_mut().expect("id is not empty").checked_add(1)?; + + Some(Self(id.into())) + } + + /// Forks the thread ID. + #[inline] + pub fn fork(&self) -> Self { + let mut id = vec![0; self.0.len() + 1]; + id[0..self.0.len()].copy_from_slice(&self.0); + + Self(id.into()) + } +} + +impl AsRef<[u8]> for ThreadId { + #[inline] + fn as_ref(&self) -> &[u8] { + self.as_bytes() + } +} diff --git a/mpz-common/src/lib.rs b/mpz-common/src/lib.rs new file mode 100644 index 00000000..35447c3b --- /dev/null +++ b/mpz-common/src/lib.rs @@ -0,0 +1,27 @@ +//! Common functionality for `mpz`. +//! +//! This crate provides various common functionalities needed for modeling protocol execution, I/O, +//! and multi-threading. +//! +//! This crate does not provide any cryptographic primitives, see `mpz-core` for that. + +#![deny( + unsafe_code, + missing_docs, + unused_imports, + unused_must_use, + unreachable_pub, + clippy::all +)] + +mod context; +pub mod executor; +mod id; +#[cfg(feature = "sync")] +pub mod sync; + +pub use context::Context; +pub use id::ThreadId; + +// Re-export scoped-futures for use with the callback-like API in `Context`. +pub use scoped_futures; diff --git a/mpz-common/src/sync/mod.rs b/mpz-common/src/sync/mod.rs new file mode 100644 index 00000000..0738cc46 --- /dev/null +++ b/mpz-common/src/sync/mod.rs @@ -0,0 +1,295 @@ +//! Synchronization primitives. + +mod mutex; + +pub use mutex::{Mutex, MutexError}; + +use std::{ + collections::HashMap, + pin::Pin, + sync::{Arc, Mutex as StdMutex}, + task::{Context as StdContext, Poll, Waker}, +}; + +use futures::{future::poll_fn, Future}; +use serio::{stream::IoStreamExt, IoDuplex}; + +/// The error type for [`Syncer`]. +#[derive(Debug, thiserror::Error)] +#[error("sync error: {0}")] +pub struct SyncError(#[from] std::io::Error); + +/// A primitive for synchronizing the order of execution across logical threads. +/// +/// This is useful for when multiple different functionalities need to access some shared stateful resource. +/// In such cases, it is important that the order in which this occurs is synchronized from all parties views. +/// +/// [`Syncer`] employs a leader-follower coordination pattern, where the leader is responsible for +/// dictating the order of execution, and the followers ensure their local execution is synchronized to it. +/// +/// Every operation involves broadcasting a 4-byte ticket to all followers, so be conscious of the overhead +/// of this. +/// +/// See [`Mutex`] for a higher-level primitive that can be used to obtain a lock on a resource in synchronized +/// order. +#[derive(Debug, Clone)] +pub struct Syncer(SyncerInner); + +impl Syncer { + /// Creates a new leader. + pub fn new_leader() -> Self { + Self(SyncerInner::Leader(Leader::default())) + } + + /// Creates a new follower. + pub fn new_follower() -> Self { + Self(SyncerInner::Follower(Follower::default())) + } + + /// Synchronizes the order of execution across logical threads. + /// + /// # Arguments + /// + /// * `io` - The I/O channel of the logical thread. + /// * `f` - The function to execute. + pub async fn sync + Unpin, F, R>( + &self, + io: &mut Io, + f: F, + ) -> Result + where + F: FnOnce() -> R + Unpin, + R: Unpin, + { + match &self.0 { + SyncerInner::Leader(leader) => leader.sync(io, f).await, + SyncerInner::Follower(follower) => follower.sync(io, f).await, + } + } +} + +#[derive(Debug, Clone)] +enum SyncerInner { + Leader(Leader), + Follower(Follower), +} + +#[derive(Debug, Default, Clone)] +struct Leader { + tick: Arc>, +} + +impl Leader { + async fn sync + Unpin, F, R>( + &self, + io: &mut Io, + f: F, + ) -> Result + where + F: FnOnce() -> R + Unpin, + R: Unpin, + { + let mut io = Pin::new(io); + poll_fn(|cx| io.as_mut().poll_ready(cx)).await?; + let (output, tick) = { + let mut tick_lock = self.tick.lock().unwrap(); + let output = f(); + let tick = tick_lock.increment_in_place(); + (output, tick) + }; + io.start_send(tick)?; + Ok(output) + } +} + +#[derive(Debug, Default, Clone)] +struct Follower { + queue: Arc>, +} + +impl Follower { + async fn sync + Unpin, F, R>( + &self, + io: &mut Io, + f: F, + ) -> Result + where + F: FnOnce() -> R + Unpin, + R: Unpin, + { + let tick = io.expect_next().await?; + Ok(Wait::new(&self.queue, tick, f).await) + } +} + +#[derive(Debug, Default)] +struct Queue { + // The current ticket. + tick: Ticket, + // Tasks waiting for their ticket to be accepted. + waiting: HashMap, +} + +impl Queue { + // Wakes up the next waiting task. + fn wake_next(&mut self) { + if let Some(waker) = self.waiting.remove(&self.tick) { + waker.wake(); + } + } +} + +#[derive(Debug)] +#[must_use = "futures do nothing unless you `.await` or poll them"] +struct Wait<'a, F> { + queue: &'a StdMutex, + tick: Ticket, + f: Option, +} + +impl<'a, F> Wait<'a, F> { + fn new(queue: &'a StdMutex, tick: Ticket, f: F) -> Self { + Self { + queue, + tick, + f: Some(f), + } + } +} + +impl<'a, F, R> Future for Wait<'a, F> +where + F: FnOnce() -> R + Unpin, + R: Unpin, +{ + type Output = R; + + fn poll(mut self: Pin<&mut Self>, cx: &mut StdContext<'_>) -> Poll { + let mut queue_lock = self.queue.lock().unwrap(); + if queue_lock.tick == self.tick { + let f = self + .f + .take() + .expect("future should not be polled after completion"); + let output = f(); + queue_lock.tick.increment_in_place(); + queue_lock.wake_next(); + Poll::Ready(output) + } else { + queue_lock.waiting.insert(self.tick, cx.waker().clone()); + Poll::Pending + } + } +} + +/// A ticket for [`Syncer`]. +#[derive( + Debug, + Default, + Clone, + Copy, + PartialEq, + Eq, + PartialOrd, + Ord, + Hash, + serde::Serialize, + serde::Deserialize, +)] +pub struct Ticket(u32); + +impl Ticket { + /// Increments the ticket in place and returns the original value. + fn increment_in_place(&mut self) -> Self { + let current = self.0; + // We should be able to wrap around without worry. This should only + // corrupt synchronization if there are more than 2^32 - 1 pending ops. + // In which case, give your head a shake. + self.0 = self.0.wrapping_add(1); + Self(current) + } +} + +#[cfg(test)] +mod tests { + use std::sync::MutexGuard; + + use futures::executor::block_on; + use serio::channel::duplex; + + use super::*; + + #[test] + fn test_syncer() { + let (mut io_0a, mut io_0b) = duplex(1); + let (mut io_1a, mut io_1b) = duplex(1); + let (mut io_2a, mut io_2b) = duplex(1); + + let syncer_a = Syncer::new_leader(); + let syncer_b = Syncer::new_follower(); + + let log_a = Arc::new(StdMutex::new(Vec::new())); + let log_b = Arc::new(StdMutex::new(Vec::new())); + + let a = async { + futures::try_join!( + syncer_a.sync(&mut io_0a, || { + let mut log = log_a.lock().unwrap(); + log.push(0); + }), + syncer_a.sync(&mut io_1a, || { + let mut log = log_a.lock().unwrap(); + log.push(1); + }), + syncer_a.sync(&mut io_2a, || { + let mut log = log_a.lock().unwrap(); + log.push(2); + }), + ) + .unwrap(); + }; + + // Order is out of sync. + let b = async { + futures::try_join!( + syncer_b.sync(&mut io_2b, || { + let mut log = log_b.lock().unwrap(); + log.push(2); + }), + syncer_b.sync(&mut io_0b, || { + let mut log = log_b.lock().unwrap(); + log.push(0); + }), + syncer_b.sync(&mut io_1b, || { + let mut log = log_b.lock().unwrap(); + log.push(1); + }), + ) + .unwrap(); + }; + + block_on(async { + futures::join!(a, b); + }); + + let log_a = Arc::into_inner(log_a).unwrap().into_inner().unwrap(); + let log_b = Arc::into_inner(log_b).unwrap().into_inner().unwrap(); + + assert_eq!(log_a, log_b); + } + + #[test] + fn test_syncer_is_send() { + let (mut io, _) = duplex(1); + let syncer = Syncer::new_leader(); + + fn is_send(_: T) {} + + fn closure_return_not_send<'a>() -> impl FnOnce() -> MutexGuard<'a, ()> { + || todo!() + } + + // The future should be send even if the type returned by the closure is not. + is_send(syncer.sync(&mut io, closure_return_not_send())); + } +} diff --git a/mpz-common/src/sync/mutex.rs b/mpz-common/src/sync/mutex.rs new file mode 100644 index 00000000..1b43e849 --- /dev/null +++ b/mpz-common/src/sync/mutex.rs @@ -0,0 +1,107 @@ +//! Synchronized mutex. + +use std::sync::{LockResult, Mutex as StdMutex, MutexGuard}; + +use crate::{context::Context, sync::Syncer}; + +use super::SyncError; + +/// A mutex which synchronizes exclusive access to a resource across logical threads. +/// +/// There are two configurations for a mutex, either as a leader or as a follower. +/// +/// **Leader** +/// +/// A leader mutex is the authority on the order in which threads can acquire a lock. When a +/// thread acquires a lock, it broadcasts a message to all follower mutexes, which then enforce +/// that this order is preserved. +/// +/// **Follower** +/// +/// A follower mutex waits for messages from the leader mutex to inform it of the order in which +/// threads can acquire a lock. +#[derive(Debug)] +pub struct Mutex { + inner: StdMutex, + syncer: Syncer, +} + +impl Mutex { + /// Creates a new leader mutex. + /// + /// # Arguments + /// + /// * `value` - The value protected by the mutex. + pub fn new_leader(value: T) -> Self { + Self { + inner: StdMutex::new(value), + syncer: Syncer::new_leader(), + } + } + + /// Creates a new follower mutex. + /// + /// # Arguments + /// + /// * `value` - The value protected by the mutex. + pub fn new_follower(value: T) -> Self { + Self { + inner: StdMutex::new(value), + syncer: Syncer::new_follower(), + } + } + + /// Returns a lock on the mutex. + pub async fn lock(&self, ctx: &mut Ctx) -> Result, MutexError> { + self.syncer + .sync(ctx.io_mut(), || self.inner.lock()) + .await? + .map_err(|_| MutexError::Poisoned) + } + + /// Returns the inner value, consuming the mutex. + pub fn into_inner(self) -> LockResult { + self.inner.into_inner() + } +} + +/// An error returned when a mutex operation fails. +#[derive(Debug, thiserror::Error)] +pub enum MutexError { + /// A synchronization error occurred. + #[error("sync error: {0}")] + Sync(#[from] SyncError), + /// The mutex was poisoned. + #[error("mutex was poisoned")] + Poisoned, +} + +#[cfg(test)] +mod tests { + use std::sync::Arc; + + use super::*; + + #[test] + fn test_mutex_st() { + let leader_mutex = Arc::new(Mutex::new_leader(())); + let follower_mutex = Arc::new(Mutex::new_follower(())); + + let (mut ctx_a, mut ctx_b) = crate::executor::test_st_executor(8); + + futures::executor::block_on(async { + futures::join!( + async { + drop(leader_mutex.lock(&mut ctx_a).await.unwrap()); + drop(leader_mutex.lock(&mut ctx_a).await.unwrap()); + drop(leader_mutex.lock(&mut ctx_a).await.unwrap()); + }, + async { + drop(follower_mutex.lock(&mut ctx_b).await.unwrap()); + drop(follower_mutex.lock(&mut ctx_b).await.unwrap()); + drop(follower_mutex.lock(&mut ctx_b).await.unwrap()); + }, + ); + }); + } +} From 38e7d0d37b4a5aec23c692eea9c4ed2a333763c4 Mon Sep 17 00:00:00 2001 From: "sinu.eth" <65924192+sinui0@users.noreply.github.com> Date: Thu, 7 Mar 2024 08:21:13 -0800 Subject: [PATCH 07/39] refactor: cointoss (#108) --- Cargo.toml | 4 + mpz-cointoss-core/Cargo.toml | 14 ++ .../mod.rs => mpz-cointoss-core/src/lib.rs | 19 +- .../src}/msgs.rs | 11 +- .../src}/receiver.rs | 10 +- .../src}/sender.rs | 45 ++-- mpz-cointoss/Cargo.toml | 18 ++ mpz-cointoss/src/lib.rs | 197 ++++++++++++++++++ mpz-core/src/lib.rs | 1 - 9 files changed, 285 insertions(+), 34 deletions(-) create mode 100644 mpz-cointoss-core/Cargo.toml rename mpz-core/src/cointoss/mod.rs => mpz-cointoss-core/src/lib.rs (72%) rename {mpz-core/src/cointoss => mpz-cointoss-core/src}/msgs.rs (69%) rename {mpz-core/src/cointoss => mpz-cointoss-core/src}/receiver.rs (94%) rename {mpz-core/src/cointoss => mpz-cointoss-core/src}/sender.rs (68%) create mode 100644 mpz-cointoss/Cargo.toml create mode 100644 mpz-cointoss/src/lib.rs diff --git a/Cargo.toml b/Cargo.toml index baf9d957..71c8a684 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,6 +10,8 @@ members = [ "matrix-transpose", "clmul", "mpz-common", + "mpz-cointoss", + "mpz-cointoss-core", ] resolver = "2" @@ -23,6 +25,8 @@ resolver = "2" mpz-core = { path = "mpz-core" } mpz-common = { path = "mpz-common" } mpz-circuits = { path = "mpz-circuits" } +mpz-cointoss-core = { path = "mpz-cointoss-core" } +mpz-cointoss = { path = "mpz-cointoss" } mpz-ot-core = { path = "ot/mpz-ot-core" } mpz-ot = { path = "ot/mpz-ot" } mpz-garble-core = { path = "garble/mpz-garble-core" } diff --git a/mpz-cointoss-core/Cargo.toml b/mpz-cointoss-core/Cargo.toml new file mode 100644 index 00000000..def0f273 --- /dev/null +++ b/mpz-cointoss-core/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "mpz-cointoss-core" +version = "0.1.0" +edition = "2021" + +[dependencies] +mpz-core.workspace = true + +serde.workspace = true +thiserror.workspace = true +opaque-debug.workspace = true + +[dev-dependencies] +rand.workspace = true diff --git a/mpz-core/src/cointoss/mod.rs b/mpz-cointoss-core/src/lib.rs similarity index 72% rename from mpz-core/src/cointoss/mod.rs rename to mpz-cointoss-core/src/lib.rs index 5daa8150..542ca783 100644 --- a/mpz-core/src/cointoss/mod.rs +++ b/mpz-cointoss-core/src/lib.rs @@ -4,8 +4,7 @@ //! //! ``` //! use rand::{thread_rng, Rng}; -//! use mpz_core::cointoss::{Sender, Receiver}; -//! # use mpz_core::cointoss::CointossError; +//! use mpz_cointoss_core::{Sender, Receiver, CointossError}; //! use mpz_core::Block; //! //! # fn main() -> Result<(), CointossError> { @@ -17,7 +16,8 @@ //! //! let (sender, commitment) = sender.send(); //! let (receiver, receiver_payload) = receiver.reveal(commitment)?; -//! let (sender_output, sender_payload) = sender.finalize(receiver_payload)?; +//! let (sender_output, sender) = sender.receive(receiver_payload)?; +//! let sender_payload = sender.finalize(); //! let receiver_output = receiver.finalize(sender_payload)?; //! //! assert_eq!(sender_output, receiver_output); @@ -25,6 +25,15 @@ //! # } //! ``` +#![deny( + unsafe_code, + missing_docs, + unused_imports, + unused_must_use, + unreachable_pub, + clippy::all +)] + pub mod msgs; mod receiver; mod sender; @@ -36,8 +45,8 @@ pub use sender::{sender_state, Sender}; #[derive(Debug, thiserror::Error)] #[allow(missing_docs)] pub enum CointossError { - #[error(transparent)] - CommitmentError(#[from] crate::commit::CommitmentError), + #[error("commitment error")] + CommitmentError(#[from] mpz_core::commit::CommitmentError), #[error("count mismatch, expected {expected}, got {actual}")] CountMismatch { expected: usize, actual: usize }, } diff --git a/mpz-core/src/cointoss/msgs.rs b/mpz-cointoss-core/src/msgs.rs similarity index 69% rename from mpz-core/src/cointoss/msgs.rs rename to mpz-cointoss-core/src/msgs.rs index a6188529..1285a65e 100644 --- a/mpz-core/src/cointoss/msgs.rs +++ b/mpz-cointoss-core/src/msgs.rs @@ -2,16 +2,7 @@ use serde::{Deserialize, Serialize}; -use crate::{commit::Decommitment, hash::Hash, Block}; - -/// A coin-toss message. -#[derive(Debug, Clone, Serialize, Deserialize)] -#[allow(missing_docs)] -pub enum Message { - SenderCommitments(SenderCommitment), - SenderPayload(SenderPayload), - ReceiverPayload(ReceiverPayload), -} +use mpz_core::{commit::Decommitment, hash::Hash, Block}; /// The coin-toss sender's commitment. #[derive(Debug, Clone, Serialize, Deserialize)] diff --git a/mpz-core/src/cointoss/receiver.rs b/mpz-cointoss-core/src/receiver.rs similarity index 94% rename from mpz-core/src/cointoss/receiver.rs rename to mpz-cointoss-core/src/receiver.rs index 6e1ec26a..40dcd269 100644 --- a/mpz-core/src/cointoss/receiver.rs +++ b/mpz-cointoss-core/src/receiver.rs @@ -1,10 +1,8 @@ +use mpz_core::{hash::Hash, Block}; + use crate::{ - cointoss::{ - msgs::{ReceiverPayload, SenderCommitment, SenderPayload}, - CointossError, - }, - hash::Hash, - Block, + msgs::{ReceiverPayload, SenderCommitment, SenderPayload}, + CointossError, }; /// A coin-toss receiver. diff --git a/mpz-core/src/cointoss/sender.rs b/mpz-cointoss-core/src/sender.rs similarity index 68% rename from mpz-core/src/cointoss/sender.rs rename to mpz-cointoss-core/src/sender.rs index 6cc0c3df..1e78b76e 100644 --- a/mpz-core/src/cointoss/sender.rs +++ b/mpz-cointoss-core/src/sender.rs @@ -1,10 +1,8 @@ +use mpz_core::{commit::HashCommit, Block}; + use crate::{ - cointoss::{ - msgs::{ReceiverPayload, SenderCommitment, SenderPayload}, - CointossError, - }, - commit::HashCommit, - Block, + msgs::{ReceiverPayload, SenderCommitment, SenderPayload}, + CointossError, }; /// A coin-toss sender. @@ -40,11 +38,12 @@ impl Sender { } impl Sender { - /// Finalizes the coin-toss, returning the random seeds and the sender's payload. - pub fn finalize( + /// Receives the receiver's payload and computes the output of the + /// coin-toss. + pub fn receive( self, payload: ReceiverPayload, - ) -> Result<(Vec, SenderPayload), CointossError> { + ) -> Result<(Vec, Sender), CointossError> { let receiver_seeds = payload.seeds; let sender_seeds = self.state.seeds; @@ -63,16 +62,27 @@ impl Sender { Ok(( seeds, - SenderPayload { - decommitment: self.state.decommitment, + Sender { + state: sender_state::Received { + decommitment: self.state.decommitment, + }, }, )) } } +impl Sender { + /// Finalizes the coin-toss, decommitting the sender's seeds. + pub fn finalize(self) -> SenderPayload { + SenderPayload { + decommitment: self.state.decommitment, + } + } +} + /// Coin-toss sender state. pub mod sender_state { - use crate::commit::Decommitment; + use mpz_core::commit::Decommitment; use super::*; @@ -83,6 +93,7 @@ pub mod sender_state { impl Sealed for Initialized {} impl Sealed for Committed {} + impl Sealed for Received {} } /// The sender's state. @@ -106,4 +117,14 @@ pub mod sender_state { impl State for Committed {} opaque_debug::implement!(Committed); + + /// The sender's state after they've received the payload from the + /// receiver. + pub struct Received { + pub(super) decommitment: Decommitment>, + } + + impl State for Received {} + + opaque_debug::implement!(Received); } diff --git a/mpz-cointoss/Cargo.toml b/mpz-cointoss/Cargo.toml new file mode 100644 index 00000000..e5765d19 --- /dev/null +++ b/mpz-cointoss/Cargo.toml @@ -0,0 +1,18 @@ +[package] +name = "mpz-cointoss" +version = "0.1.0" +edition = "2021" + +[dependencies] +mpz-core.workspace = true +mpz-common.workspace = true +mpz-cointoss-core.workspace = true + +futures.workspace = true +serio.workspace = true +thiserror.workspace = true + +[dev-dependencies] +mpz-common = { workspace = true, features = ["test-utils"] } + +rand.workspace = true diff --git a/mpz-cointoss/src/lib.rs b/mpz-cointoss/src/lib.rs new file mode 100644 index 00000000..4d4747c0 --- /dev/null +++ b/mpz-cointoss/src/lib.rs @@ -0,0 +1,197 @@ +//! A simple 2-party coin-toss protocol. +//! +//! # Example +//! +//! ``` +//! use rand::{thread_rng, Rng}; +//! use mpz_core::Block; +//! use mpz_common::executor::test_st_executor; +//! use mpz_cointoss::{cointoss_receiver, cointoss_sender}; +//! # use mpz_cointoss::CointossError; +//! # use futures::executor::block_on; +//! +//! # fn main() { +//! # block_on(async { +//! let (mut ctx_sender, mut ctx_receiver) = test_st_executor(8); +//! let sender_seeds = (0..8).map(|_| Block::random(&mut thread_rng())).collect(); +//! let receiver_seeds = (0..8).map(|_| Block::random(&mut thread_rng())).collect(); +//! +//! let (sender_output, receiver_output) = +//! futures::try_join!( +//! cointoss_sender(&mut ctx_sender, sender_seeds), +//! cointoss_receiver(&mut ctx_receiver, receiver_seeds), +//! )?; +//! +//! assert_eq!(sender_output, receiver_output); +//! # Ok::<_, CointossError>(()) +//! # }).unwrap(); +//! # } +//! ``` + +#![deny( + unsafe_code, + missing_docs, + unused_imports, + unused_must_use, + unreachable_pub, + clippy::all +)] + +use mpz_cointoss_core::{ + CointossError as CoreError, Receiver as CoreReceiver, Sender as CoreSender, +}; +use mpz_common::Context; +use mpz_core::Block; +use serio::{stream::IoStreamExt, SinkExt}; + +pub use mpz_cointoss_core::{msgs, receiver_state, sender_state}; + +/// Coin-toss protocol error. +#[derive(Debug, thiserror::Error)] +#[non_exhaustive] +pub enum CointossError { + /// An I/O error occurred. + #[error("io error: {0}")] + Io(#[from] std::io::Error), + /// A core error occurred. + #[error("core error: {0}")] + Core(#[from] CoreError), +} + +/// A coin-toss sender. +#[derive(Debug)] +pub struct Sender { + inner: CoreSender, +} + +impl Sender { + /// Create a new sender. + pub fn new(seeds: Vec) -> Self { + Self { + inner: CoreSender::new(seeds), + } + } + + /// Sends the coin-toss commitment. + pub async fn commit( + self, + ctx: &mut impl Context, + ) -> Result, CointossError> { + let (inner, commitment) = self.inner.send(); + ctx.io_mut().send(commitment).await?; + Ok(Sender { inner }) + } + + /// Executes the coin-toss protocol to completion. + pub async fn execute(self, ctx: &mut impl Context) -> Result, CointossError> { + let (seeds, sender) = self.commit(ctx).await?.receive(ctx).await?; + sender.finalize(ctx).await?; + Ok(seeds) + } +} + +impl Sender { + /// Receives the receiver's payload and computes the output of the coin-toss. + pub async fn receive( + self, + ctx: &mut impl Context, + ) -> Result<(Vec, Sender), CointossError> { + let payload = ctx.io_mut().expect_next().await?; + let (seeds, sender) = self.inner.receive(payload)?; + Ok((seeds, Sender { inner: sender })) + } +} + +impl Sender { + /// Finalizes the coin-toss, decommitting the sender's seeds. + pub async fn finalize(self, ctx: &mut impl Context) -> Result<(), CointossError> { + ctx.io_mut().send(self.inner.finalize()).await?; + Ok(()) + } +} + +/// A coin-toss receiver. +#[derive(Debug)] +pub struct Receiver { + inner: CoreReceiver, +} + +impl Receiver { + /// Create a new receiver. + pub fn new(seeds: Vec) -> Self { + Self { + inner: CoreReceiver::new(seeds), + } + } + + /// Reveals the receiver's seeds after receiving the sender's commitment. + pub async fn receive( + self, + ctx: &mut impl Context, + ) -> Result, CointossError> { + let commitment = ctx.io_mut().expect_next().await?; + let (inner, payload) = self.inner.reveal(commitment)?; + ctx.io_mut().send(payload).await?; + Ok(Receiver { inner }) + } + + /// Executes the coin-toss protocol to completion. + pub async fn execute(self, ctx: &mut impl Context) -> Result, CointossError> { + self.receive(ctx).await?.finalize(ctx).await + } +} + +impl Receiver { + /// Finalizes the coin-toss, returning the random seeds. + pub async fn finalize(self, ctx: &mut impl Context) -> Result, CointossError> { + let payload = ctx.io_mut().expect_next().await?; + let seeds = self.inner.finalize(payload)?; + Ok(seeds) + } +} + +/// Executes the coin-toss protocol as the sender. +/// +/// # Arguments +/// +/// * `ctx` - The thread context. +/// * `seeds` - The seeds to use for the coin-toss. +pub async fn cointoss_sender( + ctx: &mut impl Context, + seeds: Vec, +) -> Result, CointossError> { + Sender::new(seeds).execute(ctx).await +} + +/// Executes the coin-toss protocol as the receiver. +/// +/// # Arguments +/// +/// * `ctx` - The thread context. +/// * `seeds` - The seeds to use for the coin-toss. +pub async fn cointoss_receiver( + ctx: &mut impl Context, + seeds: Vec, +) -> Result, CointossError> { + Receiver::new(seeds).execute(ctx).await +} + +#[cfg(test)] +mod tests { + use super::*; + + use futures::executor::block_on; + use mpz_common::executor::test_st_executor; + + #[test] + fn test_cointoss() { + let (mut ctx_a, mut ctx_b) = test_st_executor(8); + block_on(async { + futures::try_join!( + cointoss_sender(&mut ctx_a, vec![Block::ZERO, Block::ONES]), + cointoss_receiver(&mut ctx_b, vec![Block::ONES, Block::ZERO]), + ) + .unwrap() + }); + } +} diff --git a/mpz-core/src/lib.rs b/mpz-core/src/lib.rs index 59afa9aa..4fa60e0b 100644 --- a/mpz-core/src/lib.rs +++ b/mpz-core/src/lib.rs @@ -4,7 +4,6 @@ pub mod aes; pub mod block; -pub mod cointoss; pub mod commit; pub mod ggm_tree; pub mod hash; From 3415943c7dee881d65705137a56b434ebb869ff2 Mon Sep 17 00:00:00 2001 From: "sinu.eth" <65924192+sinui0@users.noreply.github.com> Date: Thu, 7 Mar 2024 08:38:09 -0800 Subject: [PATCH 08/39] refactor: mpz-ot (#109) --- ot/mpz-ot-core/src/chou_orlandi/msgs.rs | 23 +- ot/mpz-ot-core/src/kos/mod.rs | 1 + ot/mpz-ot-core/src/kos/msgs.rs | 33 +-- ot/mpz-ot-core/src/lib.rs | 11 +- ot/mpz-ot/Cargo.toml | 13 +- ot/mpz-ot/benches/ot.rs | 43 ++- ot/mpz-ot/src/actor/kos/error.rs | 144 --------- ot/mpz-ot/src/actor/kos/mod.rs | 194 ------------ ot/mpz-ot/src/actor/kos/msgs.rs | 57 ---- ot/mpz-ot/src/actor/kos/receiver.rs | 376 ------------------------ ot/mpz-ot/src/actor/kos/sender.rs | 340 --------------------- ot/mpz-ot/src/actor/mod.rs | 4 - ot/mpz-ot/src/chou_orlandi/error.rs | 28 +- ot/mpz-ot/src/chou_orlandi/mod.rs | 175 +++-------- ot/mpz-ot/src/chou_orlandi/receiver.rs | 162 ++++------ ot/mpz-ot/src/chou_orlandi/sender.rs | 135 +++------ ot/mpz-ot/src/ideal/{owned => }/cot.rs | 59 ++-- ot/mpz-ot/src/ideal/mod.rs | 18 +- ot/mpz-ot/src/ideal/{owned => }/ot.rs | 106 ++----- ot/mpz-ot/src/ideal/owned/mod.rs | 9 - ot/mpz-ot/src/ideal/{owned => }/rcot.rs | 63 ++-- ot/mpz-ot/src/ideal/{owned => }/rot.rs | 86 +++--- ot/mpz-ot/src/ideal/shared/cot.rs | 137 --------- ot/mpz-ot/src/ideal/shared/mod.rs | 14 - ot/mpz-ot/src/ideal/shared/ot.rs | 137 --------- ot/mpz-ot/src/ideal/shared/rcot.rs | 151 ---------- ot/mpz-ot/src/ideal/shared/rot.rs | 241 --------------- ot/mpz-ot/src/kos/error.rs | 28 +- ot/mpz-ot/src/kos/mod.rs | 217 ++++++-------- ot/mpz-ot/src/kos/receiver.rs | 282 +++++++----------- ot/mpz-ot/src/kos/sender.rs | 305 +++++++------------ ot/mpz-ot/src/kos/shared_receiver.rs | 55 ++++ ot/mpz-ot/src/kos/shared_sender.rs | 51 ++++ ot/mpz-ot/src/lib.rs | 343 +++++---------------- 34 files changed, 776 insertions(+), 3265 deletions(-) delete mode 100644 ot/mpz-ot/src/actor/kos/error.rs delete mode 100644 ot/mpz-ot/src/actor/kos/mod.rs delete mode 100644 ot/mpz-ot/src/actor/kos/msgs.rs delete mode 100644 ot/mpz-ot/src/actor/kos/receiver.rs delete mode 100644 ot/mpz-ot/src/actor/kos/sender.rs delete mode 100644 ot/mpz-ot/src/actor/mod.rs rename ot/mpz-ot/src/ideal/{owned => }/cot.rs (62%) rename ot/mpz-ot/src/ideal/{owned => }/ot.rs (54%) delete mode 100644 ot/mpz-ot/src/ideal/owned/mod.rs rename ot/mpz-ot/src/ideal/{owned => }/rcot.rs (66%) rename ot/mpz-ot/src/ideal/{owned => }/rot.rs (69%) delete mode 100644 ot/mpz-ot/src/ideal/shared/cot.rs delete mode 100644 ot/mpz-ot/src/ideal/shared/mod.rs delete mode 100644 ot/mpz-ot/src/ideal/shared/ot.rs delete mode 100644 ot/mpz-ot/src/ideal/shared/rcot.rs delete mode 100644 ot/mpz-ot/src/ideal/shared/rot.rs create mode 100644 ot/mpz-ot/src/kos/shared_receiver.rs create mode 100644 ot/mpz-ot/src/kos/shared_sender.rs diff --git a/ot/mpz-ot-core/src/chou_orlandi/msgs.rs b/ot/mpz-ot-core/src/chou_orlandi/msgs.rs index 0d7c0494..3c714410 100644 --- a/ot/mpz-ot-core/src/chou_orlandi/msgs.rs +++ b/ot/mpz-ot-core/src/chou_orlandi/msgs.rs @@ -1,30 +1,9 @@ //! Messages for the Chou-Orlandi protocol. use curve25519_dalek::RistrettoPoint; -use enum_try_as_inner::EnumTryAsInner; -use mpz_core::{cointoss, Block}; +use mpz_core::Block; use serde::{Deserialize, Serialize}; -/// A CO15 protocol message. -#[derive(Debug, Clone, EnumTryAsInner, Serialize, Deserialize)] -#[derive_err(Debug)] -#[allow(missing_docs)] -pub enum Message { - SenderSetup(SenderSetup), - SenderPayload(SenderPayload), - ReceiverPayload(ReceiverPayload), - ReceiverReveal(ReceiverReveal), - CointossSenderCommitment(cointoss::msgs::SenderCommitment), - CointossSenderPayload(cointoss::msgs::SenderPayload), - CointossReceiverPayload(cointoss::msgs::ReceiverPayload), -} - -impl From for std::io::Error { - fn from(err: MessageError) -> Self { - std::io::Error::new(std::io::ErrorKind::InvalidData, err.to_string()) - } -} - /// Sender setup message. #[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)] pub struct SenderSetup { diff --git a/ot/mpz-ot-core/src/kos/mod.rs b/ot/mpz-ot-core/src/kos/mod.rs index d551ebfc..42288251 100644 --- a/ot/mpz-ot-core/src/kos/mod.rs +++ b/ot/mpz-ot-core/src/kos/mod.rs @@ -52,6 +52,7 @@ mod tests { use rand::Rng; use rand_chacha::ChaCha12Rng; + use rand_core::SeedableRng; #[fixture] fn choices() -> Vec { diff --git a/ot/mpz-ot-core/src/kos/msgs.rs b/ot/mpz-ot-core/src/kos/msgs.rs index 7ee1bc13..d332ddd0 100644 --- a/ot/mpz-ot-core/src/kos/msgs.rs +++ b/ot/mpz-ot-core/src/kos/msgs.rs @@ -1,39 +1,8 @@ //! Messages for the KOS15 protocol. -use enum_try_as_inner::EnumTryAsInner; -use mpz_core::{ - cointoss::msgs::{ - ReceiverPayload as CointossReceiverPayload, SenderCommitment, - SenderPayload as CointossSenderPayload, - }, - Block, -}; +use mpz_core::Block; use serde::{Deserialize, Serialize}; -use crate::msgs::Derandomize; - -/// A KOS15 protocol message. -#[derive(Debug, Clone, EnumTryAsInner, Serialize, Deserialize)] -#[derive_err(Debug)] -#[allow(missing_docs)] -pub enum Message { - BaseMsg(BaseMsg), - StartExtend(StartExtend), - Extend(Extend), - Check(Check), - Derandomize(Derandomize), - SenderPayload(SenderPayload), - CointossCommit(SenderCommitment), - CointossReceiverPayload(CointossReceiverPayload), - CointossSenderPayload(CointossSenderPayload), -} - -impl From> for std::io::Error { - fn from(err: MessageError) -> Self { - std::io::Error::new(std::io::ErrorKind::InvalidData, err.to_string()) - } -} - /// Extension message sent by the receiver to agree upon the number of OTs to set up. #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] pub struct StartExtend { diff --git a/ot/mpz-ot-core/src/lib.rs b/ot/mpz-ot-core/src/lib.rs index aebad59c..f357bf8b 100644 --- a/ot/mpz-ot-core/src/lib.rs +++ b/ot/mpz-ot-core/src/lib.rs @@ -10,9 +10,14 @@ //! //! USE AT YOUR OWN RISK. -#![deny(missing_docs, unreachable_pub, unused_must_use)] -#![deny(unsafe_code)] -#![deny(clippy::all)] +#![deny( + unsafe_code, + missing_docs, + unused_imports, + unused_must_use, + unreachable_pub, + clippy::all +)] pub mod chou_orlandi; pub mod ferret; diff --git a/ot/mpz-ot/Cargo.toml b/ot/mpz-ot/Cargo.toml index c8a216b1..16fec565 100644 --- a/ot/mpz-ot/Cargo.toml +++ b/ot/mpz-ot/Cargo.toml @@ -10,21 +10,20 @@ workspace = true name = "mpz_ot" [features] -default = ["ideal", "rayon", "actor"] +default = ["ideal", "rayon"] rayon = ["mpz-ot-core/rayon"] -actor = ["dep:serde"] ideal = [] [dependencies] mpz-core.workspace = true +mpz-common.workspace = true +mpz-cointoss.workspace = true mpz-ot-core.workspace = true + tlsn-utils-aio.workspace = true + async-trait.workspace = true -prost.workspace = true futures.workspace = true -futures-util.workspace = true -aes.workspace = true -cipher.workspace = true rand.workspace = true rand_core.workspace = true rand_chacha.workspace = true @@ -35,9 +34,11 @@ itybity.workspace = true enum-try-as-inner.workspace = true opaque-debug.workspace = true serde = { workspace = true, optional = true } +serio.workspace = true cfg-if.workspace = true [dev-dependencies] +mpz-common = { workspace = true, features = ["test-utils"] } rstest = { workspace = true } criterion = { workspace = true, features = ["async_tokio"] } tokio = { workspace = true, features = [ diff --git a/ot/mpz-ot/benches/ot.rs b/ot/mpz-ot/benches/ot.rs index d4d5243b..4acb7b4e 100644 --- a/ot/mpz-ot/benches/ot.rs +++ b/ot/mpz-ot/benches/ot.rs @@ -1,11 +1,10 @@ use criterion::{black_box, criterion_group, criterion_main, BenchmarkId, Criterion}; -use futures_util::StreamExt; +use mpz_common::executor::test_st_executor; use mpz_core::Block; use mpz_ot::{ - chou_orlandi::{Receiver, ReceiverConfig, Sender, SenderConfig}, + chou_orlandi::{Receiver, Sender}, OTReceiver, OTSender, OTSetup, }; -use utils_aio::duplex::MemoryDuplex; fn chou_orlandi(c: &mut Criterion) { let rt = tokio::runtime::Runtime::new().unwrap(); @@ -15,28 +14,22 @@ fn chou_orlandi(c: &mut Criterion) { let msgs = vec![[Block::ONES; 2]; n]; let choices = vec![false; n]; b.to_async(&rt).iter(|| async { - let (sender_channel, receiver_channel) = MemoryDuplex::new(); - let (mut sender_sink, mut sender_stream) = sender_channel.split(); - let (mut receiver_sink, mut receiver_stream) = receiver_channel.split(); - - let mut sender = Sender::new(SenderConfig::default()); - let mut receiver = Receiver::new(ReceiverConfig::default()); - - let (sender_res, receiver_res) = futures::join!( - sender.setup(&mut sender_sink, &mut sender_stream), - receiver.setup(&mut receiver_sink, &mut receiver_stream) - ); - - sender_res.unwrap(); - receiver_res.unwrap(); - - let (sender_res, receiver_res) = futures::join!( - sender.send(&mut sender_sink, &mut sender_stream, &msgs), - receiver.receive(&mut receiver_sink, &mut receiver_stream, &choices) - ); - - sender_res.unwrap(); - let received = receiver_res.unwrap(); + let (mut sender_ctx, mut receiver_ctx) = test_st_executor(8); + + let mut sender = Sender::default(); + let mut receiver = Receiver::default(); + + futures::try_join!( + sender.setup(&mut sender_ctx), + receiver.setup(&mut receiver_ctx) + ) + .unwrap(); + + let (_, received) = futures::try_join!( + sender.send(&mut sender_ctx, &msgs), + receiver.receive(&mut receiver_ctx, &choices) + ) + .unwrap(); black_box(received) }) diff --git a/ot/mpz-ot/src/actor/kos/error.rs b/ot/mpz-ot/src/actor/kos/error.rs deleted file mode 100644 index 6b17a438..00000000 --- a/ot/mpz-ot/src/actor/kos/error.rs +++ /dev/null @@ -1,144 +0,0 @@ -use crate::{ - actor::kos::msgs::MessageError, - kos::{ReceiverError, SenderError}, -}; - -/// Errors that can occur in the KOS Sender Actor. -#[derive(Debug, thiserror::Error)] -#[allow(missing_docs)] -#[non_exhaustive] -pub enum SenderActorError { - #[error(transparent)] - Io(#[from] std::io::Error), - #[error(transparent)] - SenderError(#[from] SenderError), - #[error("actor channel error: {0}")] - Channel(String), - #[error("{0}")] - Other(String), -} - -impl From for SenderActorError { - fn from(err: mpz_ot_core::kos::SenderError) -> Self { - SenderActorError::SenderError(err.into()) - } -} - -impl From for SenderActorError { - fn from(err: crate::OTError) -> Self { - match err { - crate::OTError::IOError(err) => err.into(), - err => SenderActorError::Other(err.to_string()), - } - } -} - -impl From for SenderActorError { - fn from(err: crate::kos::SenderStateError) -> Self { - SenderError::from(err).into() - } -} - -impl From for SenderActorError { - fn from(err: futures::channel::oneshot::Canceled) -> Self { - SenderActorError::Channel(err.to_string()) - } -} - -impl From> for SenderActorError { - fn from(err: futures::channel::mpsc::TrySendError) -> Self { - SenderActorError::Channel(err.to_string()) - } -} - -impl From> for SenderActorError { - fn from(err: MessageError) -> Self { - SenderActorError::Io(std::io::Error::new( - std::io::ErrorKind::InvalidData, - err.to_string(), - )) - } -} - -impl From> for SenderError { - fn from(err: futures::channel::mpsc::TrySendError) -> Self { - SenderError::Other(format!("actor channel error: {}", err)) - } -} - -impl From for SenderError { - fn from(err: futures::channel::oneshot::Canceled) -> Self { - SenderError::Other(format!("actor channel canceled: {}", err)) - } -} - -/// Errors that can occur in the KOS Receiver Actor. -#[derive(Debug, thiserror::Error)] -#[allow(missing_docs)] -#[non_exhaustive] -pub enum ReceiverActorError { - #[error(transparent)] - Io(#[from] std::io::Error), - #[error(transparent)] - ReceiverError(#[from] ReceiverError), - #[error("received unexpected transfer id: {0}")] - UnexpectedTransferId(String), - #[error("actor channel error: {0}")] - Channel(String), - #[error("{0}")] - Other(String), -} - -impl From for ReceiverActorError { - fn from(err: mpz_ot_core::kos::ReceiverError) -> Self { - ReceiverActorError::ReceiverError(err.into()) - } -} - -impl From for ReceiverActorError { - fn from(err: crate::OTError) -> Self { - match err { - crate::OTError::IOError(err) => err.into(), - err => ReceiverActorError::Other(err.to_string()), - } - } -} - -impl From for ReceiverActorError { - fn from(err: crate::kos::ReceiverStateError) -> Self { - ReceiverError::from(err).into() - } -} - -impl From for ReceiverActorError { - fn from(err: futures::channel::oneshot::Canceled) -> Self { - ReceiverActorError::Channel(err.to_string()) - } -} - -impl From> for ReceiverActorError { - fn from(err: futures::channel::mpsc::TrySendError) -> Self { - ReceiverActorError::Channel(err.to_string()) - } -} - -impl From> for ReceiverActorError { - fn from(err: MessageError) -> Self { - ReceiverActorError::Io(std::io::Error::new( - std::io::ErrorKind::InvalidData, - err.to_string(), - )) - } -} - -impl From> for ReceiverError { - fn from(err: futures::channel::mpsc::TrySendError) -> Self { - ReceiverError::Other(format!("actor channel error: {}", err)) - } -} - -impl From for ReceiverError { - fn from(err: futures::channel::oneshot::Canceled) -> Self { - ReceiverError::Other(format!("actor channel canceled: {}", err)) - } -} diff --git a/ot/mpz-ot/src/actor/kos/mod.rs b/ot/mpz-ot/src/actor/kos/mod.rs deleted file mode 100644 index 875fe16f..00000000 --- a/ot/mpz-ot/src/actor/kos/mod.rs +++ /dev/null @@ -1,194 +0,0 @@ -mod error; -pub mod msgs; -mod receiver; -mod sender; - -use futures::{SinkExt, StreamExt}; -use utils_aio::{sink::IoSink, stream::IoStream}; - -use crate::kos::msgs::Message as KosMessage; - -pub use error::{ReceiverActorError, SenderActorError}; -pub use receiver::{ReceiverActor, SharedReceiver}; -pub use sender::{SenderActor, SharedSender}; - -/// Converts a sink of KOS actor messages into a sink of KOS messages. -pub(crate) fn into_kos_sink<'a, Si: IoSink> + Send + Unpin, T: Send + 'a>( - sink: &'a mut Si, -) -> impl IoSink> + Send + Unpin + 'a { - Box::pin(SinkExt::with(sink, |msg| async move { - Ok(msgs::Message::Protocol(msg)) - })) -} - -/// Converts a stream of KOS actor messages into a stream of KOS messages. -pub(crate) fn into_kos_stream<'a, St: IoStream> + Send + Unpin, T: Send + 'a>( - stream: &'a mut St, -) -> impl IoStream> + Send + Unpin + 'a { - StreamExt::map(stream, |msg| match msg { - Ok(msg) => msg.try_into_protocol().map_err(From::from), - Err(err) => Err(err), - }) -} - -#[cfg(test)] -mod tests { - use crate::{ - ideal::{ideal_ot_pair, IdealOTReceiver, IdealOTSender}, - kos::{Receiver, Sender}, - OTReceiverShared, OTSenderShared, VerifiableOTReceiverShared, - }; - - use msgs::Message; - - use super::*; - use futures::stream::{SplitSink, SplitStream}; - use rstest::*; - - use mpz_core::Block; - use mpz_ot_core::kos::{ReceiverConfig, SenderConfig}; - use rand::{Rng, SeedableRng}; - use rand_chacha::ChaCha12Rng; - use utils_aio::duplex::MemoryDuplex; - - #[fixture] - fn choices() -> Vec { - let mut rng = ChaCha12Rng::seed_from_u64(0); - (0..128).map(|_| rng.gen()).collect() - } - - #[fixture] - fn data() -> Vec<[Block; 2]> { - let mut rng = ChaCha12Rng::seed_from_u64(0); - (0..128) - .map(|_| [rng.gen::<[u8; 16]>().into(), rng.gen::<[u8; 16]>().into()]) - .collect() - } - - fn choose( - data: impl IntoIterator, - choices: impl IntoIterator, - ) -> impl Iterator { - data.into_iter() - .zip(choices) - .map(|([zero, one], choice)| if choice { one } else { zero }) - } - - async fn setup( - sender_config: SenderConfig, - receiver_config: ReceiverConfig, - count: usize, - ) -> ( - SenderActor< - IdealOTReceiver, - SplitSink>, Message<()>>, - SplitStream>>, - >, - ReceiverActor< - IdealOTSender, - SplitSink>, Message<()>>, - SplitStream>>, - >, - ) { - let (sender_channel, receiver_channel) = MemoryDuplex::new(); - - let (sender_sink, sender_stream) = sender_channel.split(); - let (receiver_sink, receiver_stream) = receiver_channel.split(); - - let (base_sender, base_receiver) = ideal_ot_pair(); - - let sender = Sender::new(sender_config, base_receiver); - let receiver = Receiver::new(receiver_config, base_sender); - - let mut sender = SenderActor::new(sender, sender_sink, sender_stream); - let mut receiver = ReceiverActor::new(receiver, receiver_sink, receiver_stream); - - let (sender_res, receiver_res) = tokio::join!(sender.setup(count), receiver.setup(count)); - - sender_res.unwrap(); - receiver_res.unwrap(); - - (sender, receiver) - } - - #[rstest] - #[tokio::test] - async fn test_kos_actor(data: Vec<[Block; 2]>, choices: Vec) { - let (mut sender_actor, mut receiver_actor) = setup( - SenderConfig::default(), - ReceiverConfig::default(), - data.len(), - ) - .await; - - let sender = sender_actor.sender(); - let receiver = receiver_actor.receiver(); - - tokio::spawn(async move { - sender_actor.run().await.unwrap(); - sender_actor - }); - - tokio::spawn(async move { - receiver_actor.run().await.unwrap(); - receiver_actor - }); - - let (sender_res, receiver_res) = tokio::join!( - sender.send("test", &data), - receiver.receive("test", &choices) - ); - - sender_res.unwrap(); - let received_data: Vec = receiver_res.unwrap(); - - let expected_data = choose(data, choices).collect::>(); - - assert_eq!(received_data, expected_data); - } - - #[rstest] - #[tokio::test] - async fn test_kos_actor_verifiable_receiver(data: Vec<[Block; 2]>, choices: Vec) { - let (mut sender_actor, mut receiver_actor) = setup( - SenderConfig::builder().sender_commit().build().unwrap(), - ReceiverConfig::builder().sender_commit().build().unwrap(), - data.len(), - ) - .await; - - let sender = sender_actor.sender(); - let receiver = receiver_actor.receiver(); - - let sender_task = tokio::spawn(async move { - sender_actor.run().await.unwrap(); - sender_actor - }); - - tokio::spawn(async move { - receiver_actor.run().await.unwrap(); - receiver_actor - }); - - let (sender_res, receiver_res) = tokio::join!( - sender.send("test", &data), - receiver.receive("test", &choices) - ); - - sender_res.unwrap(); - - let received_data: Vec = receiver_res.unwrap(); - - let expected_data = choose(data.clone(), choices).collect::>(); - - assert_eq!(received_data, expected_data); - - sender.shutdown().await.unwrap(); - - let mut sender_actor = sender_task.await.unwrap(); - - sender_actor.reveal().await.unwrap(); - - receiver.verify("test", &data).await.unwrap(); - } -} diff --git a/ot/mpz-ot/src/actor/kos/msgs.rs b/ot/mpz-ot/src/actor/kos/msgs.rs deleted file mode 100644 index b87c52ad..00000000 --- a/ot/mpz-ot/src/actor/kos/msgs.rs +++ /dev/null @@ -1,57 +0,0 @@ -//! Message types for the KOS actors. - -use enum_try_as_inner::EnumTryAsInner; -use serde::{Deserialize, Serialize}; - -use mpz_ot_core::{ - kos::msgs::{Message as KosMessage, SenderPayload}, - msgs::Derandomize, -}; - -/// KOS actor message -#[derive(Debug, Clone, EnumTryAsInner, Serialize, Deserialize)] -#[derive_err(Debug)] -#[allow(missing_docs)] -pub enum Message { - ActorMessage(ActorMessage), - Protocol(KosMessage), -} - -impl From> for std::io::Error { - fn from(err: MessageError) -> Self { - std::io::Error::new(std::io::ErrorKind::InvalidData, err.to_string()) - } -} - -impl From for Message { - fn from(value: ActorMessage) -> Self { - Message::ActorMessage(value) - } -} - -/// KOS actor message -#[derive(Debug, Clone, EnumTryAsInner, Serialize, Deserialize)] -#[allow(missing_docs)] -pub enum ActorMessage { - TransferRequest(TransferRequest), - TransferPayload(TransferPayload), - Reveal, -} - -/// A message indicating that a transfer with the provided id is expected. -#[derive(Debug, Clone, Serialize, Deserialize)] -pub struct TransferRequest { - /// The id of the transfer. - pub id: String, - /// Beaver-derandomization. - pub derandomize: Derandomize, -} - -/// A message containing a payload for a transfer with the provided id. -#[derive(Debug, Clone, Serialize, Deserialize)] -pub struct TransferPayload { - /// The id of the transfer. - pub id: String, - /// The payload. - pub payload: SenderPayload, -} diff --git a/ot/mpz-ot/src/actor/kos/receiver.rs b/ot/mpz-ot/src/actor/kos/receiver.rs deleted file mode 100644 index f735cde5..00000000 --- a/ot/mpz-ot/src/actor/kos/receiver.rs +++ /dev/null @@ -1,376 +0,0 @@ -use std::collections::{HashMap, VecDeque}; - -use async_trait::async_trait; -use futures::{ - channel::{mpsc, oneshot}, - stream::Fuse, - SinkExt, StreamExt, -}; -use utils_aio::{ - non_blocking_backend::{Backend, NonBlockingBackend}, - sink::IoSink, - stream::IoStream, -}; - -use crate::{ - kos::{Receiver, ReceiverError, ReceiverKeys}, - OTError, OTReceiverShared, OTSetup, VerifiableOTReceiverShared, VerifiableOTSender, -}; -use mpz_core::{Block, ProtocolMessage}; -use mpz_ot_core::kos::{msgs::SenderPayload, PayloadRecord}; - -use crate::actor::kos::{ - into_kos_sink, into_kos_stream, - msgs::{ActorMessage, Message, TransferPayload, TransferRequest}, - ReceiverActorError, -}; - -/// Commands that can be sent to a [`ReceiverActor`]. -enum Command { - Receive(Receive), - Verify(Verify), - Shutdown(Shutdown), -} - -struct Receive { - id: String, - choices: Vec, - /// Used to send back the Result to the caller of the Receive command. - caller_response: oneshot::Sender>, -} - -struct Verify { - id: String, - /// Used to send back the Result to the caller of the Verify command. - caller_response: oneshot::Sender>, -} - -struct Shutdown { - /// Used to send back the Result to the caller of the Shutdown command. - caller_response: oneshot::Sender>, -} - -/// A pending oblivious transfer which was requested by this KOS receiver but has not yet been -/// responded to by the KOS sender. -struct PendingTransfer { - keys: ReceiverKeys, - /// Used to send back the Result to the caller of the Receive command. - caller_response: oneshot::Sender>, -} - -opaque_debug::implement!(PendingTransfer); - -#[derive(Default)] -struct State { - /// All oblivious transfer ids seen so far. - ids: HashMap, - - pending_transfers: HashMap, - pending_verify: VecDeque, -} - -/// KOS receiver actor. -pub struct ReceiverActor { - /// A sink to send messages to the KOS sender actor. - sink: Si, - /// A stream to receive messages from the KOS sender actor. - stream: Fuse, - - receiver: Receiver, - - state: State, - - /// Used to send commands to this actor. - command_sender: mpsc::UnboundedSender, - /// Used to receive commands to this actor. - commands: mpsc::UnboundedReceiver, -} - -impl ReceiverActor -where - // TODO: Support non-verifiable base OT. - BaseOT: OTSetup + VerifiableOTSender + ProtocolMessage + Send, - Si: IoSink> + Send + Unpin, - St: IoStream> + Send + Unpin, -{ - /// Create a new receiver actor. - pub fn new(receiver: Receiver, sink: Si, stream: St) -> Self { - let (command_sender, commands) = mpsc::unbounded(); - - Self { - receiver, - sink, - stream: stream.fuse(), - state: Default::default(), - command_sender, - commands, - } - } - - /// Sets up the receiver with the given number of OTs. - pub async fn setup(&mut self, count: usize) -> Result<(), ReceiverActorError> { - let mut sink = into_kos_sink(&mut self.sink); - let mut stream = into_kos_stream(&mut self.stream); - - self.receiver.setup(&mut sink, &mut stream).await?; - self.receiver.extend(&mut sink, &mut stream, count).await?; - - Ok(()) - } - - /// Returns a `SharedReceiver` which implements `Clone`. - pub fn receiver(&self) -> SharedReceiver { - SharedReceiver { - sender: self.command_sender.clone(), - } - } - - /// Run the receiver actor. - pub async fn run(&mut self) -> Result<(), ReceiverActorError> { - loop { - futures::select! { - // Handle messages from the KOS sender actor. - msg = self.stream.select_next_some() => self.handle_msg(msg?).await?, - // Handle commands from controllers. - cmd = self.commands.select_next_some() => { - if let Command::Shutdown(Shutdown { caller_response }) = cmd { - _ = caller_response.send(Ok(())); - return Ok(()); - } - - self.handle_cmd(cmd).await? - }, - } - } - } - - /// Starts an oblivious transfer by sending a request to the peer. - async fn start_transfer( - &mut self, - id: &str, - choices: &[bool], - ) -> Result { - let mut keys = self - .receiver - .state_mut() - .try_as_extension_mut()? - .keys(choices.len())?; - - let derandomize = keys.derandomize(choices)?; - - self.sink - .send( - ActorMessage::TransferRequest(TransferRequest { - id: id.to_string(), - derandomize, - }) - .into(), - ) - .await?; - - Ok(keys) - } - - async fn start_verification(&mut self) -> Result<(), ReceiverError> { - self.receiver - .verify_delta( - &mut into_kos_sink(&mut self.sink), - &mut into_kos_stream(&mut self.stream), - ) - .await?; - - // Process backlog of pending verifications. - let backlog = std::mem::take(&mut self.state.pending_verify); - for verify in backlog { - self.handle_verify(verify) - } - - Ok(()) - } - - /// Handles the Verify command from a controller. - /// - /// Sends back the [`PayloadRecord`] which the controller must verify itself. - fn handle_verify(&mut self, verify: Verify) { - // If we're ready to start verifying, we do so, otherwise, we buffer - // the verification for later. - if self.receiver.state().is_verify() { - let Verify { - id, - caller_response, - } = verify; - - if let Some(id) = self.state.ids.get(&id) { - // Send payload record to the caller. - _ = caller_response.send( - self.receiver - .state_mut() - .try_as_verify_mut() - .map_err(ReceiverError::from) - .and_then(|receiver| { - receiver.remove_record(*id).map_err(ReceiverError::from) - }), - ); - } else { - _ = caller_response.send(Err(ReceiverError::Other(format!( - "transfer id not found: {id}" - )))); - } - } else { - self.state.pending_verify.push_back(verify) - } - } - - /// Handles commands received from a controller. - async fn handle_cmd(&mut self, cmd: Command) -> Result<(), ReceiverError> { - match cmd { - Command::Receive(Receive { - id, - choices, - caller_response, - }) => { - let keys = match self.start_transfer(&id, &choices).await { - Ok(keys) => keys, - Err(e) => { - _ = caller_response.send(Err(e)); - return Ok(()); - } - }; - - if self.state.ids.contains_key(&id) { - _ = caller_response.send(Err(ReceiverError::Other(format!( - "duplicate transfer id: {id}" - )))); - return Ok(()); - } - - self.state.ids.insert(id.clone(), keys.id()); - self.state.pending_transfers.insert( - id, - PendingTransfer { - keys, - caller_response, - }, - ); - } - Command::Verify(verify) => self.handle_verify(verify), - Command::Shutdown(_) => unreachable!("shutdown should be handled already"), - } - - Ok(()) - } - - /// Handles a message from the KOS sender actor. - async fn handle_msg(&mut self, msg: Message) -> Result<(), ReceiverActorError> { - let msg = msg.try_into_actor_message()?; - - match msg { - ActorMessage::TransferPayload(TransferPayload { id, payload }) => { - let PendingTransfer { - keys, - caller_response, - } = self - .state - .pending_transfers - .remove(&id) - .ok_or_else(|| ReceiverActorError::UnexpectedTransferId(id))?; - - _ = caller_response.send(Ok((keys, payload))); - } - ActorMessage::Reveal => { - self.start_verification().await?; - } - msg => { - return Err(std::io::Error::new( - std::io::ErrorKind::InvalidData, - format!("unexpected msg: {:?}", msg), - ))? - } - } - - Ok(()) - } -} - -/// KOS Shared Receiver controller. -#[derive(Debug, Clone)] -pub struct SharedReceiver { - /// Channel for sending commands to the receiver actor. - sender: mpsc::UnboundedSender, -} - -impl SharedReceiver { - /// Shuts down the receiver actor. - pub async fn shutdown(&self) -> Result<(), ReceiverActorError> { - let (sender, receiver) = oneshot::channel(); - - self.sender.unbounded_send(Command::Shutdown(Shutdown { - caller_response: sender, - }))?; - - receiver.await? - } -} - -#[async_trait] -impl OTReceiverShared for SharedReceiver { - async fn receive(&self, id: &str, choices: &[bool]) -> Result, OTError> { - let (sender, receiver) = oneshot::channel(); - - self.sender - .unbounded_send(Command::Receive(Receive { - id: id.to_string(), - choices: choices.to_vec(), - caller_response: sender, - })) - .map_err(ReceiverError::from)?; - - let (keys, payload) = receiver.await.map_err(ReceiverError::from)??; - - Backend::spawn(move || keys.decrypt_blocks(payload)) - .await - .map_err(OTError::from) - } -} - -#[async_trait] -impl OTReceiverShared for SharedReceiver { - async fn receive(&self, id: &str, choices: &[bool]) -> Result, OTError> { - let (sender, receiver) = oneshot::channel(); - - self.sender - .unbounded_send(Command::Receive(Receive { - id: id.to_string(), - choices: choices.to_vec(), - caller_response: sender, - })) - .map_err(ReceiverError::from)?; - - let (keys, payload) = receiver.await.map_err(ReceiverError::from)??; - - Backend::spawn(move || keys.decrypt_bytes(payload)) - .await - .map_err(OTError::from) - } -} - -#[async_trait] -impl VerifiableOTReceiverShared for SharedReceiver { - async fn verify(&self, id: &str, msgs: &[[Block; 2]]) -> Result<(), OTError> { - let (sender, receiver) = oneshot::channel(); - - self.sender - .unbounded_send(Command::Verify(Verify { - id: id.to_string(), - caller_response: sender, - })) - .map_err(ReceiverError::from)?; - - let record = receiver.await.map_err(ReceiverError::from)??; - - let msgs = msgs.to_vec(); - Backend::spawn(move || record.verify(&msgs)) - .await - .map_err(OTError::from) - } -} diff --git a/ot/mpz-ot/src/actor/kos/sender.rs b/ot/mpz-ot/src/actor/kos/sender.rs deleted file mode 100644 index caeb8718..00000000 --- a/ot/mpz-ot/src/actor/kos/sender.rs +++ /dev/null @@ -1,340 +0,0 @@ -use std::collections::HashMap; - -use async_trait::async_trait; -use futures::channel::{mpsc, oneshot}; -use futures_util::{stream::Fuse, SinkExt, StreamExt}; -use mpz_core::{Block, ProtocolMessage}; -use mpz_ot_core::kos::msgs::SenderPayload; -use utils_aio::{ - non_blocking_backend::{Backend, NonBlockingBackend}, - sink::IoSink, - stream::IoStream, -}; - -use crate::{ - actor::kos::{ - into_kos_sink, into_kos_stream, - msgs::{ActorMessage, Message, TransferPayload, TransferRequest}, - }, - kos::{Sender, SenderError, SenderKeys}, - CommittedOTReceiver, CommittedOTSenderShared, OTError, OTReceiver, OTSenderShared, OTSetup, -}; - -use super::SenderActorError; - -/// Commands that can be sent to a [`SenderActor`]. -enum Command { - GetKeys(GetKeys), - SendPayload(SendPayload), - Shutdown(Shutdown), -} - -struct GetKeys { - id: String, - /// Used to send back the Result to the caller of the GetKeys command. - caller_response: oneshot::Sender>, -} - -struct SendPayload { - id: String, - payload: SenderPayload, - /// Used to send back the Result to the caller of the SendPayload command. - caller_response: oneshot::Sender>, -} - -struct Shutdown { - /// Used to send back the Result to the caller of the Shutdown command. - caller_response: oneshot::Sender>, -} - -#[derive(Default)] -struct State { - pending_keys: HashMap>, - pending_callers: HashMap>>, -} - -opaque_debug::implement!(State); - -/// KOS sender actor. -pub struct SenderActor { - /// A sink to send messages to the KOS receiver actor. - sink: Si, - /// A stream to receive messages from the KOS receiver actor. - stream: Fuse, - - sender: Sender, - - state: State, - - /// Used to send commands to this actor. - command_sender: mpsc::UnboundedSender, - /// Used to receive commands to this actor. - commands: mpsc::UnboundedReceiver, -} - -impl SenderActor -where - BaseOT: OTSetup + OTReceiver + ProtocolMessage + Send, - Si: IoSink> + Send + Unpin, - St: IoStream> + Send + Unpin, -{ - /// Creates a new sender actor. - pub fn new(sender: Sender, sink: Si, stream: St) -> Self { - let (buffer_sender, buffer_receiver) = mpsc::unbounded(); - Self { - sink, - stream: stream.fuse(), - sender, - state: Default::default(), - command_sender: buffer_sender, - commands: buffer_receiver, - } - } - - /// Sets up the sender with the given number of OTs. - pub async fn setup(&mut self, count: usize) -> Result<(), SenderActorError> { - let mut sink = into_kos_sink(&mut self.sink); - let mut stream = into_kos_stream(&mut self.stream); - - self.sender.setup(&mut sink, &mut stream).await?; - self.sender.extend(&mut sink, &mut stream, count).await?; - - Ok(()) - } - - /// Sets up the sender with the given number of OTs. - pub async fn setup_with_delta( - &mut self, - delta: Block, - count: usize, - ) -> Result<(), SenderActorError> { - let mut sink = into_kos_sink(&mut self.sink); - let mut stream = into_kos_stream(&mut self.stream); - - self.sender - .setup_with_delta(&mut sink, &mut stream, delta) - .await?; - self.sender.extend(&mut sink, &mut stream, count).await?; - - Ok(()) - } - - /// Returns a `SharedSender` which implements `Clone`. - pub fn sender(&self) -> SharedSender { - SharedSender { - command_sender: self.command_sender.clone(), - } - } - - /// Runs the sender actor. - pub async fn run(&mut self) -> Result<(), SenderActorError> { - loop { - futures::select! { - // Processes a message received from the Receiver. - msg = self.stream.select_next_some() => { - self.handle_msg(msg?.try_into_actor_message()?)?; - } - // Processes a command from a controller. - cmd = self.commands.select_next_some() => { - if let Command::Shutdown(Shutdown { caller_response }) = cmd { - _ = caller_response.send(Ok(())); - return Ok(()); - } - - self.handle_cmd(cmd).await; - } - } - } - } - - /// Handles commands received from a controller. - async fn handle_cmd(&mut self, cmd: Command) { - match cmd { - Command::GetKeys(GetKeys { - id, - caller_response, - }) => { - if let Some(keys) = self.state.pending_keys.remove(&id) { - _ = caller_response.send(keys); - } else { - // The peer has not requested an OT with this id yet. - self.state.pending_callers.insert(id, caller_response); - } - } - Command::SendPayload(SendPayload { - id, - payload, - caller_response, - }) => { - let res = self - .sink - .send(ActorMessage::TransferPayload(TransferPayload { id, payload }).into()) - .await; - - _ = caller_response.send(res.map_err(SenderError::from)); - } - Command::Shutdown(_) => unreachable!("shutdown should be handled already"), - } - } - - /// Handles a message from the KOS receiver actor. - fn handle_msg(&mut self, msg: ActorMessage) -> Result<(), SenderActorError> { - match msg { - ActorMessage::TransferRequest(TransferRequest { id, derandomize }) => { - // Reserve the keys for the transfer. - let keys = self - .sender - .state_mut() - .try_as_extension_mut() - .map_err(SenderError::from) - .and_then(|sender| { - sender - .keys(derandomize.count as usize) - .map_err(SenderError::from) - }); - - // Derandomization is cheap, we just do it here. - let keys = keys - .and_then(|mut keys| { - keys.derandomize(derandomize)?; - Ok(keys) - }) - .map_err(SenderError::from); - - // If there is a pending caller, send the keys to it, otherwise - // we buffer it. - if let Some(pending_caller) = self.state.pending_callers.remove(&id) { - _ = pending_caller.send(keys); - } else { - self.state.pending_keys.insert(id, keys); - } - } - msg => { - return Err(std::io::Error::new( - std::io::ErrorKind::InvalidData, - format!("unexpected msg: {:?}", msg), - ))? - } - } - - Ok(()) - } -} - -impl SenderActor -where - BaseOT: CommittedOTReceiver + ProtocolMessage + Send, - Si: IoSink> + Send + Unpin, - St: IoStream> + Send + Unpin, -{ - /// Reveals all messages sent to the receiver. - /// - /// # Warning - /// - /// Obviously, you should be sure you want to do this before calling this function! - pub async fn reveal(&mut self) -> Result<(), SenderActorError> { - self.sink.send(ActorMessage::Reveal.into()).await?; - - self.sender - .reveal( - &mut into_kos_sink(&mut self.sink), - &mut into_kos_stream(&mut self.stream), - ) - .await - .map_err(SenderActorError::from) - } -} - -/// KOS Shared Sender controller -#[derive(Clone)] -pub struct SharedSender { - /// Channel for sending commands to the sender actor. - command_sender: mpsc::UnboundedSender, -} - -opaque_debug::implement!(SharedSender); - -impl SharedSender { - /// Shuts down the sender actor. - pub async fn shutdown(&self) -> Result<(), SenderActorError> { - let (caller_response, receiver) = oneshot::channel(); - self.command_sender - .unbounded_send(Command::Shutdown(Shutdown { caller_response }))?; - - receiver.await? - } -} - -#[async_trait] -impl OTSenderShared<[Block; 2]> for SharedSender { - async fn send(&self, id: &str, msgs: &[[Block; 2]]) -> Result<(), OTError> { - let (caller_response, receiver) = oneshot::channel(); - self.command_sender - .unbounded_send(Command::GetKeys(GetKeys { - id: id.to_string(), - caller_response, - })) - .map_err(SenderError::from)?; - - let keys = receiver.await.map_err(SenderError::from)??; - let msgs = msgs.to_vec(); - let payload = Backend::spawn(move || keys.encrypt_blocks(&msgs)).await?; - - let (caller_response, receiver) = oneshot::channel(); - self.command_sender - .unbounded_send(Command::SendPayload(SendPayload { - id: id.to_string(), - payload, - caller_response, - })) - .map_err(SenderError::from)?; - - receiver - .await - .map_err(SenderError::from)? - .map_err(OTError::from) - } -} - -#[async_trait] -impl OTSenderShared<[[u8; N]; 2]> for SharedSender { - async fn send(&self, id: &str, msgs: &[[[u8; N]; 2]]) -> Result<(), OTError> { - let (caller_response, receiver) = oneshot::channel(); - self.command_sender - .unbounded_send(Command::GetKeys(GetKeys { - id: id.to_string(), - caller_response, - })) - .map_err(SenderError::from)?; - - let keys = receiver.await.map_err(SenderError::from)??; - let msgs = msgs.to_vec(); - let payload = Backend::spawn(move || keys.encrypt_bytes(&msgs)).await?; - - let (caller_response, receiver) = oneshot::channel(); - self.command_sender - .unbounded_send(Command::SendPayload(SendPayload { - id: id.to_string(), - payload, - caller_response, - })) - .map_err(SenderError::from)?; - - receiver - .await - .map_err(SenderError::from)? - .map_err(OTError::from) - } -} - -#[async_trait] -impl CommittedOTSenderShared for SharedSender -where - SharedSender: OTSenderShared, -{ - async fn reveal(&self) -> Result<(), OTError> { - // this is no-op, as the reveal is performed using the actor struct after - // shutdown. - Ok(()) - } -} diff --git a/ot/mpz-ot/src/actor/mod.rs b/ot/mpz-ot/src/actor/mod.rs deleted file mode 100644 index c1d12409..00000000 --- a/ot/mpz-ot/src/actor/mod.rs +++ /dev/null @@ -1,4 +0,0 @@ -//! Actor implementations of oblivious transfer protocols. - -/// KOS actor implementations. -pub mod kos; diff --git a/ot/mpz-ot/src/chou_orlandi/error.rs b/ot/mpz-ot/src/chou_orlandi/error.rs index 7da75ea4..9bdde51e 100644 --- a/ot/mpz-ot/src/chou_orlandi/error.rs +++ b/ot/mpz-ot/src/chou_orlandi/error.rs @@ -1,5 +1,3 @@ -use mpz_ot_core::chou_orlandi::msgs::MessageError; - use crate::OTError; /// A Chou-Orlandi sender error. @@ -12,8 +10,8 @@ pub enum SenderError { CoreError(#[from] mpz_ot_core::chou_orlandi::SenderError), #[error("{0}")] StateError(String), - #[error(transparent)] - CointossError(#[from] mpz_core::cointoss::CointossError), + #[error("coin-toss error: {0}")] + CointossError(#[from] mpz_cointoss::CointossError), #[error("invalid configuration: {0}")] InvalidConfig(String), } @@ -33,15 +31,6 @@ impl From for SenderError { } } -impl From for SenderError { - fn from(err: MessageError) -> Self { - SenderError::from(std::io::Error::new( - std::io::ErrorKind::InvalidData, - err.to_string(), - )) - } -} - /// A Chou-Orlandi receiver error. #[derive(Debug, thiserror::Error)] #[allow(missing_docs)] @@ -52,8 +41,8 @@ pub enum ReceiverError { CoreError(#[from] mpz_ot_core::chou_orlandi::ReceiverError), #[error("{0}")] StateError(String), - #[error(transparent)] - CointossError(#[from] mpz_core::cointoss::CointossError), + #[error("coin-toss error: {0}")] + CointossError(#[from] mpz_cointoss::CointossError), #[error("invalid configuration: {0}")] InvalidConfig(String), } @@ -72,12 +61,3 @@ impl From for ReceiverError { ReceiverError::StateError(err.to_string()) } } - -impl From for ReceiverError { - fn from(err: MessageError) -> Self { - ReceiverError::from(std::io::Error::new( - std::io::ErrorKind::InvalidData, - err.to_string(), - )) - } -} diff --git a/ot/mpz-ot/src/chou_orlandi/mod.rs b/ot/mpz-ot/src/chou_orlandi/mod.rs index fdd91fab..6b58edbb 100644 --- a/ot/mpz-ot/src/chou_orlandi/mod.rs +++ b/ot/mpz-ot/src/chou_orlandi/mod.rs @@ -3,106 +3,36 @@ //! # Examples //! //! ``` -//! use utils_aio::duplex::MemoryDuplex; -//! use mpz_ot::chou_orlandi::{Receiver, Sender, SenderConfig, ReceiverConfig}; -//! use mpz_ot::{OTReceiver, OTSender, OTSetup}; +//! use mpz_common::executor::test_st_executor; +//! use mpz_ot::{ +//! chou_orlandi::{Receiver, Sender, SenderConfig, ReceiverConfig}, +//! OTReceiver, OTSender, OTSetup +//! }; //! use mpz_core::Block; -//! use futures::StreamExt; //! //! # futures::executor::block_on(async { -//! // An in-memory duplex channel. -//! let (sender_channel, receiver_channel) = MemoryDuplex::new(); +//! let (mut ctx_sender, mut ctx_receiver) = test_st_executor(8); //! -//! let (mut sender_sink, mut sender_stream) = sender_channel.split(); -//! let (mut receiver_sink, mut receiver_stream) = receiver_channel.split(); -//! -//! let mut sender = Sender::new(SenderConfig::default()); -//! let mut receiver = Receiver::new(ReceiverConfig::default()); +//! let mut sender = Sender::default(); +//! let mut receiver = Receiver::default(); //! //! // Perform the setup phase. -//! let (sender_res, receiver_res) = futures::join!( -//! sender.setup(&mut sender_sink, &mut sender_stream), -//! receiver.setup(&mut receiver_sink, &mut receiver_stream) -//! ); -//! -//! sender_res.unwrap(); -//! receiver_res.unwrap(); +//! let (sender_res, receiver_res) = futures::try_join!( +//! sender.setup(&mut ctx_sender), +//! receiver.setup(&mut ctx_receiver) +//! ).unwrap(); //! //! // Perform the transfer phase. //! let messages = vec![[Block::ZERO, Block::ONES], [Block::ZERO, Block::ONES]]; //! -//! let (sender_res, receiver_res) = futures::join!( -//! sender.send(&mut sender_sink, &mut sender_stream, &messages), -//! receiver.receive(&mut receiver_sink, &mut receiver_stream, &[true, false]) -//! ); -//! -//! sender_res.unwrap(); -//! -//! let received = receiver_res.unwrap(); +//! let (_, received) = futures::try_join!( +//! sender.send(&mut ctx_sender, &messages), +//! receiver.receive(&mut ctx_receiver, &[true, false]) +//! ).unwrap(); //! //! assert_eq!(received, vec![Block::ONES, Block::ZERO]); //! # }); //! ``` -//! -//! # Committed Receiver -//! -//! This implementation also provides support for a committed receiver. This is a receiver that commits to their choice -//! bits, and can later provably reveal them to the sender. -//! -//! ## Example -//! -//! ``` -//! use utils_aio::duplex::MemoryDuplex; -//! use mpz_ot::chou_orlandi::{Receiver, Sender, SenderConfig, ReceiverConfig}; -//! use mpz_ot::{OTReceiver, OTSender, CommittedOTReceiver, VerifiableOTSender, OTSetup}; -//! use mpz_core::Block; -//! use futures::StreamExt; -//! -//! # futures::executor::block_on(async { -//! // An in-memory duplex channel. -//! let (sender_channel, receiver_channel) = MemoryDuplex::new(); -//! -//! let (mut sender_sink, mut sender_stream) = sender_channel.split(); -//! let (mut receiver_sink, mut receiver_stream) = receiver_channel.split(); -//! -//! // Enable committed receiver in config. -//! let mut sender = Sender::new(SenderConfig::builder().receiver_commit().build().unwrap()); -//! let mut receiver = Receiver::new(ReceiverConfig::builder().receiver_commit().build().unwrap()); -//! -//! // Perform the setup phase. -//! let (sender_res, receiver_res) = futures::join!( -//! sender.setup(&mut sender_sink, &mut sender_stream), -//! receiver.setup(&mut receiver_sink, &mut receiver_stream) -//! ); -//! -//! sender_res.unwrap(); -//! receiver_res.unwrap(); -//! -//! // Perform the transfer phase. -//! let messages = vec![[Block::ZERO, Block::ONES], [Block::ZERO, Block::ONES]]; -//! -//! let (sender_res, receiver_res) = futures::join!( -//! sender.send(&mut sender_sink, &mut sender_stream, &messages), -//! receiver.receive(&mut receiver_sink, &mut receiver_stream, &[true, false]) -//! ); -//! -//! sender_res.unwrap(); -//! _ = receiver_res.unwrap(); -//! -//! // Reveal the choice bits. -//! let (sender_res, receiver_res) = futures::join!( -//! sender.verify_choices(&mut sender_sink, &mut sender_stream), -//! receiver.reveal_choices(&mut receiver_sink, &mut receiver_stream) -//! ); -//! -//! receiver_res.unwrap(); -//! -//! // The verified choice bits are returned to the sender. -//! let choices = sender_res.unwrap(); -//! -//! assert_eq!(choices, vec![true, false]); -//! # }); -//! ``` mod error; mod receiver; @@ -119,14 +49,13 @@ pub use mpz_ot_core::chou_orlandi::{ #[cfg(test)] mod tests { - use futures_util::StreamExt; use itybity::ToBits; + use mpz_common::executor::test_st_executor; + use mpz_common::Context; use mpz_core::Block; - use mpz_ot_core::chou_orlandi::msgs::Message; use rand::Rng; use rand_chacha::ChaCha12Rng; use rand_core::SeedableRng; - use utils_aio::{duplex::MemoryDuplex, sink::IoSink, stream::IoStream}; use crate::{CommittedOTReceiver, OTReceiver, OTSender, OTSetup, VerifiableOTSender}; @@ -155,24 +84,16 @@ mod tests { .map(|([zero, one], choice)| if choice { one } else { zero }) } - async fn setup + Send + Unpin, St: IoStream + Send + Unpin>( + async fn setup( sender_config: SenderConfig, receiver_config: ReceiverConfig, - sender_sink: &mut Si, - sender_stream: &mut St, - receiver_sink: &mut Si, - receiver_stream: &mut St, + sender_ctx: &mut impl Context, + receiver_ctx: &mut impl Context, ) -> (Sender, Receiver) { let mut sender = Sender::new(sender_config); let mut receiver = Receiver::new(receiver_config); - let (sender_res, receiver_res) = tokio::join!( - sender.setup(sender_sink, sender_stream), - receiver.setup(receiver_sink, receiver_stream) - ); - - sender_res.unwrap(); - receiver_res.unwrap(); + tokio::try_join!(sender.setup(sender_ctx), receiver.setup(receiver_ctx)).unwrap(); (sender, receiver) } @@ -180,24 +101,18 @@ mod tests { #[rstest] #[tokio::test] async fn test_chou_orlandi(data: Vec<[Block; 2]>, choices: Vec) { - let (sender_channel, receiver_channel) = MemoryDuplex::new(); - - let (mut sender_sink, mut sender_stream) = sender_channel.split(); - let (mut receiver_sink, mut receiver_stream) = receiver_channel.split(); - + let (mut sender_ctx, mut receiver_ctx) = test_st_executor(8); let (mut sender, mut receiver) = setup( SenderConfig::default(), ReceiverConfig::default(), - &mut sender_sink, - &mut sender_stream, - &mut receiver_sink, - &mut receiver_stream, + &mut sender_ctx, + &mut receiver_ctx, ) .await; let (sender_res, receiver_res) = tokio::join!( - sender.send(&mut sender_sink, &mut sender_stream, &data), - receiver.receive(&mut receiver_sink, &mut receiver_stream, &choices) + sender.send(&mut sender_ctx, &data), + receiver.receive(&mut receiver_ctx, &choices) ); sender_res.unwrap(); @@ -211,36 +126,26 @@ mod tests { #[rstest] #[tokio::test] async fn test_chou_orlandi_committed_receiver(data: Vec<[Block; 2]>, choices: Vec) { - let (sender_channel, receiver_channel) = MemoryDuplex::new(); - - let (mut sender_sink, mut sender_stream) = sender_channel.split(); - let (mut receiver_sink, mut receiver_stream) = receiver_channel.split(); - + let (mut sender_ctx, mut receiver_ctx) = test_st_executor(8); let (mut sender, mut receiver) = setup( SenderConfig::builder().receiver_commit().build().unwrap(), ReceiverConfig::builder().receiver_commit().build().unwrap(), - &mut sender_sink, - &mut sender_stream, - &mut receiver_sink, - &mut receiver_stream, + &mut sender_ctx, + &mut receiver_ctx, ) .await; - let (sender_res, receiver_res) = tokio::join!( - sender.send(&mut sender_sink, &mut sender_stream, &data), - receiver.receive(&mut receiver_sink, &mut receiver_stream, &choices) - ); - - sender_res.unwrap(); - _ = receiver_res.unwrap(); - - let (sender_res, receiver_res) = tokio::join!( - sender.verify_choices(&mut sender_sink, &mut sender_stream), - receiver.reveal_choices(&mut receiver_sink, &mut receiver_stream) - ); + tokio::try_join!( + sender.send(&mut sender_ctx, &data), + receiver.receive(&mut receiver_ctx, &choices) + ) + .unwrap(); - let verified_choices = sender_res.unwrap(); - receiver_res.unwrap(); + let (verified_choices, _) = tokio::try_join!( + sender.verify_choices(&mut sender_ctx), + receiver.reveal_choices(&mut receiver_ctx) + ) + .unwrap(); assert_eq!(verified_choices, choices); } diff --git a/ot/mpz-ot/src/chou_orlandi/receiver.rs b/ot/mpz-ot/src/chou_orlandi/receiver.rs index 227bed3b..58e499df 100644 --- a/ot/mpz-ot/src/chou_orlandi/receiver.rs +++ b/ot/mpz-ot/src/chou_orlandi/receiver.rs @@ -1,19 +1,17 @@ use async_trait::async_trait; -use futures::SinkExt; use itybity::BitIterable; -use mpz_core::{cointoss, Block, ProtocolMessage}; +use mpz_cointoss as cointoss; +use mpz_common::Context; +use mpz_core::Block; use mpz_ot_core::chou_orlandi::{ - msgs::Message, receiver_state as state, Receiver as ReceiverCore, ReceiverConfig, + receiver_state as state, Receiver as ReceiverCore, ReceiverConfig, }; use enum_try_as_inner::EnumTryAsInner; use rand::{thread_rng, Rng}; -use utils_aio::{ - non_blocking_backend::{Backend, NonBlockingBackend}, - sink::IoSink, - stream::{ExpectStreamExt, IoStream}, -}; +use serio::{stream::IoStreamExt as _, SinkExt as _}; +use utils_aio::non_blocking_backend::{Backend, NonBlockingBackend}; use crate::{CommittedOTReceiver, OTError, OTReceiver, OTSetup}; @@ -35,7 +33,19 @@ pub(crate) enum State { #[derive(Debug)] pub struct Receiver { state: State, - cointoss_payload: Option, + cointoss_sender: Option>, +} + +impl Default for Receiver { + fn default() -> Self { + Self { + state: State::Initialized { + config: ReceiverConfig::default(), + seed: None, + }, + cointoss_sender: None, + } + } } impl Receiver { @@ -47,7 +57,7 @@ impl Receiver { pub fn new(config: ReceiverConfig) -> Self { Self { state: State::Initialized { config, seed: None }, - cointoss_payload: None, + cointoss_sender: None, } } @@ -63,18 +73,14 @@ impl Receiver { config, seed: Some(seed), }, - cointoss_payload: None, + cointoss_sender: None, } } } #[async_trait] -impl OTSetup for Receiver { - async fn setup + Send + Unpin, St: IoStream + Send + Unpin>( - &mut self, - sink: &mut Si, - stream: &mut St, - ) -> Result<(), OTError> { +impl OTSetup for Receiver { + async fn setup(&mut self, ctx: &mut Ctx) -> Result<(), OTError> { if self.state.is_setup() { return Ok(()); } @@ -84,29 +90,39 @@ impl OTSetup for Receiver { .map_err(ReceiverError::from)?; // If the receiver is committed, we generate the seed using a cointoss. - let receiver = if config.receiver_commit() { + let seed = if config.receiver_commit() { if seed.is_some() { return Err(ReceiverError::InvalidConfig( "committed receiver seed must be generated using coin toss".to_string(), ))?; } - let (seed, cointoss_payload) = execute_cointoss(sink, stream).await?; + let cointoss_seed = thread_rng().gen(); + let (seeds, cointoss_sender) = cointoss::Sender::new(vec![cointoss_seed]) + .commit(ctx) + .await + .map_err(ReceiverError::from)? + .receive(ctx) + .await + .map_err(ReceiverError::from)?; + + self.cointoss_sender = Some(cointoss_sender); - self.cointoss_payload = Some(cointoss_payload); + let seed = seeds[0].to_bytes(); + // Stretch seed to 32 bytes + let mut stretched_seed = [0u8; 32]; + stretched_seed[..16].copy_from_slice(&seed); + stretched_seed[16..].copy_from_slice(&seed); - ReceiverCore::new_with_seed(config, seed) + stretched_seed } else { - ReceiverCore::new_with_seed(config, seed.unwrap_or_else(|| thread_rng().gen())) + seed.unwrap_or_else(|| thread_rng().gen()) }; - let sender_setup = stream - .expect_next() - .await? - .try_into_sender_setup() - .map_err(ReceiverError::from)?; - - let receiver = Backend::spawn(move || receiver.setup(sender_setup)).await; + let sender_setup = ctx.io_mut().expect_next().await?; + let receiver = + Backend::spawn(move || ReceiverCore::new_with_seed(config, seed).setup(sender_setup)) + .await; self.state = State::Setup(Box::new(receiver)); @@ -114,52 +130,13 @@ impl OTSetup for Receiver { } } -/// Executes the coin toss protocol as the sender up until the point when we should send -/// a decommitment. The decommitment will be sent later during verification. -async fn execute_cointoss< - Si: IoSink + Send + Unpin, - St: IoStream + Send + Unpin, ->( - sink: &mut Si, - stream: &mut St, -) -> Result<([u8; 32], cointoss::msgs::SenderPayload), ReceiverError> { - let (sender, commitment) = cointoss::Sender::new(vec![thread_rng().gen()]).send(); - - sink.send(Message::CointossSenderCommitment(commitment)) - .await?; - - let payload = stream - .expect_next() - .await? - .try_into_cointoss_receiver_payload()?; - - let (seeds, payload) = sender.finalize(payload)?; - - let mut seed = [0u8; 32]; - seed[..16].copy_from_slice(&seeds[0].to_bytes()); - seed[16..].copy_from_slice(&seeds[0].to_bytes()); - - Ok((seed, payload)) -} - -impl ProtocolMessage for Receiver { - type Msg = Message; -} - #[async_trait] -impl OTReceiver for Receiver +impl OTReceiver for Receiver where + Ctx: Context, T: BitIterable + Send + Sync + Clone + 'static, { - async fn receive< - Si: IoSink + Send + Unpin, - St: IoStream + Send + Unpin, - >( - &mut self, - sink: &mut Si, - stream: &mut St, - choices: &[T], - ) -> Result, OTError> { + async fn receive(&mut self, ctx: &mut Ctx, choices: &[T]) -> Result, OTError> { let mut receiver = std::mem::replace(&mut self.state, State::Error) .try_into_setup() .map_err(ReceiverError::from)?; @@ -171,22 +148,17 @@ where }) .await; - sink.send(Message::ReceiverPayload(receiver_payload)) - .await?; + ctx.io_mut().send(receiver_payload).await?; - let sender_payload = stream - .expect_next() - .await? - .try_into_sender_payload() - .map_err(ReceiverError::from)?; + let sender_payload = ctx.io_mut().expect_next().await?; let (receiver, data) = Backend::spawn(move || { - let data = receiver.receive(sender_payload); - (receiver, data) + receiver + .receive(sender_payload) + .map(|data| (receiver, data)) }) - .await; - - let data = data.map_err(ReceiverError::from)?; + .await + .map_err(ReceiverError::from)?; self.state = State::Setup(receiver); @@ -195,32 +167,26 @@ where } #[async_trait] -impl CommittedOTReceiver for Receiver { - async fn reveal_choices< - Si: IoSink + Send + Unpin, - St: IoStream + Send + Unpin, - >( - &mut self, - sink: &mut Si, - _stream: &mut St, - ) -> Result<(), OTError> { +impl CommittedOTReceiver for Receiver { + async fn reveal_choices(&mut self, ctx: &mut Ctx) -> Result<(), OTError> { let receiver = std::mem::replace(&mut self.state, State::Error) .try_into_setup() .map_err(ReceiverError::from)?; - let Some(cointoss_payload) = self.cointoss_payload.take() else { + let Some(cointoss_sender) = self.cointoss_sender.take() else { return Err(ReceiverError::InvalidConfig( "receiver not configured to commit".to_string(), ) .into()); }; - let reveal = receiver.reveal_choices().map_err(ReceiverError::from)?; + cointoss_sender + .finalize(ctx) + .await + .map_err(ReceiverError::from)?; - sink.feed(Message::CointossSenderPayload(cointoss_payload)) - .await?; - sink.feed(Message::ReceiverReveal(reveal)).await?; - sink.flush().await?; + let reveal = receiver.reveal_choices().map_err(ReceiverError::from)?; + ctx.io_mut().send(reveal).await?; self.state = State::Complete; diff --git a/ot/mpz-ot/src/chou_orlandi/sender.rs b/ot/mpz-ot/src/chou_orlandi/sender.rs index e758e4d8..7ba6121d 100644 --- a/ot/mpz-ot/src/chou_orlandi/sender.rs +++ b/ot/mpz-ot/src/chou_orlandi/sender.rs @@ -1,17 +1,13 @@ use crate::{chou_orlandi::SenderError, OTError, OTSender, OTSetup, VerifiableOTSender}; use async_trait::async_trait; -use futures_util::SinkExt; -use mpz_core::{cointoss, Block, ProtocolMessage}; -use mpz_ot_core::chou_orlandi::{ - msgs::Message, sender_state as state, Sender as SenderCore, SenderConfig, -}; +use mpz_cointoss as cointoss; +use mpz_common::Context; +use mpz_core::Block; +use mpz_ot_core::chou_orlandi::{sender_state as state, Sender as SenderCore, SenderConfig}; use rand::{thread_rng, Rng}; -use utils_aio::{ - non_blocking_backend::{Backend, NonBlockingBackend}, - sink::IoSink, - stream::{ExpectStreamExt, IoStream}, -}; +use serio::{stream::IoStreamExt, SinkExt as _}; +use utils_aio::non_blocking_backend::{Backend, NonBlockingBackend}; use enum_try_as_inner::EnumTryAsInner; @@ -33,6 +29,15 @@ pub struct Sender { cointoss_receiver: Option>, } +impl Default for Sender { + fn default() -> Self { + Self { + state: State::Initialized(SenderCore::new(SenderConfig::default())), + cointoss_receiver: None, + } + } +} + impl Sender { /// Creates a new Sender /// @@ -61,12 +66,8 @@ impl Sender { } #[async_trait] -impl OTSetup for Sender { - async fn setup + Send + Unpin, St: IoStream + Send + Unpin>( - &mut self, - sink: &mut Si, - stream: &mut St, - ) -> Result<(), OTError> { +impl OTSetup for Sender { + async fn setup(&mut self, ctx: &mut Ctx) -> Result<(), OTError> { if self.state.is_setup() { return Ok(()); } @@ -77,12 +78,18 @@ impl OTSetup for Sender { // If the receiver is committed, we run the cointoss protocol if sender.config().receiver_commit() { - self.cointoss_receiver = Some(execute_cointoss(sink, stream).await?); + let cointoss_seed = thread_rng().gen(); + self.cointoss_receiver = Some( + cointoss::Receiver::new(vec![cointoss_seed]) + .receive(ctx) + .await + .map_err(SenderError::from)?, + ); } let (msg, sender) = sender.setup(); - sink.send(Message::SenderSetup(msg)).await?; + ctx.io_mut().send(msg).await?; self.state = State::Setup(sender); @@ -90,61 +97,25 @@ impl OTSetup for Sender { } } -/// Executes the coin toss protocol as the receiver up until the point when the sender should send -/// a decommitment. The decommitment will be sent later during verification. -async fn execute_cointoss< - Si: IoSink + Send + Unpin, - St: IoStream + Send + Unpin, ->( - sink: &mut Si, - stream: &mut St, -) -> Result, SenderError> { - let receiver = cointoss::Receiver::new(vec![thread_rng().gen()]); - - let commitment = stream - .expect_next() - .await? - .try_into_cointoss_sender_commitment()?; - - let (receiver, payload) = receiver.reveal(commitment)?; - - sink.send(Message::CointossReceiverPayload(payload)).await?; - - Ok(receiver) -} - -impl ProtocolMessage for Sender { - type Msg = Message; -} - #[async_trait] -impl OTSender<[Block; 2]> for Sender { - async fn send + Send + Unpin, St: IoStream + Send + Unpin>( - &mut self, - sink: &mut Si, - stream: &mut St, - input: &[[Block; 2]], - ) -> Result<(), OTError> { +impl OTSender for Sender { + async fn send(&mut self, ctx: &mut Ctx, input: &[[Block; 2]]) -> Result<(), OTError> { let mut sender = std::mem::replace(&mut self.state, State::Error) .try_into_setup() .map_err(SenderError::from)?; - let receiver_payload = stream - .expect_next() - .await? - .try_into_receiver_payload() - .map_err(SenderError::from)?; + let receiver_payload = ctx.io_mut().expect_next().await?; let input = input.to_vec(); let (sender, payload) = Backend::spawn(move || { - let payload = sender.send(&input, receiver_payload); - (sender, payload) + sender + .send(&input, receiver_payload) + .map(|payload| (sender, payload)) }) - .await; - - let payload = payload.map_err(SenderError::from)?; + .await + .map_err(SenderError::from)?; - sink.send(Message::SenderPayload(payload)).await?; + ctx.io_mut().send(payload).await?; self.state = State::Setup(sender); @@ -153,15 +124,8 @@ impl OTSender<[Block; 2]> for Sender { } #[async_trait] -impl VerifiableOTSender for Sender { - async fn verify_choices< - Si: IoSink + Send + Unpin, - St: IoStream + Send + Unpin, - >( - &mut self, - _sink: &mut Si, - stream: &mut St, - ) -> Result, OTError> { +impl VerifiableOTSender for Sender { + async fn verify_choices(&mut self, ctx: &mut Ctx) -> Result, OTError> { let sender = std::mem::replace(&mut self.state, State::Error) .try_into_setup() .map_err(SenderError::from)?; @@ -172,27 +136,20 @@ impl VerifiableOTSender for Sender { ))? }; - let cointoss_payload = stream - .expect_next() - .await? - .try_into_cointoss_sender_payload() - .map_err(SenderError::from)?; - - let receiver_reveal = stream - .expect_next() - .await? - .try_into_receiver_reveal() + let seed = cointoss_receiver + .finalize(ctx) + .await .map_err(SenderError::from)?; - let cointoss_seed = cointoss_receiver - .finalize(cointoss_payload) - .map_err(SenderError::from)?[0]; - let mut receiver_seed = [0u8; 32]; - receiver_seed[..16].copy_from_slice(&cointoss_seed.to_bytes()); - receiver_seed[16..].copy_from_slice(&cointoss_seed.to_bytes()); + let seed = seed[0].to_bytes(); + // Stretch seed to 32 bytes + let mut stretched_seed = [0u8; 32]; + stretched_seed[..16].copy_from_slice(&seed); + stretched_seed[16..].copy_from_slice(&seed); + let receiver_reveal = ctx.io_mut().expect_next().await?; let verified_choices = - Backend::spawn(move || sender.verify_choices(receiver_seed, receiver_reveal)) + Backend::spawn(move || sender.verify_choices(stretched_seed, receiver_reveal)) .await .map_err(SenderError::from)?; diff --git a/ot/mpz-ot/src/ideal/owned/cot.rs b/ot/mpz-ot/src/ideal/cot.rs similarity index 62% rename from ot/mpz-ot/src/ideal/owned/cot.rs rename to ot/mpz-ot/src/ideal/cot.rs index b4634132..988066a1 100644 --- a/ot/mpz-ot/src/ideal/owned/cot.rs +++ b/ot/mpz-ot/src/ideal/cot.rs @@ -1,8 +1,10 @@ +//! Ideal functionality for correlated oblivious transfer. + use crate::{COTReceiver, COTSender, OTError, OTSetup}; use async_trait::async_trait; use futures::{channel::mpsc, StreamExt}; -use mpz_core::{Block, ProtocolMessage}; -use utils_aio::{sink::IoSink, stream::IoStream}; +use mpz_common::Context; +use mpz_core::Block; /// Ideal OT sender. #[derive(Debug)] @@ -17,14 +19,6 @@ pub struct IdealCOTReceiver { receiver: mpsc::Receiver>, } -impl ProtocolMessage for IdealCOTSender { - type Msg = (); -} - -impl ProtocolMessage for IdealCOTReceiver { - type Msg = (); -} - /// Creates a pair of ideal COT sender and receiver. pub fn ideal_cot_pair( delta: Block, @@ -38,27 +32,19 @@ pub fn ideal_cot_pair( } #[async_trait] -impl OTSetup for IdealCOTSender +impl OTSetup for IdealCOTSender where + Ctx: Context, T: Send + Sync, { - async fn setup + Send + Unpin, St: IoStream<()> + Send + Unpin>( - &mut self, - _sink: &mut Si, - _stream: &mut St, - ) -> Result<(), OTError> { + async fn setup(&mut self, _ctx: &mut Ctx) -> Result<(), OTError> { Ok(()) } } #[async_trait] -impl COTSender for IdealCOTSender { - async fn send_correlated + Send + Unpin, St: IoStream<()> + Send + Unpin>( - &mut self, - _sink: &mut Si, - _stream: &mut St, - msgs: &[Block], - ) -> Result<(), OTError> { +impl COTSender for IdealCOTSender { + async fn send_correlated(&mut self, _ctx: &mut Ctx, msgs: &[Block]) -> Result<(), OTError> { self.sender .try_send( msgs.iter() @@ -72,25 +58,21 @@ impl COTSender for IdealCOTSender { } #[async_trait] -impl OTSetup for IdealCOTReceiver +impl OTSetup for IdealCOTReceiver where + Ctx: Context, T: Send + Sync, { - async fn setup + Send + Unpin, St: IoStream<()> + Send + Unpin>( - &mut self, - _sink: &mut Si, - _stream: &mut St, - ) -> Result<(), OTError> { + async fn setup(&mut self, _ctx: &mut Ctx) -> Result<(), OTError> { Ok(()) } } #[async_trait] -impl COTReceiver for IdealCOTReceiver { - async fn receive_correlated + Send + Unpin, St: IoStream<()> + Send + Unpin>( +impl COTReceiver for IdealCOTReceiver { + async fn receive_correlated( &mut self, - _sink: &mut Si, - _stream: &mut St, + _ctx: &mut Ctx, choices: &[bool], ) -> Result, OTError> { let payload = self @@ -117,10 +99,10 @@ impl COTReceiver for IdealCOTReceiver { #[cfg(test)] mod tests { use itybity::IntoBits; + use mpz_common::executor::test_st_executor; use rand::Rng; use rand_chacha::ChaCha12Rng; use rand_core::SeedableRng; - use utils_aio::duplex::MemoryDuplex; use super::*; @@ -128,10 +110,7 @@ mod tests { #[tokio::test] async fn test_ideal_cot_owned() { let mut rng = ChaCha12Rng::seed_from_u64(0); - let (send_channel, recv_channel) = MemoryDuplex::<()>::new(); - - let (mut send_sink, mut send_stream) = send_channel.split(); - let (mut recv_sink, mut recv_stream) = recv_channel.split(); + let (mut ctx_sender, mut ctx_receiver) = test_st_executor(8); let values = Block::random_vec(&mut rng, 8); let choices = rng.gen::().into_lsb0_vec(); @@ -139,12 +118,12 @@ mod tests { let (mut sender, mut receiver) = ideal_cot_pair::(delta); sender - .send_correlated(&mut send_sink, &mut send_stream, &values) + .send_correlated(&mut ctx_sender, &values) .await .unwrap(); let received = receiver - .receive_correlated(&mut recv_sink, &mut recv_stream, &choices) + .receive_correlated(&mut ctx_receiver, &choices) .await .unwrap(); diff --git a/ot/mpz-ot/src/ideal/mod.rs b/ot/mpz-ot/src/ideal/mod.rs index 7f9fe564..a06697a9 100644 --- a/ot/mpz-ot/src/ideal/mod.rs +++ b/ot/mpz-ot/src/ideal/mod.rs @@ -1,16 +1,6 @@ //! Ideal implementations of the OT protocols. -mod owned; -mod shared; - -pub use owned::{ - ideal_cot_pair, ideal_ot_pair, ideal_random_cot_pair, ideal_random_ot_pair, IdealCOTReceiver, - IdealCOTSender, IdealOTReceiver, IdealOTSender, IdealRandomCOTReceiver, IdealRandomCOTSender, - IdealRandomOTReceiver, IdealRandomOTSender, -}; -pub use shared::{ - ideal_cot_shared_pair, ideal_ot_shared_pair, ideal_random_cot_shared_pair, - ideal_random_ot_shared_pair, IdealSharedCOTReceiver, IdealSharedCOTSender, - IdealSharedOTReceiver, IdealSharedOTSender, IdealSharedRandomCOTReceiver, - IdealSharedRandomCOTSender, IdealSharedRandomOTReceiver, IdealSharedRandomOTSender, -}; +pub mod cot; +pub mod ot; +pub mod rcot; +pub mod rot; diff --git a/ot/mpz-ot/src/ideal/owned/ot.rs b/ot/mpz-ot/src/ideal/ot.rs similarity index 54% rename from ot/mpz-ot/src/ideal/owned/ot.rs rename to ot/mpz-ot/src/ideal/ot.rs index 7eaebd62..b5745242 100644 --- a/ot/mpz-ot/src/ideal/owned/ot.rs +++ b/ot/mpz-ot/src/ideal/ot.rs @@ -1,3 +1,5 @@ +//! Ideal functionality for oblivious transfer. + use crate::{ CommittedOTReceiver, CommittedOTSender, OTError, OTReceiver, OTSender, OTSetup, VerifiableOTReceiver, VerifiableOTSender, @@ -7,8 +9,7 @@ use futures::{ channel::{mpsc, oneshot}, StreamExt, }; -use mpz_core::ProtocolMessage; -use utils_aio::{sink::IoSink, stream::IoStream}; +use mpz_common::Context; /// Ideal OT sender. #[derive(Debug)] @@ -26,14 +27,6 @@ pub struct IdealOTReceiver { choices_sender: Option>>, } -impl ProtocolMessage for IdealOTSender { - type Msg = (); -} - -impl ProtocolMessage for IdealOTReceiver { - type Msg = (); -} - /// Creates a pair of ideal OT sender and receiver. pub fn ideal_ot_pair() -> (IdealOTSender, IdealOTReceiver) { let (sender, receiver) = mpsc::channel(10); @@ -54,30 +47,23 @@ pub fn ideal_ot_pair() -> (IdealOTSender, IdealOTRe } #[async_trait] -impl OTSetup for IdealOTSender +impl OTSetup for IdealOTSender where + Ctx: Context, T: Send + Sync, { - async fn setup + Send + Unpin, St: IoStream<()> + Send + Unpin>( - &mut self, - _sink: &mut Si, - _stream: &mut St, - ) -> Result<(), OTError> { + async fn setup(&mut self, _ctx: &mut Ctx) -> Result<(), OTError> { Ok(()) } } #[async_trait] -impl OTSender<[T; 2]> for IdealOTSender +impl OTSender for IdealOTSender where + Ctx: Context, T: Send + Sync + Clone + 'static, { - async fn send + Send + Unpin, St: IoStream<()> + Send + Unpin>( - &mut self, - _sink: &mut Si, - _stream: &mut St, - msgs: &[[T; 2]], - ) -> Result<(), OTError> { + async fn send(&mut self, _ctx: &mut Ctx, msgs: &[[T; 2]]) -> Result<(), OTError> { self.msgs.extend(msgs.iter().cloned()); self.sender @@ -89,30 +75,23 @@ where } #[async_trait] -impl OTSetup for IdealOTReceiver +impl OTSetup for IdealOTReceiver where + Ctx: Context, T: Send + Sync, { - async fn setup + Send + Unpin, St: IoStream<()> + Send + Unpin>( - &mut self, - _sink: &mut Si, - _stream: &mut St, - ) -> Result<(), OTError> { + async fn setup(&mut self, _ctx: &mut Ctx) -> Result<(), OTError> { Ok(()) } } #[async_trait] -impl OTReceiver for IdealOTReceiver +impl OTReceiver for IdealOTReceiver where + Ctx: Context, T: Send + Sync + 'static, { - async fn receive + Send + Unpin, St: IoStream<()> + Send + Unpin>( - &mut self, - _sink: &mut Si, - _stream: &mut St, - choices: &[bool], - ) -> Result, OTError> { + async fn receive(&mut self, _ctx: &mut Ctx, choices: &[bool]) -> Result, OTError> { self.choices.extend(choices.iter().copied()); let payload = self @@ -137,46 +116,35 @@ where } #[async_trait] -impl VerifiableOTReceiver for IdealOTReceiver +impl VerifiableOTReceiver for IdealOTReceiver where + Ctx: Context, U: Send + Sync + 'static, V: Send + Sync + 'static, { - async fn verify + Send + Unpin, St: IoStream<()> + Send + Unpin>( - &mut self, - _sink: &mut Si, - _stream: &mut St, - _index: usize, - _msgs: &[V], - ) -> Result<(), OTError> { + async fn verify(&mut self, _ctx: &mut Ctx, _index: usize, _msgs: &[V]) -> Result<(), OTError> { Ok(()) } } #[async_trait] -impl CommittedOTSender<[T; 2]> for IdealOTSender +impl CommittedOTSender for IdealOTSender where + Ctx: Context, T: Send + Sync + Clone + 'static, { - async fn reveal + Send + Unpin, St: IoStream<()> + Send + Unpin>( - &mut self, - _sink: &mut Si, - _stream: &mut St, - ) -> Result<(), OTError> { + async fn reveal(&mut self, _ctx: &mut Ctx) -> Result<(), OTError> { Ok(()) } } #[async_trait] -impl CommittedOTReceiver for IdealOTReceiver +impl CommittedOTReceiver for IdealOTReceiver where + Ctx: Context, T: Send + Sync + 'static, { - async fn reveal_choices + Send + Unpin, St: IoStream<()> + Send + Unpin>( - &mut self, - _sink: &mut Si, - _stream: &mut St, - ) -> Result<(), OTError> { + async fn reveal_choices(&mut self, _ctx: &mut Ctx) -> Result<(), OTError> { self.choices_sender .take() .expect("choices should not be revealed twice") @@ -188,15 +156,12 @@ where } #[async_trait] -impl VerifiableOTSender for IdealOTSender +impl VerifiableOTSender for IdealOTSender where + Ctx: Context, T: Send + Sync + Clone + 'static, { - async fn verify_choices + Send + Unpin, St: IoStream<()> + Send + Unpin>( - &mut self, - _sink: &mut Si, - _stream: &mut St, - ) -> Result, OTError> { + async fn verify_choices(&mut self, _ctx: &mut Ctx) -> Result, OTError> { Ok(self .choices_receiver .take() @@ -208,31 +173,22 @@ where #[cfg(test)] mod tests { - use utils_aio::duplex::MemoryDuplex; + use mpz_common::executor::test_st_executor; use super::*; // Test that the sender and receiver can be used to send and receive values #[tokio::test] async fn test_ideal_ot_owned() { - let (send_channel, recv_channel) = MemoryDuplex::<()>::new(); - - let (mut send_sink, mut send_stream) = send_channel.split(); - let (mut recv_sink, mut recv_stream) = recv_channel.split(); + let (mut ctx_sender, mut ctx_receiver) = test_st_executor(8); let values = vec![[0, 1], [2, 3]]; let choices = vec![false, true]; let (mut sender, mut receiver) = ideal_ot_pair::(); - sender - .send(&mut send_sink, &mut send_stream, &values) - .await - .unwrap(); + sender.send(&mut ctx_sender, &values).await.unwrap(); - let received = receiver - .receive(&mut recv_sink, &mut recv_stream, &choices) - .await - .unwrap(); + let received = receiver.receive(&mut ctx_receiver, &choices).await.unwrap(); assert_eq!(received, vec![0, 3]); } diff --git a/ot/mpz-ot/src/ideal/owned/mod.rs b/ot/mpz-ot/src/ideal/owned/mod.rs deleted file mode 100644 index 7a8ed684..00000000 --- a/ot/mpz-ot/src/ideal/owned/mod.rs +++ /dev/null @@ -1,9 +0,0 @@ -mod cot; -mod ot; -mod rcot; -mod rot; - -pub use cot::{ideal_cot_pair, IdealCOTReceiver, IdealCOTSender}; -pub use ot::{ideal_ot_pair, IdealOTReceiver, IdealOTSender}; -pub use rcot::{ideal_random_cot_pair, IdealRandomCOTReceiver, IdealRandomCOTSender}; -pub use rot::{ideal_random_ot_pair, IdealRandomOTReceiver, IdealRandomOTSender}; diff --git a/ot/mpz-ot/src/ideal/owned/rcot.rs b/ot/mpz-ot/src/ideal/rcot.rs similarity index 66% rename from ot/mpz-ot/src/ideal/owned/rcot.rs rename to ot/mpz-ot/src/ideal/rcot.rs index 4bffc2ac..deb524d3 100644 --- a/ot/mpz-ot/src/ideal/owned/rcot.rs +++ b/ot/mpz-ot/src/ideal/rcot.rs @@ -1,11 +1,13 @@ +//! Ideal functionality for random correlated oblivious transfer. + use crate::{OTError, OTSetup, RandomCOTReceiver, RandomCOTSender}; use async_trait::async_trait; use futures::{channel::mpsc, StreamExt}; -use mpz_core::{Block, ProtocolMessage}; +use mpz_common::Context; +use mpz_core::Block; use rand::Rng; use rand_chacha::ChaCha12Rng; use rand_core::SeedableRng; -use utils_aio::{sink::IoSink, stream::IoStream}; /// Ideal random OT sender. #[derive(Debug)] @@ -22,14 +24,6 @@ pub struct IdealRandomCOTReceiver { rng: ChaCha12Rng, } -impl ProtocolMessage for IdealRandomCOTSender { - type Msg = (); -} - -impl ProtocolMessage for IdealRandomCOTReceiver { - type Msg = (); -} - /// Creates a pair of ideal random COT sender and receiver. pub fn ideal_random_cot_pair( seed: [u8; 32], @@ -51,28 +45,21 @@ pub fn ideal_random_cot_pair( } #[async_trait] -impl OTSetup for IdealRandomCOTSender +impl OTSetup for IdealRandomCOTSender where + Ctx: Context, T: Send + Sync, { - async fn setup + Send + Unpin, St: IoStream<()> + Send + Unpin>( - &mut self, - _sink: &mut Si, - _stream: &mut St, - ) -> Result<(), OTError> { + async fn setup(&mut self, _ctx: &mut Ctx) -> Result<(), OTError> { Ok(()) } } #[async_trait] -impl RandomCOTSender for IdealRandomCOTSender { - async fn send_random_correlated< - Si: IoSink<()> + Send + Unpin, - St: IoStream<()> + Send + Unpin, - >( +impl RandomCOTSender for IdealRandomCOTSender { + async fn send_random_correlated( &mut self, - _sink: &mut Si, - _stream: &mut St, + _ctx: &mut Ctx, count: usize, ) -> Result, OTError> { let low = (0..count) @@ -92,28 +79,21 @@ impl RandomCOTSender for IdealRandomCOTSender { } #[async_trait] -impl OTSetup for IdealRandomCOTReceiver +impl OTSetup for IdealRandomCOTReceiver where + Ctx: Context, T: Send + Sync, { - async fn setup + Send + Unpin, St: IoStream<()> + Send + Unpin>( - &mut self, - _sink: &mut Si, - _stream: &mut St, - ) -> Result<(), OTError> { + async fn setup(&mut self, _ctx: &mut Ctx) -> Result<(), OTError> { Ok(()) } } #[async_trait] -impl RandomCOTReceiver for IdealRandomCOTReceiver { - async fn receive_random_correlated< - Si: IoSink<()> + Send + Unpin, - St: IoStream<()> + Send + Unpin, - >( +impl RandomCOTReceiver for IdealRandomCOTReceiver { + async fn receive_random_correlated( &mut self, - _sink: &mut Si, - _stream: &mut St, + _ctx: &mut Ctx, count: usize, ) -> Result<(Vec, Vec), OTError> { let payload = self @@ -144,7 +124,7 @@ impl RandomCOTReceiver for IdealRandomCOTReceiver { #[cfg(test)] mod tests { - use utils_aio::duplex::MemoryDuplex; + use mpz_common::executor::test_st_executor; use super::*; @@ -152,21 +132,18 @@ mod tests { #[tokio::test] async fn test_ideal_random_cot_owned() { let seed = [0u8; 32]; - let (send_channel, recv_channel) = MemoryDuplex::<()>::new(); - - let (mut send_sink, mut send_stream) = send_channel.split(); - let (mut recv_sink, mut recv_stream) = recv_channel.split(); + let (mut ctx_sender, mut ctx_receiver) = test_st_executor(8); let delta = Block::from([42u8; 16]); let (mut sender, mut receiver) = ideal_random_cot_pair::(seed, delta); let values = sender - .send_random_correlated(&mut send_sink, &mut send_stream, 8) + .send_random_correlated(&mut ctx_sender, 8) .await .unwrap(); let (choices, received) = receiver - .receive_random_correlated(&mut recv_sink, &mut recv_stream, 8) + .receive_random_correlated(&mut ctx_receiver, 8) .await .unwrap(); diff --git a/ot/mpz-ot/src/ideal/owned/rot.rs b/ot/mpz-ot/src/ideal/rot.rs similarity index 69% rename from ot/mpz-ot/src/ideal/owned/rot.rs rename to ot/mpz-ot/src/ideal/rot.rs index d6bf638a..f1f02a2e 100644 --- a/ot/mpz-ot/src/ideal/owned/rot.rs +++ b/ot/mpz-ot/src/ideal/rot.rs @@ -1,11 +1,13 @@ +//! Ideal functionality for random oblivious transfer. + use crate::{OTError, OTSetup, RandomOTReceiver, RandomOTSender}; use async_trait::async_trait; use futures::{channel::mpsc, StreamExt}; -use mpz_core::{prg::Prg, Block, ProtocolMessage}; +use mpz_common::Context; +use mpz_core::{prg::Prg, Block}; use rand::Rng; use rand_chacha::ChaCha12Rng; use rand_core::{RngCore, SeedableRng}; -use utils_aio::{sink::IoSink, stream::IoStream}; /// Ideal random OT sender. #[derive(Debug)] @@ -21,14 +23,6 @@ pub struct IdealRandomOTReceiver { rng: ChaCha12Rng, } -impl ProtocolMessage for IdealRandomOTSender { - type Msg = (); -} - -impl ProtocolMessage for IdealRandomOTReceiver { - type Msg = (); -} - /// Creates a pair of ideal random OT sender and receiver. pub fn ideal_random_ot_pair( seed: [u8; 32], @@ -48,25 +42,21 @@ pub fn ideal_random_ot_pair( } #[async_trait] -impl OTSetup for IdealRandomOTSender +impl OTSetup for IdealRandomOTSender where + Ctx: Context, T: Send + Sync, { - async fn setup + Send + Unpin, St: IoStream<()> + Send + Unpin>( - &mut self, - _sink: &mut Si, - _stream: &mut St, - ) -> Result<(), OTError> { + async fn setup(&mut self, _ctx: &mut Ctx) -> Result<(), OTError> { Ok(()) } } #[async_trait] -impl RandomOTSender<[Block; 2]> for IdealRandomOTSender { - async fn send_random + Send + Unpin, St: IoStream<()> + Send + Unpin>( +impl RandomOTSender for IdealRandomOTSender { + async fn send_random( &mut self, - _sink: &mut Si, - _stream: &mut St, + _ctx: &mut Ctx, count: usize, ) -> Result, OTError> { let messages = (0..count) @@ -82,11 +72,12 @@ impl RandomOTSender<[Block; 2]> for IdealRandomOTSender { } #[async_trait] -impl RandomOTSender<[[u8; N]; 2]> for IdealRandomOTSender<[u8; N]> { - async fn send_random + Send + Unpin, St: IoStream<()> + Send + Unpin>( +impl RandomOTSender + for IdealRandomOTSender<[u8; N]> +{ + async fn send_random( &mut self, - _sink: &mut Si, - _stream: &mut St, + _ctx: &mut Ctx, count: usize, ) -> Result, OTError> { let prng = |block| { @@ -114,25 +105,21 @@ impl RandomOTSender<[[u8; N]; 2]> for IdealRandomOTSender<[u8; N } #[async_trait] -impl OTSetup for IdealRandomOTReceiver +impl OTSetup for IdealRandomOTReceiver where + Ctx: Context, T: Send + Sync, { - async fn setup + Send + Unpin, St: IoStream<()> + Send + Unpin>( - &mut self, - _sink: &mut Si, - _stream: &mut St, - ) -> Result<(), OTError> { + async fn setup(&mut self, _ctx: &mut Ctx) -> Result<(), OTError> { Ok(()) } } #[async_trait] -impl RandomOTReceiver for IdealRandomOTReceiver { - async fn receive_random + Send + Unpin, St: IoStream<()> + Send + Unpin>( +impl RandomOTReceiver for IdealRandomOTReceiver { + async fn receive_random( &mut self, - _sink: &mut Si, - _stream: &mut St, + _ctx: &mut Ctx, count: usize, ) -> Result<(Vec, Vec), OTError> { let payload = self @@ -162,11 +149,12 @@ impl RandomOTReceiver for IdealRandomOTReceiver { } #[async_trait] -impl RandomOTReceiver for IdealRandomOTReceiver<[u8; N]> { - async fn receive_random + Send + Unpin, St: IoStream<()> + Send + Unpin>( +impl RandomOTReceiver + for IdealRandomOTReceiver<[u8; N]> +{ + async fn receive_random( &mut self, - _sink: &mut Si, - _stream: &mut St, + _ctx: &mut Ctx, count: usize, ) -> Result<(Vec, Vec<[u8; N]>), OTError> { let payload = self @@ -198,24 +186,20 @@ impl RandomOTReceiver for IdealRandomOTReceiver<[ #[cfg(test)] mod tests { use super::*; - use utils_aio::duplex::MemoryDuplex; + use mpz_common::executor::test_st_executor; #[tokio::test] async fn test_ideal_random_ot_owned_block() { let seed = [0u8; 32]; - let (send_channel, recv_channel) = MemoryDuplex::<()>::new(); - - let (mut send_sink, mut send_stream) = send_channel.split(); - let (mut recv_sink, mut recv_stream) = recv_channel.split(); - + let (mut ctx_sender, mut ctx_receiver) = test_st_executor(8); let (mut sender, mut receiver) = ideal_random_ot_pair::(seed); - let values = RandomOTSender::send_random(&mut sender, &mut send_sink, &mut send_stream, 8) + let values = RandomOTSender::send_random(&mut sender, &mut ctx_sender, 8) .await .unwrap(); let (choices, received) = - RandomOTReceiver::receive_random(&mut receiver, &mut recv_sink, &mut recv_stream, 8) + RandomOTReceiver::receive_random(&mut receiver, &mut ctx_receiver, 8) .await .unwrap(); @@ -231,19 +215,15 @@ mod tests { #[tokio::test] async fn test_ideal_random_ot_owned_array() { let seed = [0u8; 32]; - let (send_channel, recv_channel) = MemoryDuplex::<()>::new(); - - let (mut send_sink, mut send_stream) = send_channel.split(); - let (mut recv_sink, mut recv_stream) = recv_channel.split(); - + let (mut ctx_sender, mut ctx_receiver) = test_st_executor(8); let (mut sender, mut receiver) = ideal_random_ot_pair::<[u8; 64]>(seed); - let values = RandomOTSender::send_random(&mut sender, &mut send_sink, &mut send_stream, 8) + let values = RandomOTSender::send_random(&mut sender, &mut ctx_sender, 8) .await .unwrap(); let (choices, received) = - RandomOTReceiver::receive_random(&mut receiver, &mut recv_sink, &mut recv_stream, 8) + RandomOTReceiver::receive_random(&mut receiver, &mut ctx_receiver, 8) .await .unwrap(); diff --git a/ot/mpz-ot/src/ideal/shared/cot.rs b/ot/mpz-ot/src/ideal/shared/cot.rs deleted file mode 100644 index 2e88c5ad..00000000 --- a/ot/mpz-ot/src/ideal/shared/cot.rs +++ /dev/null @@ -1,137 +0,0 @@ -use std::{ - any::Any, - collections::HashMap, - sync::{Arc, Mutex}, -}; - -use async_trait::async_trait; -use futures::channel::oneshot; -use mpz_core::Block; - -use crate::{COTReceiverShared, COTSenderShared, OTError}; - -type SenderBuffer = Arc>>>; -type ReceiverBuffer = Arc>>>>; - -/// Creates an ideal correlated ot sender and receiver pair. -pub fn ideal_cot_shared_pair(delta: Block) -> (IdealSharedCOTSender, IdealSharedCOTReceiver) { - let sender_buffer = Arc::new(Mutex::new(HashMap::new())); - let receiver_buffer = Arc::new(Mutex::new(HashMap::new())); - - let sender = IdealSharedCOTSender { - delta, - sender_buffer: sender_buffer.clone(), - receiver_buffer: receiver_buffer.clone(), - }; - - let receiver = IdealSharedCOTReceiver { - sender_buffer, - receiver_buffer, - }; - - (sender, receiver) -} - -/// An ideal correlated oblivious transfer sender. -#[derive(Clone, Debug)] -pub struct IdealSharedCOTSender { - delta: Block, - sender_buffer: SenderBuffer, - receiver_buffer: ReceiverBuffer, -} - -#[async_trait] -impl COTSenderShared for IdealSharedCOTSender { - async fn send_correlated(&self, id: &str, msgs: &[Block]) -> Result<(), OTError> { - let msgs = Box::new( - msgs.iter() - .map(|msg| [*msg, *msg ^ self.delta]) - .collect::>(), - ); - if let Some(sender) = self.receiver_buffer.lock().unwrap().remove(id) { - sender - .send(msgs) - .expect("IdealCOTSenderControl should be able to send"); - } else { - self.sender_buffer - .lock() - .unwrap() - .insert(id.to_string(), msgs); - } - Ok(()) - } -} - -/// An ideal correlated oblivious transfer receiver. -#[derive(Clone, Debug)] -pub struct IdealSharedCOTReceiver { - sender_buffer: SenderBuffer, - receiver_buffer: ReceiverBuffer, -} - -#[async_trait] -impl COTReceiverShared for IdealSharedCOTReceiver { - async fn receive_correlated(&self, id: &str, choices: &[bool]) -> Result, OTError> { - if let Some(value) = self.sender_buffer.lock().unwrap().remove(id) { - let value = *value - .downcast::>() - .expect("value type should be consistent"); - - return Ok(value - .into_iter() - .zip(choices) - .map(|(v, c)| v[*c as usize]) - .collect::>()); - } - - let (sender, receiver) = oneshot::channel(); - self.receiver_buffer - .lock() - .unwrap() - .insert(id.to_string(), sender); - - let values = receiver.await.unwrap(); - - let values = *values - .downcast::>() - .expect("value type should be consistent"); - - Ok(values - .into_iter() - .zip(choices) - .map(|(v, c)| v[*c as usize]) - .collect::>()) - } -} - -#[cfg(test)] -mod tests { - use itybity::IntoBits; - use rand::Rng; - use rand_chacha::ChaCha12Rng; - use rand_core::SeedableRng; - - use super::*; - - #[tokio::test] - async fn test_ideal_cot_shared() { - let mut rng = ChaCha12Rng::seed_from_u64(0); - - let values = Block::random_vec(&mut rng, 8); - let choices = rng.gen::().into_lsb0_vec(); - let delta = Block::from([42u8; 16]); - let (sender, receiver) = ideal_cot_shared_pair(delta); - - sender.send_correlated("", &values).await.unwrap(); - - let received = receiver.receive_correlated("", &choices).await.unwrap(); - - let expected = values - .into_iter() - .zip(choices) - .map(|(v, c)| if c { v ^ delta } else { v }) - .collect::>(); - - assert_eq!(received, expected); - } -} diff --git a/ot/mpz-ot/src/ideal/shared/mod.rs b/ot/mpz-ot/src/ideal/shared/mod.rs deleted file mode 100644 index 1a3d73e8..00000000 --- a/ot/mpz-ot/src/ideal/shared/mod.rs +++ /dev/null @@ -1,14 +0,0 @@ -mod cot; -mod ot; -mod rcot; -mod rot; - -pub use cot::{ideal_cot_shared_pair, IdealSharedCOTReceiver, IdealSharedCOTSender}; -pub use ot::{ideal_ot_shared_pair, IdealSharedOTReceiver, IdealSharedOTSender}; -pub use rcot::{ - ideal_random_cot_shared_pair, IdealSharedRandomCOTReceiver, IdealSharedRandomCOTSender, -}; - -pub use rot::{ - ideal_random_ot_shared_pair, IdealSharedRandomOTReceiver, IdealSharedRandomOTSender, -}; diff --git a/ot/mpz-ot/src/ideal/shared/ot.rs b/ot/mpz-ot/src/ideal/shared/ot.rs deleted file mode 100644 index cd1e62c9..00000000 --- a/ot/mpz-ot/src/ideal/shared/ot.rs +++ /dev/null @@ -1,137 +0,0 @@ -use std::{ - any::Any, - collections::HashMap, - sync::{Arc, Mutex}, -}; - -use async_trait::async_trait; -use futures::channel::oneshot; - -use crate::{ - CommittedOTSenderShared, OTError, OTReceiverShared, OTSenderShared, VerifiableOTReceiverShared, -}; - -/// Creates a ideal sender and receiver pair. -pub fn ideal_ot_shared_pair() -> (IdealSharedOTSender, IdealSharedOTReceiver) { - let sender_buffer = Arc::new(Mutex::new(HashMap::new())); - let receiver_buffer = Arc::new(Mutex::new(HashMap::new())); - - let sender = IdealSharedOTSender { - sender_buffer: sender_buffer.clone(), - receiver_buffer: receiver_buffer.clone(), - }; - - let receiver = IdealSharedOTReceiver { - sender_buffer, - receiver_buffer, - }; - - (sender, receiver) -} - -/// A ideal oblivious transfer sender. -#[derive(Clone, Debug)] -#[allow(clippy::type_complexity)] -pub struct IdealSharedOTSender { - sender_buffer: Arc>>>, - receiver_buffer: Arc>>>>, -} - -#[async_trait] -impl OTSenderShared<[T; 2]> - for IdealSharedOTSender -{ - async fn send(&self, id: &str, msgs: &[[T; 2]]) -> Result<(), OTError> { - let msgs = Box::new(msgs.to_vec()); - if let Some(sender) = self.receiver_buffer.lock().unwrap().remove(id) { - sender - .send(msgs) - .expect("IdealOTSenderControl should be able to send"); - } else { - self.sender_buffer - .lock() - .unwrap() - .insert(id.to_string(), msgs); - } - Ok(()) - } -} - -#[async_trait] -impl CommittedOTSenderShared<[T; 2]> - for IdealSharedOTSender -{ - async fn reveal(&self) -> Result<(), OTError> { - Ok(()) - } -} - -/// A ideal oblivious transfer receiver. -#[derive(Clone, Debug)] -#[allow(clippy::type_complexity)] -pub struct IdealSharedOTReceiver { - sender_buffer: Arc>>>, - receiver_buffer: Arc>>>>, -} - -#[async_trait] -impl OTReceiverShared for IdealSharedOTReceiver { - async fn receive(&self, id: &str, choices: &[bool]) -> Result, OTError> { - if let Some(value) = self.sender_buffer.lock().unwrap().remove(id) { - let value = *value - .downcast::>() - .expect("value type should be consistent"); - - return Ok(value - .into_iter() - .zip(choices) - .map(|(v, c)| v[*c as usize]) - .collect::>()); - } - - let (sender, receiver) = oneshot::channel(); - self.receiver_buffer - .lock() - .unwrap() - .insert(id.to_string(), sender); - - let values = receiver.await.unwrap(); - - let values = *values - .downcast::>() - .expect("value type should be consistent"); - - Ok(values - .into_iter() - .zip(choices) - .map(|(v, c)| v[*c as usize]) - .collect::>()) - } -} - -#[async_trait] -impl VerifiableOTReceiverShared - for IdealSharedOTReceiver -{ - async fn verify(&self, _id: &str, _msgs: &[[T; 2]]) -> Result<(), OTError> { - // Ideal OT is always honest - Ok(()) - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[tokio::test] - async fn test_ideal_ot() { - let values = vec![[0, 1], [2, 3]]; - let choices = vec![false, true]; - let (sender, receiver) = ideal_ot_shared_pair(); - - sender.send("", &values).await.unwrap(); - - let received: Vec = receiver.receive("", &choices).await.unwrap(); - assert_eq!(received, vec![0, 3]); - } -} diff --git a/ot/mpz-ot/src/ideal/shared/rcot.rs b/ot/mpz-ot/src/ideal/shared/rcot.rs deleted file mode 100644 index 7bb014c3..00000000 --- a/ot/mpz-ot/src/ideal/shared/rcot.rs +++ /dev/null @@ -1,151 +0,0 @@ -use std::{ - any::Any, - collections::HashMap, - sync::{Arc, Mutex}, -}; - -use async_trait::async_trait; -use futures::channel::oneshot; -use mpz_core::Block; -use rand::Rng; -use rand_chacha::ChaCha12Rng; -use rand_core::SeedableRng; - -use crate::{OTError, RandomCOTReceiverShared, RandomCOTSenderShared}; - -type SenderBuffer = Arc>>>; -type ReceiverBuffer = Arc>>>>; - -/// Creates an ideal random cot sender and receiver pair. -pub fn ideal_random_cot_shared_pair( - seed: [u8; 32], - delta: Block, -) -> (IdealSharedRandomCOTSender, IdealSharedRandomCOTReceiver) { - let sender_buffer: Arc>>> = - Arc::new(Mutex::new(HashMap::new())); - let receiver_buffer = Arc::new(Mutex::new(HashMap::new())); - - let sender = IdealSharedRandomCOTSender { - rng: Arc::new(Mutex::new(ChaCha12Rng::from_seed(seed))), - delta, - sender_buffer: sender_buffer.clone(), - receiver_buffer: receiver_buffer.clone(), - }; - - let receiver = IdealSharedRandomCOTReceiver { - rng: Arc::new(Mutex::new(ChaCha12Rng::from_seed(seed))), - sender_buffer, - receiver_buffer, - }; - - (sender, receiver) -} - -/// An ideal random correlated oblivious transfer sender. -#[derive(Clone, Debug)] -pub struct IdealSharedRandomCOTSender { - delta: Block, - rng: Arc>, - sender_buffer: SenderBuffer, - receiver_buffer: ReceiverBuffer, -} - -#[async_trait] -impl RandomCOTSenderShared for IdealSharedRandomCOTSender { - async fn send_random_correlated(&self, id: &str, count: usize) -> Result, OTError> { - let low = Block::random_vec(&mut (*self.rng.lock().unwrap()), count); - let msgs = Box::new( - low.iter() - .map(|msg| [*msg, *msg ^ self.delta]) - .collect::>(), - ); - if let Some(sender) = self.receiver_buffer.lock().unwrap().remove(id) { - sender - .send(msgs) - .expect("IdealCOTSenderControl should be able to send"); - } else { - self.sender_buffer - .lock() - .unwrap() - .insert(id.to_string(), msgs); - } - Ok(low) - } -} - -/// An ideal random correlated oblivious transfer receiver. -#[derive(Clone, Debug)] -pub struct IdealSharedRandomCOTReceiver { - rng: Arc>, - sender_buffer: SenderBuffer, - receiver_buffer: ReceiverBuffer, -} - -#[async_trait] -impl RandomCOTReceiverShared for IdealSharedRandomCOTReceiver { - async fn receive_random_correlated( - &self, - id: &str, - count: usize, - ) -> Result<(Vec, Vec), OTError> { - let choices = (0..count) - .map(|_| (*self.rng.lock().unwrap()).gen()) - .collect::>(); - if let Some(value) = self.sender_buffer.lock().unwrap().remove(id) { - let values = *value - .downcast::>() - .expect("value type should be consistent"); - - let value = values - .into_iter() - .zip(&choices) - .map(|([low, high], c)| if *c { high } else { low }) - .collect::>(); - - return Ok((choices, value)); - } - - let (sender, receiver) = oneshot::channel(); - self.receiver_buffer - .lock() - .unwrap() - .insert(id.to_string(), sender); - - let values = receiver.await.unwrap(); - - let values = *values - .downcast::>() - .expect("value type should be consistent"); - - let values = values - .into_iter() - .zip(&choices) - .map(|([low, high], c)| if *c { high } else { low }) - .collect::>(); - - Ok((choices, values)) - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[tokio::test] - async fn test_ideal_random_cot_shared() { - let delta = Block::from([42u8; 16]); - let (sender, receiver) = ideal_random_cot_shared_pair([0u8; 32], delta); - - let values = sender.send_random_correlated("", 8).await.unwrap(); - - let (choices, received) = receiver.receive_random_correlated("", 8).await.unwrap(); - - let expected = values - .into_iter() - .zip(choices) - .map(|(v, c)| if c { v ^ delta } else { v }) - .collect::>(); - - assert_eq!(received, expected); - } -} diff --git a/ot/mpz-ot/src/ideal/shared/rot.rs b/ot/mpz-ot/src/ideal/shared/rot.rs deleted file mode 100644 index 8fbd1793..00000000 --- a/ot/mpz-ot/src/ideal/shared/rot.rs +++ /dev/null @@ -1,241 +0,0 @@ -use std::{ - any::Any, - collections::HashMap, - sync::{Arc, Mutex}, -}; - -use async_trait::async_trait; -use futures::channel::oneshot; -use mpz_core::{prg::Prg, Block}; -use rand::Rng; -use rand_chacha::ChaCha12Rng; -use rand_core::{RngCore, SeedableRng}; - -use crate::{OTError, RandomOTReceiverShared, RandomOTSenderShared}; - -type SenderBuffer = Arc>>>; -type ReceiverBuffer = Arc>>>>; - -/// Creates an ideal random ot sender and receiver pair. -pub fn ideal_random_ot_shared_pair( - seed: [u8; 32], -) -> (IdealSharedRandomOTSender, IdealSharedRandomOTReceiver) { - let sender_buffer: Arc>>> = - Arc::new(Mutex::new(HashMap::new())); - let receiver_buffer = Arc::new(Mutex::new(HashMap::new())); - - let sender = IdealSharedRandomOTSender { - rng: Arc::new(Mutex::new(ChaCha12Rng::from_seed(seed))), - sender_buffer: sender_buffer.clone(), - receiver_buffer: receiver_buffer.clone(), - }; - - let receiver = IdealSharedRandomOTReceiver { - rng: Arc::new(Mutex::new(ChaCha12Rng::from_seed(seed))), - sender_buffer, - receiver_buffer, - }; - - (sender, receiver) -} - -/// An ideal random oblivious transfer sender. -#[derive(Clone, Debug)] -pub struct IdealSharedRandomOTSender { - rng: Arc>, - sender_buffer: SenderBuffer, - receiver_buffer: ReceiverBuffer, -} - -#[async_trait] -impl RandomOTSenderShared<[Block; 2]> for IdealSharedRandomOTSender { - async fn send_random(&self, id: &str, count: usize) -> Result, OTError> { - let blocks = Block::random_vec(&mut (*self.rng.lock().unwrap()), 2 * count); - let messages = (0..count) - .map(|k| [blocks[2 * k], blocks[2 * k + 1]]) - .collect::>(); - - if let Some(sender) = self.receiver_buffer.lock().unwrap().remove(id) { - sender - .send(Box::new(messages.clone())) - .expect("IdealOTSenderControl should be able to send"); - } else { - self.sender_buffer - .lock() - .unwrap() - .insert(id.to_string(), Box::new(messages.clone())); - } - Ok(messages) - } -} - -#[async_trait] -impl RandomOTSenderShared<[[u8; N]; 2]> for IdealSharedRandomOTSender { - async fn send_random(&self, id: &str, count: usize) -> Result, OTError> { - let prng = |block| { - let mut prg = Prg::from_seed(block); - let mut out = [0_u8; N]; - prg.fill_bytes(&mut out); - out - }; - - let blocks = Block::random_vec(&mut (*self.rng.lock().unwrap()), 2 * count); - let messages = (0..count) - .map(|k| [prng(blocks[2 * k]), prng(blocks[2 * k + 1])]) - .collect::>(); - - if let Some(sender) = self.receiver_buffer.lock().unwrap().remove(id) { - sender - .send(Box::new(messages.clone())) - .expect("IdealOTSenderControl should be able to send"); - } else { - self.sender_buffer - .lock() - .unwrap() - .insert(id.to_string(), Box::new(messages.clone())); - } - Ok(messages) - } -} - -/// An ideal random oblivious transfer receiver. -#[derive(Clone, Debug)] -pub struct IdealSharedRandomOTReceiver { - rng: Arc>, - sender_buffer: SenderBuffer, - receiver_buffer: ReceiverBuffer, -} - -#[async_trait] -impl RandomOTReceiverShared for IdealSharedRandomOTReceiver { - async fn receive_random( - &self, - id: &str, - count: usize, - ) -> Result<(Vec, Vec), OTError> { - let choices = (0..count) - .map(|_| (*self.rng.lock().unwrap()).gen()) - .collect::>(); - - if let Some(value) = self.sender_buffer.lock().unwrap().remove(id) { - let values = *value - .downcast::>() - .expect("value type should be consistent"); - - let value = values - .into_iter() - .zip(&choices) - .map(|([low, high], c)| if *c { high } else { low }) - .collect::>(); - - return Ok((choices, value)); - } - - let (sender, receiver) = oneshot::channel(); - self.receiver_buffer - .lock() - .unwrap() - .insert(id.to_string(), sender); - - let values = receiver.await.unwrap(); - - let values = *values - .downcast::>() - .expect("value type should be consistent"); - - let values = values - .into_iter() - .zip(&choices) - .map(|([low, high], c)| if *c { high } else { low }) - .collect::>(); - - Ok((choices, values)) - } -} - -#[async_trait] -impl RandomOTReceiverShared for IdealSharedRandomOTReceiver { - async fn receive_random( - &self, - id: &str, - count: usize, - ) -> Result<(Vec, Vec<[u8; N]>), OTError> { - let choices = (0..count) - .map(|_| (*self.rng.lock().unwrap()).gen()) - .collect::>(); - - if let Some(value) = self.sender_buffer.lock().unwrap().remove(id) { - let values = *value - .downcast::>() - .expect("value type should be consistent"); - - let value = values - .into_iter() - .zip(&choices) - .map(|([low, high], c)| if *c { high } else { low }) - .collect::>(); - - return Ok((choices, value)); - } - - let (sender, receiver) = oneshot::channel(); - self.receiver_buffer - .lock() - .unwrap() - .insert(id.to_string(), sender); - - let values = receiver.await.unwrap(); - - let values = *values - .downcast::>() - .expect("value type should be consistent"); - - let values = values - .into_iter() - .zip(&choices) - .map(|([low, high], c)| if *c { high } else { low }) - .collect::>(); - - Ok((choices, values)) - } -} -#[cfg(test)] -mod tests { - use super::*; - - #[tokio::test] - async fn test_ideal_random_ot_shared_block() { - let (sender, receiver) = ideal_random_ot_shared_pair([0u8; 32]); - - let values: Vec<[Block; 2]> = sender.send_random("", 8).await.unwrap(); - - let (choices, received): (Vec, Vec) = - receiver.receive_random("", 8).await.unwrap(); - - let expected: Vec = values - .into_iter() - .zip(choices) - .map(|(v, c): ([Block; 2], bool)| v[c as usize]) - .collect::>(); - - assert_eq!(received, expected); - } - - #[tokio::test] - async fn test_ideal_random_ot_shared_array() { - let (sender, receiver) = ideal_random_ot_shared_pair([0u8; 32]); - - let values: Vec<[[u8; 64]; 2]> = sender.send_random("", 8).await.unwrap(); - - let (choices, received): (Vec, Vec<[u8; 64]>) = - receiver.receive_random("", 8).await.unwrap(); - - let expected: Vec<[u8; 64]> = values - .into_iter() - .zip(choices) - .map(|(v, c): ([[u8; 64]; 2], bool)| v[c as usize]) - .collect::>(); - - assert_eq!(received, expected); - } -} diff --git a/ot/mpz-ot/src/kos/error.rs b/ot/mpz-ot/src/kos/error.rs index 8ebce4a5..05361cd5 100644 --- a/ot/mpz-ot/src/kos/error.rs +++ b/ot/mpz-ot/src/kos/error.rs @@ -1,5 +1,3 @@ -use mpz_ot_core::kos::msgs::MessageError; - use crate::OTError; /// A KOS sender error. @@ -12,8 +10,8 @@ pub enum SenderError { CoreError(#[from] mpz_ot_core::kos::SenderError), #[error(transparent)] BaseOTError(#[from] crate::OTError), - #[error(transparent)] - CointossError(#[from] mpz_core::cointoss::CointossError), + #[error("coin-toss error: {0}")] + CointossError(#[from] mpz_cointoss::CointossError), #[error("{0}")] StateError(String), #[error("configuration error: {0}")] @@ -43,15 +41,6 @@ impl From for OTError { } } -impl From> for SenderError { - fn from(err: MessageError) -> Self { - SenderError::from(std::io::Error::new( - std::io::ErrorKind::InvalidData, - err.to_string(), - )) - } -} - /// A KOS receiver error. #[derive(Debug, thiserror::Error)] #[allow(missing_docs)] @@ -62,8 +51,8 @@ pub enum ReceiverError { CoreError(#[from] mpz_ot_core::kos::ReceiverError), #[error(transparent)] BaseOTError(#[from] crate::OTError), - #[error(transparent)] - CointossError(#[from] mpz_core::cointoss::CointossError), + #[error("coin-toss error: {0}")] + CointossError(#[from] mpz_cointoss::CointossError), #[error("{0}")] StateError(String), #[error("configuration error: {0}")] @@ -95,15 +84,6 @@ impl From for OTError { } } -impl From> for ReceiverError { - fn from(err: MessageError) -> Self { - ReceiverError::from(std::io::Error::new( - std::io::ErrorKind::InvalidData, - err.to_string(), - )) - } -} - #[derive(Debug, thiserror::Error)] #[allow(missing_docs)] pub enum ReceiverVerifyError { diff --git a/ot/mpz-ot/src/kos/mod.rs b/ot/mpz-ot/src/kos/mod.rs index ad844027..831e95cf 100644 --- a/ot/mpz-ot/src/kos/mod.rs +++ b/ot/mpz-ot/src/kos/mod.rs @@ -3,11 +3,14 @@ mod error; mod receiver; mod sender; +mod shared_receiver; +mod shared_sender; pub use error::{ReceiverError, ReceiverVerifyError, SenderError}; -use futures_util::{SinkExt, StreamExt}; pub use receiver::Receiver; pub use sender::Sender; +pub use shared_receiver::SharedReceiver; +pub use shared_sender::SharedSender; pub(crate) use receiver::StateError as ReceiverStateError; pub(crate) use sender::StateError as SenderStateError; @@ -16,7 +19,6 @@ pub use mpz_ot_core::kos::{ msgs, PayloadRecord, ReceiverConfig, ReceiverConfigBuilder, ReceiverConfigBuilderError, ReceiverKeys, SenderConfig, SenderConfigBuilder, SenderConfigBuilderError, SenderKeys, }; -use utils_aio::{sink::IoSink, stream::IoStream}; // If we're testing we use a smaller chunk size to make sure the chunking code paths are tested. cfg_if::cfg_if! { @@ -28,41 +30,23 @@ cfg_if::cfg_if! { } } -/// Converts a sink of KOS messages into a sink of base OT messages. -pub(crate) fn into_base_sink<'a, Si: IoSink> + Send + Unpin, T: Send + 'a>( - sink: &'a mut Si, -) -> impl IoSink + Send + Unpin + 'a { - Box::pin(SinkExt::with(sink, |msg| async move { - Ok(msgs::Message::BaseMsg(msg)) - })) -} - -/// Converts a stream of KOS messages into a stream of base OT messages. -pub(crate) fn into_base_stream<'a, St: IoStream> + Send + Unpin, T: Send + 'a>( - stream: &'a mut St, -) -> impl IoStream + Send + Unpin + 'a { - StreamExt::map(stream, |msg| match msg { - Ok(msg) => msg.try_into_base_msg().map_err(From::from), - Err(err) => Err(err), - }) -} - #[cfg(test)] mod tests { use super::*; use rstest::*; + use futures::TryFutureExt; use itybity::ToBits; + use mpz_common::{executor::test_st_executor, Context}; use mpz_core::Block; - use mpz_ot_core::kos::msgs::Message; use rand::Rng; use rand_chacha::ChaCha12Rng; use rand_core::SeedableRng; - use utils_aio::duplex::MemoryDuplex; use crate::{ - ideal::{ideal_ot_pair, IdealOTReceiver, IdealOTSender}, - OTReceiver, OTSender, OTSetup, RandomOTReceiver, RandomOTSender, VerifiableOTReceiver, + ideal::ot::{ideal_ot_pair, IdealOTReceiver, IdealOTSender}, + OTError, OTReceiver, OTSender, OTSetup, RandomOTReceiver, RandomOTSender, + VerifiableOTReceiver, }; #[fixture] @@ -87,16 +71,11 @@ mod tests { .map(|([zero, one], choice)| if choice { one } else { zero }) } - async fn setup< - Si: IoSink> + Send + Unpin, - St: IoStream> + Send + Unpin, - >( + async fn setup( sender_config: SenderConfig, receiver_config: ReceiverConfig, - sender_sink: &mut Si, - sender_stream: &mut St, - receiver_sink: &mut Si, - receiver_stream: &mut St, + ctx_sender: &mut Ctx, + ctx_receiver: &mut Ctx, count: usize, ) -> ( Sender>, @@ -107,21 +86,12 @@ mod tests { let mut sender = Sender::new(sender_config, base_receiver); let mut receiver = Receiver::new(receiver_config, base_sender); - let (sender_res, receiver_res) = tokio::join!( - sender.setup(sender_sink, sender_stream), - receiver.setup(receiver_sink, receiver_stream) - ); - - sender_res.unwrap(); - receiver_res.unwrap(); - - let (sender_res, receiver_res) = tokio::join!( - sender.extend(sender_sink, sender_stream, count), - receiver.extend(receiver_sink, receiver_stream, count) - ); - - sender_res.unwrap(); - receiver_res.unwrap(); + tokio::try_join!(sender.setup(ctx_sender), receiver.setup(ctx_receiver)).unwrap(); + tokio::try_join!( + sender.extend(ctx_sender, count).map_err(OTError::from), + receiver.extend(ctx_receiver, count).map_err(OTError::from) + ) + .unwrap(); (sender, receiver) } @@ -129,29 +99,23 @@ mod tests { #[rstest] #[tokio::test] async fn test_kos(data: Vec<[Block; 2]>, choices: Vec) { - let (sender_channel, receiver_channel) = MemoryDuplex::new(); - - let (mut sender_sink, mut sender_stream) = sender_channel.split(); - let (mut receiver_sink, mut receiver_stream) = receiver_channel.split(); - + let (mut ctx_sender, mut ctx_receiver) = test_st_executor(8); let (mut sender, mut receiver) = setup( SenderConfig::default(), ReceiverConfig::default(), - &mut sender_sink, - &mut sender_stream, - &mut receiver_sink, - &mut receiver_stream, + &mut ctx_sender, + &mut ctx_receiver, data.len(), ) .await; - let (sender_res, receiver_res) = tokio::join!( - sender.send(&mut sender_sink, &mut sender_stream, &data), - receiver.receive(&mut receiver_sink, &mut receiver_stream, &choices) - ); - - sender_res.unwrap(); - let received: Vec = receiver_res.unwrap(); + let (_, received): (_, Vec) = tokio::try_join!( + sender.send(&mut ctx_sender, &data).map_err(OTError::from), + receiver + .receive(&mut ctx_receiver, &choices) + .map_err(OTError::from) + ) + .unwrap(); let expected = choose(data.iter().copied(), choices.iter_lsb0()).collect::>(); @@ -160,34 +124,24 @@ mod tests { #[tokio::test] async fn test_kos_random() { - let (sender_channel, receiver_channel) = MemoryDuplex::new(); - - let (mut sender_sink, mut sender_stream) = sender_channel.split(); - let (mut receiver_sink, mut receiver_stream) = receiver_channel.split(); - + let (mut ctx_sender, mut ctx_receiver) = test_st_executor(8); let (mut sender, mut receiver) = setup( SenderConfig::default(), ReceiverConfig::default(), - &mut sender_sink, - &mut sender_stream, - &mut receiver_sink, - &mut receiver_stream, + &mut ctx_sender, + &mut ctx_receiver, 10, ) .await; - let (sender_res, receiver_res) = tokio::join!( - RandomOTSender::send_random(&mut sender, &mut sender_sink, &mut sender_stream, 10), - RandomOTReceiver::receive_random( - &mut receiver, - &mut receiver_sink, - &mut receiver_stream, - 10 - ) - ); - - let sender_output: Vec<[Block; 2]> = sender_res.unwrap(); - let (choices, receiver_output): (Vec, Vec) = receiver_res.unwrap(); + let (sender_output, (choices, receiver_output)): ( + Vec<[Block; 2]>, + (Vec, Vec), + ) = tokio::try_join!( + RandomOTSender::send_random(&mut sender, &mut ctx_sender, 10), + RandomOTReceiver::receive_random(&mut receiver, &mut ctx_receiver, 10) + ) + .unwrap(); let expected = sender_output .into_iter() @@ -201,18 +155,12 @@ mod tests { #[rstest] #[tokio::test] async fn test_kos_bytes(data: Vec<[Block; 2]>, choices: Vec) { - let (sender_channel, receiver_channel) = MemoryDuplex::new(); - - let (mut sender_sink, mut sender_stream) = sender_channel.split(); - let (mut receiver_sink, mut receiver_stream) = receiver_channel.split(); - + let (mut ctx_sender, mut ctx_receiver) = test_st_executor(8); let (mut sender, mut receiver) = setup( SenderConfig::default(), ReceiverConfig::default(), - &mut sender_sink, - &mut sender_stream, - &mut receiver_sink, - &mut receiver_stream, + &mut ctx_sender, + &mut ctx_receiver, data.len(), ) .await; @@ -222,13 +170,13 @@ mod tests { .map(|[a, b]| [a.to_bytes(), b.to_bytes()]) .collect(); - let (sender_res, receiver_res) = tokio::join!( - sender.send(&mut sender_sink, &mut sender_stream, &data), - receiver.receive(&mut receiver_sink, &mut receiver_stream, &choices) - ); - - sender_res.unwrap(); - let received: Vec<[u8; 16]> = receiver_res.unwrap(); + let (_, received): (_, Vec<[u8; 16]>) = tokio::try_join!( + sender.send(&mut ctx_sender, &data).map_err(OTError::from), + receiver + .receive(&mut ctx_receiver, &choices) + .map_err(OTError::from) + ) + .unwrap(); let expected = choose(data.iter().copied(), choices.iter_lsb0()).collect::>(); @@ -238,40 +186,63 @@ mod tests { #[rstest] #[tokio::test] async fn test_kos_committed_sender(data: Vec<[Block; 2]>, choices: Vec) { - let (sender_channel, receiver_channel) = MemoryDuplex::new(); - - let (mut sender_sink, mut sender_stream) = sender_channel.split(); - let (mut receiver_sink, mut receiver_stream) = receiver_channel.split(); - + let (mut ctx_sender, mut ctx_receiver) = test_st_executor(8); let (mut sender, mut receiver) = setup( SenderConfig::builder().sender_commit().build().unwrap(), ReceiverConfig::builder().sender_commit().build().unwrap(), - &mut sender_sink, - &mut sender_stream, - &mut receiver_sink, - &mut receiver_stream, + &mut ctx_sender, + &mut ctx_receiver, data.len(), ) .await; - let (sender_res, receiver_res) = tokio::join!( - sender.send(&mut sender_sink, &mut sender_stream, &data), - receiver.receive(&mut receiver_sink, &mut receiver_stream, &choices) - ); - - sender_res.unwrap(); - let received: Vec = receiver_res.unwrap(); + let (_, received): (_, Vec) = tokio::try_join!( + sender.send(&mut ctx_sender, &data).map_err(OTError::from), + receiver + .receive(&mut ctx_receiver, &choices) + .map_err(OTError::from) + ) + .unwrap(); let expected = choose(data.iter().copied(), choices.iter_lsb0()).collect::>(); assert_eq!(received, expected); - let (sender_res, receiver_res) = tokio::join!( - sender.reveal(&mut sender_sink, &mut sender_stream), - receiver.verify(&mut receiver_sink, &mut receiver_stream, 0, &data) - ); + tokio::try_join!( + sender.reveal(&mut ctx_sender).map_err(OTError::from), + receiver + .verify(&mut ctx_receiver, 0, &data) + .map_err(OTError::from) + ) + .unwrap(); + } + + #[rstest] + #[tokio::test] + async fn test_shared_kos(data: Vec<[Block; 2]>, choices: Vec) { + let (mut ctx_sender, mut ctx_receiver) = test_st_executor(8); + let (sender, receiver) = setup( + SenderConfig::default(), + ReceiverConfig::default(), + &mut ctx_sender, + &mut ctx_receiver, + data.len(), + ) + .await; + + let mut receiver = SharedReceiver::new(receiver); + let mut sender = SharedSender::new(sender); - sender_res.unwrap(); - receiver_res.unwrap(); + let (_, received): (_, Vec) = tokio::try_join!( + sender.send(&mut ctx_sender, &data).map_err(OTError::from), + receiver + .receive(&mut ctx_receiver, &choices) + .map_err(OTError::from) + ) + .unwrap(); + + let expected = choose(data.iter().copied(), choices.iter_lsb0()).collect::>(); + + assert_eq!(received, expected); } } diff --git a/ot/mpz-ot/src/kos/receiver.rs b/ot/mpz-ot/src/kos/receiver.rs index 1d48a349..ab3bf325 100644 --- a/ot/mpz-ot/src/kos/receiver.rs +++ b/ot/mpz-ot/src/kos/receiver.rs @@ -1,24 +1,20 @@ use async_trait::async_trait; -use futures::SinkExt; use itybity::{FromBitIterator, IntoBitIterator}; -use mpz_core::{cointoss, prg::Prg, Block, ProtocolMessage}; +use mpz_cointoss as cointoss; +use mpz_common::{scoped_futures::ScopedFutureExt, Context}; +use mpz_core::{prg::Prg, Block}; use mpz_ot_core::kos::{ - msgs::{Message, StartExtend}, - pad_ot_count, receiver_state as state, Receiver as ReceiverCore, ReceiverConfig, CSP, + msgs::StartExtend, pad_ot_count, receiver_state as state, Receiver as ReceiverCore, + ReceiverConfig, ReceiverKeys, CSP, }; use enum_try_as_inner::EnumTryAsInner; use rand::{thread_rng, Rng}; use rand_core::{RngCore, SeedableRng}; -use utils_aio::{ - non_blocking_backend::{Backend, NonBlockingBackend}, - sink::IoSink, - stream::{ExpectStreamExt, IoStream}, -}; +use serio::{stream::IoStreamExt as _, SinkExt as _}; +use utils_aio::non_blocking_backend::{Backend, NonBlockingBackend}; -use super::{ - into_base_sink, into_base_stream, ReceiverError, ReceiverVerifyError, EXTEND_CHUNK_SIZE, -}; +use super::{ReceiverError, ReceiverVerifyError, EXTEND_CHUNK_SIZE}; use crate::{ OTError, OTReceiver, OTSender, OTSetup, RandomOTReceiver, VerifiableOTReceiver, VerifiableOTSender, @@ -44,7 +40,7 @@ pub struct Receiver { impl Receiver where - BaseOT: OTSender<[Block; 2]> + Send, + BaseOT: Send, { /// Creates a new receiver. /// @@ -64,14 +60,12 @@ where Ok(self.state.try_as_extension()?.remaining()) } - /// Returns a reference to the inner receiver state. - pub(crate) fn state(&self) -> &State { - &self.state - } - - /// Returns a mutable reference to the inner receiver state. - pub(crate) fn state_mut(&mut self) -> &mut State { - &mut self.state + /// Returns the provided number of keys. + pub(crate) fn take_keys(&mut self, count: usize) -> Result { + self.state + .try_as_extension_mut()? + .keys(count) + .map_err(ReceiverError::from) } /// Performs OT extension. @@ -81,13 +75,9 @@ where /// * `sink` - The sink to send messages to the sender /// * `stream` - The stream to receive messages from the sender /// * `count` - The number of OTs to extend - pub async fn extend< - Si: IoSink> + Send + Unpin, - St: IoStream> + Send + Unpin, - >( + pub async fn extend( &mut self, - sink: &mut Si, - stream: &mut St, + ctx: &mut Ctx, count: usize, ) -> Result<(), ReceiverError> { let mut ext_receiver = @@ -97,52 +87,33 @@ where // Extend the OTs. let (mut ext_receiver, extend) = Backend::spawn(move || { - let extend = ext_receiver.extend(count); - - (ext_receiver, extend) + ext_receiver + .extend(count) + .map(|extend| (ext_receiver, extend)) }) - .await; - - let extend = extend?; - - // Commit to coin toss seed - let seed: Block = thread_rng().gen(); - let (cointoss_sender, cointoss_commitment) = cointoss::Sender::new(vec![seed]).send(); + .await?; - // Send the extend message and cointoss commitment - sink.feed(Message::StartExtend(StartExtend { count })) - .await?; + // Send the extend message and cointoss commitment. + ctx.io_mut().feed(StartExtend { count }).await?; for extend in extend.into_chunks(EXTEND_CHUNK_SIZE) { - sink.feed(Message::Extend(extend)).await?; + ctx.io_mut().feed(extend).await?; } - sink.feed(Message::CointossCommit(cointoss_commitment)) - .await?; - sink.flush().await?; - - // Receive coin toss - let cointoss_payload = stream - .expect_next() - .await? - .try_into_cointoss_receiver_payload()?; + ctx.io_mut().flush().await?; - // Open commitment - let (mut seeds, payload) = cointoss_sender.finalize(cointoss_payload)?; - let chi_seed = seeds.pop().expect("seed is present"); + // Sample chi_seed with coin-toss. + let seed = thread_rng().gen(); + let chi_seed = cointoss::cointoss_sender(ctx, vec![seed]).await?[0]; - // Compute consistency check + // Compute consistency check. let (ext_receiver, check) = Backend::spawn(move || { - let check = ext_receiver.check(chi_seed); - - (ext_receiver, check) + ext_receiver + .check(chi_seed) + .map(|check| (ext_receiver, check)) }) - .await; - - let check = check?; + .await?; - // Send coin toss decommitment and correlation check value. - sink.feed(Message::CointossSenderPayload(payload)).await?; - sink.feed(Message::Check(check)).await?; - sink.flush().await?; + // Send correlation check value. + ctx.io_mut().send(check).await?; self.state = State::Extension(ext_receiver); @@ -152,25 +123,18 @@ where impl Receiver where - BaseOT: VerifiableOTSender + ProtocolMessage + Send, + BaseOT: Send, { - pub(crate) async fn verify_delta< - Si: IoSink> + Send + Unpin, - St: IoStream> + Send + Unpin, - >( + pub(crate) async fn verify_delta( &mut self, - sink: &mut Si, - stream: &mut St, - ) -> Result<(), ReceiverError> { + ctx: &mut Ctx, + ) -> Result<(), ReceiverError> + where + BaseOT: VerifiableOTSender, + { let receiver = std::mem::replace(&mut self.state, State::Error).try_into_extension()?; // Finalize coin toss to determine expected delta - let cointoss_payload = stream - .expect_next() - .await? - .try_into_cointoss_sender_payload() - .map_err(ReceiverError::from)?; - let Some(cointoss_receiver) = self.cointoss_receiver.take() else { return Err(ReceiverError::ConfigError( "committed sender not configured".to_string(), @@ -178,14 +142,12 @@ where }; let expected_delta = cointoss_receiver - .finalize(cointoss_payload) + .finalize(ctx) + .await .map_err(ReceiverError::from)?[0]; // Receive delta by verifying the sender's base OT choices. - let choices = self - .base - .verify_choices(&mut into_base_sink(sink), &mut into_base_stream(stream)) - .await?; + let choices = self.base.verify_choices(ctx).await?; let actual_delta = <[u8; 16]>::from_lsb0_iter(choices).into(); @@ -199,26 +161,13 @@ where } } -impl ProtocolMessage for Receiver -where - BaseOT: ProtocolMessage, -{ - type Msg = Message; -} - #[async_trait] -impl OTSetup for Receiver +impl OTSetup for Receiver where - BaseOT: OTSetup + OTSender<[Block; 2]> + Send, + Ctx: Context, + BaseOT: OTSetup + OTSender + Send, { - async fn setup< - Si: IoSink> + Send + Unpin, - St: IoStream> + Send + Unpin, - >( - &mut self, - sink: &mut Si, - stream: &mut St, - ) -> Result<(), OTError> { + async fn setup(&mut self, ctx: &mut Ctx) -> Result<(), OTError> { if self.state.is_extension() { return Ok(()); } @@ -229,36 +178,36 @@ where // If the sender is committed, we run a coin toss if ext_receiver.config().sender_commit() { - let commitment = stream - .expect_next() - .await? - .try_into_cointoss_commit() - .map_err(ReceiverError::from)?; - - let (cointoss_receiver, payload) = cointoss::Receiver::new(vec![thread_rng().gen()]) - .reveal(commitment) - .map_err(ReceiverError::from)?; - - sink.send(Message::CointossReceiverPayload(payload)).await?; + let cointoss_seed = thread_rng().gen(); + let base = &mut self.base; + + let (cointoss_receiver, _) = ctx + .try_join( + |ctx| { + async move { + cointoss::Receiver::new(vec![cointoss_seed]) + .receive(ctx) + .await + .map_err(ReceiverError::from) + } + .scope_boxed() + }, + |ctx| { + async move { base.setup(ctx).await.map_err(ReceiverError::from) } + .scope_boxed() + }, + ) + .await?; self.cointoss_receiver = Some(cointoss_receiver); + } else { + self.base.setup(ctx).await?; } - // Set up base OT - self.base - .setup(&mut into_base_sink(sink), &mut into_base_stream(stream)) - .await?; - let seeds: [[Block; 2]; CSP] = std::array::from_fn(|_| thread_rng().gen()); // Send seeds to sender - self.base - .send( - &mut into_base_sink(sink), - &mut into_base_stream(stream), - &seeds, - ) - .await?; + self.base.send(ctx, &seeds).await?; let ext_receiver = ext_receiver.setup(seeds); @@ -269,19 +218,12 @@ where } #[async_trait] -impl OTReceiver for Receiver +impl OTReceiver for Receiver where - BaseOT: ProtocolMessage + Send, + Ctx: Context, + BaseOT: Send, { - async fn receive< - Si: IoSink> + Send + Unpin, - St: IoStream> + Send + Unpin, - >( - &mut self, - sink: &mut Si, - stream: &mut St, - choices: &[bool], - ) -> Result, OTError> { + async fn receive(&mut self, ctx: &mut Ctx, choices: &[bool]) -> Result, OTError> { let receiver = self .state .try_as_extension_mut() @@ -295,14 +237,10 @@ where .map_err(ReceiverError::from)?; // Send derandomize message - sink.send(Message::Derandomize(derandomize)).await?; + ctx.io_mut().send(derandomize).await?; // Receive payload - let payload = stream - .expect_next() - .await? - .try_into_sender_payload() - .map_err(ReceiverError::from)?; + let payload = ctx.io_mut().expect_next().await?; let received = Backend::spawn(move || { receiver_keys @@ -316,17 +254,14 @@ where } #[async_trait] -impl RandomOTReceiver for Receiver +impl RandomOTReceiver for Receiver where - BaseOT: ProtocolMessage + Send, + Ctx: Context, + BaseOT: Send, { - async fn receive_random< - Si: IoSink> + Send + Unpin, - St: IoStream> + Send + Unpin, - >( + async fn receive_random( &mut self, - _sink: &mut Si, - _stream: &mut St, + _ctx: &mut Ctx, count: usize, ) -> Result<(Vec, Vec), OTError> { let receiver = self @@ -344,19 +279,12 @@ where } #[async_trait] -impl OTReceiver for Receiver +impl OTReceiver for Receiver where - BaseOT: ProtocolMessage + Send, + Ctx: Context, + BaseOT: Send, { - async fn receive< - Si: IoSink> + Send + Unpin, - St: IoStream> + Send + Unpin, - >( - &mut self, - sink: &mut Si, - stream: &mut St, - choices: &[bool], - ) -> Result, OTError> { + async fn receive(&mut self, ctx: &mut Ctx, choices: &[bool]) -> Result, OTError> { let receiver = self .state .try_as_extension_mut() @@ -370,14 +298,10 @@ where .map_err(ReceiverError::from)?; // Send derandomize message - sink.send(Message::Derandomize(derandomize)).await?; + ctx.io_mut().send(derandomize).await?; // Receive payload - let payload = stream - .expect_next() - .await? - .try_into_sender_payload() - .map_err(ReceiverError::from)?; + let payload = ctx.io_mut().expect_next().await?; let received = Backend::spawn(move || { receiver_keys @@ -391,17 +315,14 @@ where } #[async_trait] -impl RandomOTReceiver for Receiver +impl RandomOTReceiver for Receiver where - BaseOT: ProtocolMessage + Send, + Ctx: Context, + BaseOT: Send, { - async fn receive_random< - Si: IoSink> + Send + Unpin, - St: IoStream> + Send + Unpin, - >( + async fn receive_random( &mut self, - _sink: &mut Si, - _stream: &mut St, + _ctx: &mut Ctx, count: usize, ) -> Result<(Vec, Vec<[u8; N]>), OTError> { let receiver = self @@ -430,23 +351,20 @@ where } #[async_trait] -impl VerifiableOTReceiver for Receiver +impl VerifiableOTReceiver for Receiver where - BaseOT: VerifiableOTSender + ProtocolMessage + Send, + Ctx: Context, + BaseOT: VerifiableOTSender + Send, { - async fn verify< - Si: IoSink + Send + Unpin, - St: IoStream + Send + Unpin, - >( + async fn verify( &mut self, - sink: &mut Si, - stream: &mut St, + ctx: &mut Ctx, id: usize, msgs: &[[Block; 2]], ) -> Result<(), OTError> { // Verify delta if we haven't yet. if self.state.is_extension() { - self.verify_delta(sink, stream).await?; + self.verify_delta(ctx).await?; } let receiver = self.state.try_as_verify().map_err(ReceiverError::from)?; diff --git a/ot/mpz-ot/src/kos/sender.rs b/ot/mpz-ot/src/kos/sender.rs index 91358b90..f5929c4b 100644 --- a/ot/mpz-ot/src/kos/sender.rs +++ b/ot/mpz-ot/src/kos/sender.rs @@ -1,22 +1,19 @@ use async_trait::async_trait; use enum_try_as_inner::EnumTryAsInner; -use futures_util::SinkExt; use itybity::IntoBits; -use mpz_core::{cointoss, prg::Prg, Block, ProtocolMessage}; +use mpz_cointoss as cointoss; +use mpz_common::{scoped_futures::ScopedFutureExt, Context}; +use mpz_core::{prg::Prg, Block}; use mpz_ot_core::kos::{ extension_matrix_size, - msgs::{Extend, Message, StartExtend}, - pad_ot_count, sender_state as state, Sender as SenderCore, SenderConfig, CSP, + msgs::{Extend, StartExtend}, + pad_ot_count, sender_state as state, Sender as SenderCore, SenderConfig, SenderKeys, CSP, }; use rand::{thread_rng, Rng}; use rand_core::{RngCore, SeedableRng}; -use utils_aio::{ - non_blocking_backend::{Backend, NonBlockingBackend}, - sink::IoSink, - stream::{ExpectStreamExt, IoStream}, -}; +use serio::{stream::IoStreamExt as _, SinkExt as _}; +use utils_aio::non_blocking_backend::{Backend, NonBlockingBackend}; -use super::{into_base_sink, into_base_stream}; use crate::{ kos::SenderError, CommittedOTReceiver, CommittedOTSender, OTError, OTReceiver, OTSender, OTSetup, RandomOTSender, @@ -37,13 +34,10 @@ pub struct Sender { state: State, base: BaseOT, - cointoss_payload: Option, + cointoss_sender: Option>, } -impl Sender -where - BaseOT: OTReceiver + Send, -{ +impl Sender { /// Creates a new Sender /// /// # Arguments @@ -53,7 +47,7 @@ where Self { state: State::Initialized(SenderCore::new(config)), base, - cointoss_payload: None, + cointoss_sender: None, } } @@ -62,9 +56,12 @@ where Ok(self.state.try_as_extension()?.remaining()) } - /// Returns a mutable reference to the inner sender state. - pub(crate) fn state_mut(&mut self) -> &mut State { - &mut self.state + /// Returns the provided number of keys. + pub(crate) fn take_keys(&mut self, count: usize) -> Result { + self.state + .try_as_extension_mut()? + .keys(count) + .map_err(SenderError::from) } /// Performs the base OT setup with the provided delta. @@ -74,44 +71,35 @@ where /// * `sink` - The sink to send messages to the base OT sender /// * `stream` - The stream to receive messages from the base OT sender /// * `delta` - The delta value to use for the base OT setup. - pub async fn setup_with_delta< - Si: IoSink> + Send + Unpin, - St: IoStream> + Send + Unpin, - >( + pub async fn setup_with_delta( &mut self, - sink: &mut Si, - stream: &mut St, + ctx: &mut Ctx, delta: Block, - ) -> Result<(), SenderError> { + ) -> Result<(), SenderError> + where + BaseOT: OTReceiver, + { if self.state.try_as_initialized()?.config().sender_commit() { return Err(SenderError::ConfigError( "committed sender can not choose delta".to_string(), )); } - self._setup_with_delta(sink, stream, delta).await + self._setup_with_delta(ctx, delta).await } - async fn _setup_with_delta< - Si: IoSink> + Send + Unpin, - St: IoStream> + Send + Unpin, - >( + async fn _setup_with_delta( &mut self, - sink: &mut Si, - stream: &mut St, + ctx: &mut Ctx, delta: Block, - ) -> Result<(), SenderError> { + ) -> Result<(), SenderError> + where + BaseOT: OTReceiver, + { let ext_sender = std::mem::replace(&mut self.state, State::Error).try_into_initialized()?; let choices = delta.into_lsb0_vec(); - let seeds = self - .base - .receive( - &mut into_base_sink(sink), - &mut into_base_stream(stream), - &choices, - ) - .await?; + let seeds = self.base.receive(ctx, &choices).await?; let seeds: [Block; CSP] = seeds.try_into().expect("seeds should be CSP length"); @@ -128,13 +116,9 @@ where /// /// * `channel` - The channel to communicate with the receiver. /// * `count` - The number of OTs to extend. - pub async fn extend< - Si: IoSink> + Send + Unpin, - St: IoStream> + Send + Unpin, - >( + pub async fn extend( &mut self, - sink: &mut Si, - stream: &mut St, + ctx: &mut Ctx, count: usize, ) -> Result<(), SenderError> { let mut ext_sender = @@ -144,11 +128,7 @@ where let StartExtend { count: receiver_count, - } = stream - .expect_next() - .await? - .try_into_start_extend() - .map_err(SenderError::from)?; + } = ctx.io_mut().expect_next().await?; if count != receiver_count { return Err(SenderError::ConfigError( @@ -163,43 +143,21 @@ where // Receive extension matrix from the receiver. while extend.us.len() < expected_us { - let Extend { us: chunk } = stream - .expect_next() - .await? - .try_into_extend() - .map_err(SenderError::from)?; + let Extend { us: chunk } = ctx.io_mut().expect_next().await?; extend.us.extend(chunk); } - // Receive coin toss commitments from the receiver. - let commitment = stream.expect_next().await?.try_into_cointoss_commit()?; - // Extend the OTs. let mut ext_sender = Backend::spawn(move || ext_sender.extend(count, extend).map(|_| ext_sender)).await?; - // Execute coin toss protocol for consistency check. + // Sample chi_seed with coin-toss. let seed: Block = thread_rng().gen(); - let cointoss_receiver = cointoss::Receiver::new(vec![seed]); - - let (cointoss_receiver, cointoss_payload) = cointoss_receiver.reveal(commitment)?; + let chi_seed = cointoss::cointoss_receiver(ctx, vec![seed]).await?[0]; - // Send coin toss payload to the receiver. - sink.send(Message::CointossReceiverPayload(cointoss_payload)) - .await?; - - // Receive coin toss sender payload from the receiver. - let cointoss_sender_payload = stream - .expect_next() - .await? - .try_into_cointoss_sender_payload()?; - - // Receive consistency check from the receiver. - let receiver_check = stream.expect_next().await?.try_into_check()?; - - // Derive chi seed for the consistency check. - let chi_seed = cointoss_receiver.finalize(cointoss_sender_payload)?[0]; + // Receive the receiver's check. + let receiver_check = ctx.io_mut().expect_next().await?; // Check consistency of extension. let ext_sender = Backend::spawn(move || { @@ -215,35 +173,24 @@ where } } -impl Sender -where - BaseOT: CommittedOTReceiver + ProtocolMessage + Send, -{ - pub(crate) async fn reveal< - Si: IoSink> + Send + Unpin, - St: IoStream> + Send + Unpin, - >( - &mut self, - sink: &mut Si, - stream: &mut St, - ) -> Result<(), SenderError> { +impl Sender { + pub(crate) async fn reveal(&mut self, ctx: &mut Ctx) -> Result<(), SenderError> + where + BaseOT: CommittedOTReceiver, + { std::mem::replace(&mut self.state, State::Error).try_into_extension()?; // Reveal coin toss payload - let Some(payload) = self.cointoss_payload.take() else { + let Some(sender) = self.cointoss_sender.take() else { return Err(SenderError::ConfigError( "committed sender not configured".to_string(), ))?; }; - sink.send(Message::CointossSenderPayload(payload)) - .await - .map_err(SenderError::from)?; + sender.finalize(ctx).await.map_err(SenderError::from)?; // Reveal base OT choices - self.base - .reveal_choices(&mut into_base_sink(sink), &mut into_base_stream(stream)) - .await?; + self.base.reveal_choices(ctx).await?; // This sender is no longer usable, so mark it as complete. self.state = State::Complete; @@ -252,26 +199,13 @@ where } } -impl ProtocolMessage for Sender -where - BaseOT: ProtocolMessage, -{ - type Msg = Message; -} - #[async_trait] -impl OTSetup for Sender +impl OTSetup for Sender where - BaseOT: OTSetup + OTReceiver + Send, + Ctx: Context, + BaseOT: OTSetup + OTReceiver + Send + 'static, { - async fn setup< - Si: IoSink> + Send + Unpin, - St: IoStream> + Send + Unpin, - >( - &mut self, - sink: &mut Si, - stream: &mut St, - ) -> Result<(), OTError> { + async fn setup(&mut self, ctx: &mut Ctx) -> Result<(), OTError> { if self.state.is_extension() { return Ok(()); } @@ -282,65 +216,59 @@ where // If the sender is committed, we sample delta using a coin toss. let delta = if sender.config().sender_commit() { - let (cointoss_sender, commitment) = - cointoss::Sender::new(vec![thread_rng().gen()]).send(); - - sink.send(Message::CointossCommit(commitment)).await?; - let payload = stream - .expect_next() - .await? - .try_into_cointoss_receiver_payload() - .map_err(SenderError::from)?; - - let (seeds, payload) = cointoss_sender - .finalize(payload) - .map_err(SenderError::from)?; - - // Store the payload to reveal to the receiver later. - self.cointoss_payload = Some(payload); + let cointoss_seed = thread_rng().gen(); + let base = &mut self.base; + // Execute coin-toss protocol and base OT setup concurrently. + let ((seeds, cointoss_sender), _) = ctx + .try_join( + |ctx| { + async move { + cointoss::Sender::new(vec![cointoss_seed]) + .commit(ctx) + .await? + .receive(ctx) + .await + .map_err(SenderError::from) + } + .scope_boxed() + }, + |ctx| { + async move { base.setup(ctx).await.map_err(SenderError::from) } + .scope_boxed() + }, + ) + .await?; + + // Store the sender to finalize the cointoss protocol later. + self.cointoss_sender = Some(cointoss_sender); seeds[0] } else { + self.base.setup(ctx).await?; Block::random(&mut thread_rng()) }; - // Set up base OT if not already done - self.base - .setup(&mut into_base_sink(sink), &mut into_base_stream(stream)) - .await?; - self.state = State::Initialized(sender); - self._setup_with_delta(sink, stream, delta) + self._setup_with_delta(ctx, delta) .await .map_err(OTError::from) } } #[async_trait] -impl OTSender<[Block; 2]> for Sender +impl OTSender for Sender where - BaseOT: ProtocolMessage + Send, + Ctx: Context, + BaseOT: Send, { - async fn send< - Si: IoSink> + Send + Unpin, - St: IoStream> + Send + Unpin, - >( - &mut self, - sink: &mut Si, - stream: &mut St, - msgs: &[[Block; 2]], - ) -> Result<(), OTError> { + async fn send(&mut self, ctx: &mut Ctx, msgs: &[[Block; 2]]) -> Result<(), OTError> { let sender = self .state .try_as_extension_mut() .map_err(SenderError::from)?; - let derandomize = stream - .expect_next() - .await? - .try_into_derandomize() - .map_err(SenderError::from)?; + let derandomize = ctx.io_mut().expect_next().await?; let mut sender_keys = sender.keys(msgs.len()).map_err(SenderError::from)?; sender_keys @@ -350,7 +278,8 @@ where .encrypt_blocks(msgs) .map_err(SenderError::from)?; - sink.send(Message::SenderPayload(payload)) + ctx.io_mut() + .send(payload) .await .map_err(SenderError::from)?; @@ -359,17 +288,14 @@ where } #[async_trait] -impl RandomOTSender<[Block; 2]> for Sender +impl RandomOTSender for Sender where - BaseOT: ProtocolMessage + Send, + Ctx: Context, + BaseOT: Send, { - async fn send_random< - Si: IoSink> + Send + Unpin, - St: IoStream> + Send + Unpin, - >( + async fn send_random( &mut self, - _sink: &mut Si, - _stream: &mut St, + _ctx: &mut Ctx, count: usize, ) -> Result, OTError> { let sender = self @@ -383,29 +309,18 @@ where } #[async_trait] -impl OTSender<[[u8; N]; 2]> for Sender +impl OTSender for Sender where - BaseOT: ProtocolMessage + Send, + Ctx: Context, + BaseOT: Send, { - async fn send< - Si: IoSink> + Send + Unpin, - St: IoStream> + Send + Unpin, - >( - &mut self, - sink: &mut Si, - stream: &mut St, - msgs: &[[[u8; N]; 2]], - ) -> Result<(), OTError> { + async fn send(&mut self, ctx: &mut Ctx, msgs: &[[[u8; N]; 2]]) -> Result<(), OTError> { let sender = self .state .try_as_extension_mut() .map_err(SenderError::from)?; - let derandomize = stream - .expect_next() - .await? - .try_into_derandomize() - .map_err(SenderError::from)?; + let derandomize = ctx.io_mut().expect_next().await?; let mut sender_keys = sender.keys(msgs.len()).map_err(SenderError::from)?; sender_keys @@ -413,7 +328,8 @@ where .map_err(SenderError::from)?; let payload = sender_keys.encrypt_bytes(msgs).map_err(SenderError::from)?; - sink.send(Message::SenderPayload(payload)) + ctx.io_mut() + .send(payload) .await .map_err(SenderError::from)?; @@ -422,17 +338,14 @@ where } #[async_trait] -impl RandomOTSender<[[u8; N]; 2]> for Sender +impl RandomOTSender for Sender where - BaseOT: ProtocolMessage + Send, + Ctx: Context, + BaseOT: Send, { - async fn send_random< - Si: IoSink> + Send + Unpin, - St: IoStream> + Send + Unpin, - >( + async fn send_random( &mut self, - _sink: &mut Si, - _stream: &mut St, + _ctx: &mut Ctx, count: usize, ) -> Result, OTError> { let sender = self @@ -458,18 +371,12 @@ where } #[async_trait] -impl CommittedOTSender<[Block; 2]> for Sender +impl CommittedOTSender for Sender where - BaseOT: CommittedOTReceiver + ProtocolMessage + Send, + Ctx: Context, + BaseOT: CommittedOTReceiver + Send, { - async fn reveal< - Si: IoSink + Send + Unpin, - St: IoStream + Send + Unpin, - >( - &mut self, - sink: &mut Si, - stream: &mut St, - ) -> Result<(), OTError> { - self.reveal(sink, stream).await.map_err(OTError::from) + async fn reveal(&mut self, ctx: &mut Ctx) -> Result<(), OTError> { + self.reveal(ctx).await.map_err(OTError::from) } } diff --git a/ot/mpz-ot/src/kos/shared_receiver.rs b/ot/mpz-ot/src/kos/shared_receiver.rs new file mode 100644 index 00000000..9d3cb35a --- /dev/null +++ b/ot/mpz-ot/src/kos/shared_receiver.rs @@ -0,0 +1,55 @@ +use std::sync::Arc; + +use async_trait::async_trait; +use itybity::IntoBitIterator; +use mpz_common::{sync::Mutex, Context}; +use mpz_core::Block; +use serio::{stream::IoStreamExt, SinkExt}; +use utils_aio::non_blocking_backend::{Backend, NonBlockingBackend}; + +use crate::{ + kos::{Receiver, ReceiverError}, + OTError, OTReceiver, +}; + +/// A shared KOS receiver. +#[derive(Debug, Clone)] +pub struct SharedReceiver { + inner: Arc>>, +} + +impl SharedReceiver { + /// Creates a new shared receiver. + pub fn new(receiver: Receiver) -> Self { + Self { + // KOS receiver is always the leader. + inner: Arc::new(Mutex::new_leader(receiver)), + } + } +} + +#[async_trait] +impl OTReceiver for SharedReceiver +where + Ctx: Context, + BaseOT: Send, +{ + async fn receive(&mut self, ctx: &mut Ctx, choices: &[bool]) -> Result, OTError> { + let mut keys = self.inner.lock(ctx).await?.take_keys(choices.len())?; + + let choices = choices.into_lsb0_vec(); + let derandomize = keys.derandomize(&choices).map_err(ReceiverError::from)?; + + // Send derandomize message + ctx.io_mut().send(derandomize).await?; + + // Receive payload + let payload = ctx.io_mut().expect_next().await?; + + let received = + Backend::spawn(move || keys.decrypt_blocks(payload).map_err(ReceiverError::from)) + .await?; + + Ok(received) + } +} diff --git a/ot/mpz-ot/src/kos/shared_sender.rs b/ot/mpz-ot/src/kos/shared_sender.rs new file mode 100644 index 00000000..bc2c6fd7 --- /dev/null +++ b/ot/mpz-ot/src/kos/shared_sender.rs @@ -0,0 +1,51 @@ +use std::sync::Arc; + +use async_trait::async_trait; + +use mpz_common::{sync::Mutex, Context}; +use mpz_core::Block; +use serio::{stream::IoStreamExt as _, SinkExt as _}; + +use crate::{ + kos::{Sender, SenderError}, + OTError, OTReceiver, OTSender, +}; + +/// A shared KOS sender. +#[derive(Debug, Clone)] +pub struct SharedSender { + inner: Arc>>, +} + +impl SharedSender { + /// Creates a new shared sender. + pub fn new(sender: Sender) -> Self { + Self { + // KOS sender is always the follower. + inner: Arc::new(Mutex::new_follower(sender)), + } + } +} + +#[async_trait] +impl OTSender for SharedSender +where + Ctx: Context, + BaseOT: OTReceiver + Send + 'static, +{ + async fn send(&mut self, ctx: &mut Ctx, msgs: &[[Block; 2]]) -> Result<(), OTError> { + let mut keys = self.inner.lock(ctx).await?.take_keys(msgs.len())?; + + let derandomize = ctx.io_mut().expect_next().await?; + + keys.derandomize(derandomize).map_err(SenderError::from)?; + let payload = keys.encrypt_blocks(msgs).map_err(SenderError::from)?; + + ctx.io_mut() + .send(payload) + .await + .map_err(SenderError::from)?; + + Ok(()) + } +} diff --git a/ot/mpz-ot/src/lib.rs b/ot/mpz-ot/src/lib.rs index 5513966e..712c3761 100644 --- a/ot/mpz-ot/src/lib.rs +++ b/ot/mpz-ot/src/lib.rs @@ -1,19 +1,21 @@ //! Implementations of oblivious transfer protocols. -#![deny(missing_docs, unreachable_pub, unused_must_use)] -#![deny(unsafe_code)] -#![deny(clippy::all)] +#![deny( + unsafe_code, + missing_docs, + unused_imports, + unused_must_use, + unreachable_pub, + clippy::all +)] -#[cfg(feature = "actor")] -pub mod actor; pub mod chou_orlandi; #[cfg(feature = "ideal")] pub mod ideal; pub mod kos; use async_trait::async_trait; -use mpz_core::ProtocolMessage; -use utils_aio::{sink::IoSink, stream::IoStream}; +use mpz_common::Context; /// An oblivious transfer error. #[derive(Debug, thiserror::Error)] @@ -21,105 +23,81 @@ use utils_aio::{sink::IoSink, stream::IoStream}; pub enum OTError { #[error(transparent)] IOError(#[from] std::io::Error), + #[error("mutex error: {0}")] + Mutex(#[from] mpz_common::sync::MutexError), #[error("sender error: {0}")] SenderError(Box), #[error("receiver error: {0}")] ReceiverError(Box), } -// ######################################################################## -// ######################## Exclusive Reference ########################### -// ######################################################################## - /// An oblivious transfer protocol that needs to perform a one-time setup. #[async_trait] -pub trait OTSetup: ProtocolMessage { +pub trait OTSetup +where + Ctx: Context, +{ /// Runs any one-time setup for the protocol. /// /// # Arguments /// - /// * `sink` - The IO sink to the peer. - /// * `stream` - The IO stream from the peer. - async fn setup + Send + Unpin, St: IoStream + Send + Unpin>( - &mut self, - sink: &mut Si, - stream: &mut St, - ) -> Result<(), OTError>; + /// * `ctx` - The thread context. + async fn setup(&mut self, ctx: &mut Ctx) -> Result<(), OTError>; } /// An oblivious transfer sender. #[async_trait] -pub trait OTSender: ProtocolMessage +pub trait OTSender where + Ctx: Context, T: Send + Sync, { /// Obliviously transfers the messages to the receiver. /// /// # Arguments /// - /// * `sink` - The IO sink to the receiver. - /// * `stream` - The IO stream from the receiver. + /// * `ctx` - The thread context. /// * `msgs` - The messages to obliviously transfer. - async fn send + Send + Unpin, St: IoStream + Send + Unpin>( - &mut self, - sink: &mut Si, - stream: &mut St, - msgs: &[T], - ) -> Result<(), OTError>; + async fn send(&mut self, ctx: &mut Ctx, msgs: &[T]) -> Result<(), OTError>; } /// A correlated oblivious transfer sender. #[async_trait] -pub trait COTSender: ProtocolMessage +pub trait COTSender where + Ctx: Context, T: Send + Sync, { /// Obliviously transfers the correlated messages to the receiver. /// /// # Arguments /// - /// * `sink` - The IO sink to the receiver. - /// * `stream` - The IO stream from the receiver. + /// * `ctx` - The thread context. /// * `msgs` - The `0`-bit messages to use during the oblivious transfer. - async fn send_correlated< - Si: IoSink + Send + Unpin, - St: IoStream + Send + Unpin, - >( - &mut self, - sink: &mut Si, - stream: &mut St, - msgs: &[T], - ) -> Result<(), OTError>; + async fn send_correlated(&mut self, ctx: &mut Ctx, msgs: &[T]) -> Result<(), OTError>; } /// A random OT sender. #[async_trait] -pub trait RandomOTSender: ProtocolMessage +pub trait RandomOTSender where + Ctx: Context, T: Send + Sync, { /// Outputs pairs of random messages. /// /// # Arguments /// - /// * `sink` - The IO sink to the receiver. - /// * `stream` - The IO stream from the receiver. + /// * `ctx` - The thread context. /// * `count` - The number of pairs of random messages to output. - async fn send_random< - Si: IoSink + Send + Unpin, - St: IoStream + Send + Unpin, - >( - &mut self, - sink: &mut Si, - stream: &mut St, - count: usize, - ) -> Result, OTError>; + async fn send_random(&mut self, ctx: &mut Ctx, count: usize) -> Result, OTError>; } /// A random correlated oblivious transfer sender. #[async_trait] -pub trait RandomCOTSender: ProtocolMessage +pub trait RandomCOTSender where + Ctx: Context, T: Send + Sync, { /// Obliviously transfers the correlated messages to the receiver. @@ -128,24 +106,20 @@ where /// /// # Arguments /// - /// * `sink` - The IO sink to the receiver. - /// * `stream` - The IO stream from the receiver. + /// * `ctx` - The thread context. /// * `count` - The number of correlated messages to obliviously transfer. - async fn send_random_correlated< - Si: IoSink + Send + Unpin, - St: IoStream + Send + Unpin, - >( + async fn send_random_correlated( &mut self, - sink: &mut Si, - stream: &mut St, + ctx: &mut Ctx, count: usize, ) -> Result, OTError>; } /// An oblivious transfer receiver. #[async_trait] -pub trait OTReceiver: ProtocolMessage +pub trait OTReceiver where + Ctx: Context, T: Send + Sync, U: Send + Sync, { @@ -153,21 +127,16 @@ where /// /// # Arguments /// - /// * `sink` - The IO sink to the sender. - /// * `stream` - The IO stream from the sender. + /// * `ctx` - The thread context. /// * `choices` - The choices made by the receiver. - async fn receive + Send + Unpin, St: IoStream + Send + Unpin>( - &mut self, - sink: &mut Si, - stream: &mut St, - choices: &[T], - ) -> Result, OTError>; + async fn receive(&mut self, ctx: &mut Ctx, choices: &[T]) -> Result, OTError>; } /// A correlated oblivious transfer receiver. #[async_trait] -pub trait COTReceiver: ProtocolMessage +pub trait COTReceiver where + Ctx: Context, T: Send + Sync, U: Send + Sync, { @@ -175,24 +144,17 @@ where /// /// # Arguments /// - /// * `sink` - The IO sink to the sender. - /// * `stream` - The IO stream from the sender. + /// * `ctx` - The thread context. /// * `choices` - The choices made by the receiver. - async fn receive_correlated< - Si: IoSink + Send + Unpin, - St: IoStream + Send + Unpin, - >( - &mut self, - sink: &mut Si, - stream: &mut St, - choices: &[T], - ) -> Result, OTError>; + async fn receive_correlated(&mut self, ctx: &mut Ctx, choices: &[T]) + -> Result, OTError>; } /// A random OT receiver. #[async_trait] -pub trait RandomOTReceiver: ProtocolMessage +pub trait RandomOTReceiver where + Ctx: Context, T: Send + Sync, U: Send + Sync, { @@ -200,24 +162,20 @@ where /// /// # Arguments /// - /// * `sink` - The IO sink to the sender. - /// * `stream` - The IO stream from the sender. + /// * `ctx` - The thread context. /// * `count` - The number of random messages to receive. - async fn receive_random< - Si: IoSink + Send + Unpin, - St: IoStream + Send + Unpin, - >( + async fn receive_random( &mut self, - sink: &mut Si, - stream: &mut St, + ctx: &mut Ctx, count: usize, ) -> Result<(Vec, Vec), OTError>; } /// A random correlated oblivious transfer receiver. #[async_trait] -pub trait RandomCOTReceiver: ProtocolMessage +pub trait RandomCOTReceiver where + Ctx: Context, T: Send + Sync, U: Send + Sync, { @@ -227,16 +185,11 @@ where /// /// # Arguments /// - /// * `sink` - The IO sink to the sender. - /// * `stream` - The IO stream from the sender. + /// * `ctx` - The thread context. /// * `count` - The number of correlated messages to obliviously receive. - async fn receive_random_correlated< - Si: IoSink + Send + Unpin, - St: IoStream + Send + Unpin, - >( + async fn receive_random_correlated( &mut self, - sink: &mut Si, - stream: &mut St, + ctx: &mut Ctx, count: usize, ) -> Result<(Vec, Vec), OTError>; } @@ -244,8 +197,9 @@ where /// An oblivious transfer sender that is committed to its messages and can reveal them /// to the receiver to verify them. #[async_trait] -pub trait CommittedOTSender: OTSender +pub trait CommittedOTSender: OTSender where + Ctx: Context, T: Send + Sync, { /// Reveals all messages sent to the receiver. @@ -256,42 +210,31 @@ where /// /// # Arguments /// - /// * `sink` - The IO sink to the receiver. - /// * `stream` - The IO stream from the receiver. - async fn reveal + Send + Unpin, St: IoStream + Send + Unpin>( - &mut self, - sink: &mut Si, - stream: &mut St, - ) -> Result<(), OTError>; + /// * `ctx` - The thread context. + async fn reveal(&mut self, ctx: &mut Ctx) -> Result<(), OTError>; } /// An oblivious transfer sender that can verify the receiver's choices. #[async_trait] -pub trait VerifiableOTSender: OTSender +pub trait VerifiableOTSender: OTSender where + Ctx: Context, U: Send + Sync, { /// Receives the purported choices made by the receiver and verifies them. /// /// # Arguments /// - /// * `sink` - The IO sink to the receiver. - /// * `stream` - The IO stream from the receiver. - async fn verify_choices< - Si: IoSink + Send + Unpin, - St: IoStream + Send + Unpin, - >( - &mut self, - sink: &mut Si, - stream: &mut St, - ) -> Result, OTError>; + /// * `ctx` - The thread context. + async fn verify_choices(&mut self, ctx: &mut Ctx) -> Result, OTError>; } /// An oblivious transfer receiver that is committed to its choices and can reveal them /// to the sender to verify them. #[async_trait] -pub trait CommittedOTReceiver: OTReceiver +pub trait CommittedOTReceiver: OTReceiver where + Ctx: Context, T: Send + Sync, U: Send + Sync, { @@ -303,22 +246,15 @@ where /// /// # Arguments /// - /// * `sink` - The IO sink to the sender. - /// * `stream` - The IO stream from the sender. - async fn reveal_choices< - Si: IoSink + Send + Unpin, - St: IoStream + Send + Unpin, - >( - &mut self, - sink: &mut Si, - stream: &mut St, - ) -> Result<(), OTError>; + /// * `ctx` - The thread context. + async fn reveal_choices(&mut self, ctx: &mut Ctx) -> Result<(), OTError>; } /// An oblivious transfer receiver that can verify the sender's messages. #[async_trait] -pub trait VerifiableOTReceiver: OTReceiver +pub trait VerifiableOTReceiver: OTReceiver where + Ctx: Context, T: Send + Sync, U: Send + Sync, V: Send + Sync, @@ -327,149 +263,8 @@ where /// /// # Arguments /// - /// * `sink` - The IO sink to the sender. - /// * `stream` - The IO stream from the sender. + /// * `ctx` - The thread context. /// * `id` - The transfer id of the messages to verify. /// * `msgs` - The purported messages sent by the sender. - async fn verify + Send + Unpin, St: IoStream + Send + Unpin>( - &mut self, - sink: &mut Si, - stream: &mut St, - id: usize, - msgs: &[V], - ) -> Result<(), OTError>; -} - -// ######################################################################## -// ########################## Shared Reference ############################ -// ######################################################################## - -/// An oblivious transfer sender that can be used via a shared reference. -#[async_trait] -pub trait OTSenderShared { - /// Obliviously transfers the messages to the receiver. - /// - /// # Arguments - /// - /// * `id` - The unique identifier for this transfer. - /// * `msgs` - The messages to obliviously transfer. - async fn send(&self, id: &str, msgs: &[T]) -> Result<(), OTError>; -} - -/// A random oblivious transfer sender that can be used via a shared reference. -#[async_trait] -pub trait RandomOTSenderShared { - /// Outputs pairs of random messages. - /// - /// # Arguments - /// - /// * `id` - The unique identifier for this transfer. - /// * `count` - The number of pairs of random messages to output. - async fn send_random(&self, id: &str, count: usize) -> Result, OTError>; -} - -/// A correlated oblivious transfer sender that can be used via a shared reference. -#[async_trait] -pub trait COTSenderShared { - /// Obliviously transfers correlated messages to the receiver. - /// - /// # Arguments - /// - /// * `id` - The unique identifier for this transfer. - /// * `msgs` - The `0`-bit messages to use during the oblivious transfer. - async fn send_correlated(&self, id: &str, msgs: &[T]) -> Result<(), OTError>; -} - -/// A random correlated oblivious transfer sender that can be used via a shared reference. -#[async_trait] -pub trait RandomCOTSenderShared { - /// Obliviously transfers correlated messages to the receiver. - /// - /// Returns the `0`-bit messages that were obliviously transferred. - /// - /// # Arguments - /// - /// * `id` - The unique identifier for this transfer. - /// * `count` - The number of correlated messages to obliviously transfer. - async fn send_random_correlated(&self, id: &str, count: usize) -> Result, OTError>; -} - -/// An oblivious transfer receiver that can be used via a shared reference. -#[async_trait] -pub trait OTReceiverShared { - /// Obliviously receives data from the sender. - /// - /// # Arguments - /// - /// * `id` - The unique identifier for this transfer. - /// * `choices` - The choices made by the receiver. - async fn receive(&self, id: &str, choices: &[T]) -> Result, OTError>; -} - -/// A random oblivious transfer receiver that can be used via a shared reference. -#[async_trait] -pub trait RandomOTReceiverShared { - /// Outputs the choice bits and the corresponding messages. - /// - /// # Arguments - /// - /// * `id` - The unique identifier for this transfer. - /// * `count` - The number of random messages to receive. - async fn receive_random(&self, id: &str, count: usize) -> Result<(Vec, Vec), OTError>; -} - -/// A correlated oblivious transfer receiver that can be used via a shared reference. -#[async_trait] -pub trait COTReceiverShared { - /// Obliviously receives correlated messages from the sender. - /// - /// # Arguments - /// - /// * `id` - The unique identifier for this transfer. - /// * `choices` - The choices made by the receiver. - async fn receive_correlated(&self, id: &str, choices: &[T]) -> Result, OTError>; -} - -/// A random correlated oblivious transfer receiver that can be used via a shared reference. -#[async_trait] -pub trait RandomCOTReceiverShared { - /// Obliviously receives correlated messages with random choices. - /// - /// Returns a tuple of the choices and the messages, respectively. - /// - /// # Arguments - /// - /// * `id` - The unique identifier for this transfer. - /// * `count` - The number of correlated messages to obliviously receive. - async fn receive_random_correlated( - &self, - id: &str, - count: usize, - ) -> Result<(Vec, Vec), OTError>; -} - -/// An oblivious transfer sender that is committed to its messages and can reveal them -/// to the receiver to verify them. -#[async_trait] -pub trait CommittedOTSenderShared: OTSenderShared { - /// Reveals all messages sent to the receiver. - /// - /// # Warning - /// - /// Obviously, you should be sure you want to do this before calling this function! - /// - /// This reveals **ALL** messages sent to the receiver, not just those for a specific transfer. - async fn reveal(&self) -> Result<(), OTError>; -} - -/// An oblivious transfer receiver that can verify the sender's messages and can be used via a shared reference. -#[async_trait] -pub trait VerifiableOTReceiverShared: OTReceiverShared { - /// Verifies purported messages sent by the sender. - /// - /// # Arguments - /// - /// * `id` - The unique identifier for the transfer corresponding to the messages. - /// * `msgs` - The purported messages sent by the sender. - async fn verify(&self, id: &str, msgs: &[V]) -> Result<(), OTError>; + async fn verify(&mut self, ctx: &mut Ctx, id: usize, msgs: &[V]) -> Result<(), OTError>; } From 73d7cee931c175c36f8dd43b441dbc1df251a6e3 Mon Sep 17 00:00:00 2001 From: "sinu.eth" <65924192+sinui0@users.noreply.github.com> Date: Thu, 7 Mar 2024 08:39:33 -0800 Subject: [PATCH 09/39] refactor: re-organize crates (#110) --- README.md | 30 ++++++---------- Cargo.toml => crates/Cargo.toml | 34 ++++++++++-------- {clmul => crates/clmul}/Cargo.toml | 0 {clmul => crates/clmul}/LICENSE-APACHE | 0 {clmul => crates/clmul}/LICENSE-MIT | 0 {clmul => crates/clmul}/README.md | 0 {clmul => crates/clmul}/benches/clmul.rs | 0 {clmul => crates/clmul}/src/backend.rs | 0 .../clmul}/src/backend/autodetect.rs | 0 {clmul => crates/clmul}/src/backend/clmul.rs | 0 {clmul => crates/clmul}/src/backend/pmull.rs | 0 {clmul => crates/clmul}/src/backend/soft32.rs | 0 {clmul => crates/clmul}/src/backend/soft64.rs | 0 {clmul => crates/clmul}/src/lib.rs | 0 .../matrix-transpose}/Cargo.toml | 0 .../matrix-transpose}/benches/transpose.rs | 0 .../matrix-transpose}/src/lib.rs | 0 .../matrix-transpose}/src/scalar.rs | 0 .../matrix-transpose}/src/simd.rs | 0 .../mpz-circuits-macros}/Cargo.toml | 0 .../mpz-circuits-macros}/src/evaluate.rs | 0 .../mpz-circuits-macros}/src/lib.rs | 0 .../mpz-circuits-macros}/src/map.rs | 0 .../mpz-circuits-macros}/src/test.rs | 0 .../mpz-circuits-macros}/src/trace.rs | 0 .../mpz-circuits-macros}/src/traits.rs | 0 .../mpz-circuits-macros}/src/visitors.rs | 0 .../mpz-circuits}/Cargo.toml | 0 .../mpz-circuits}/benches/sha256.rs | 0 .../mpz-circuits}/circuits/bin/aes_128.bin | Bin .../mpz-circuits}/circuits/bin/sha256.bin | Bin .../circuits/bristol/adder64_reverse.txt | 0 .../circuits/bristol/aes_128_reverse.txt | 0 .../circuits/bristol/sha256_reverse.txt | 0 .../mpz-circuits}/src/bin/parse.rs | 0 .../mpz-circuits}/src/builder.rs | 0 .../mpz-circuits}/src/circuit.rs | 0 .../mpz-circuits}/src/circuits/big_num.rs | 0 .../mpz-circuits}/src/circuits/mod.rs | 0 .../mpz-circuits}/src/components.rs | 0 .../mpz-circuits}/src/lib.rs | 0 .../mpz-circuits}/src/ops/binary.rs | 0 .../mpz-circuits}/src/ops/mod.rs | 0 .../mpz-circuits}/src/ops/uint.rs | 0 .../mpz-circuits}/src/parse.rs | 0 .../mpz-circuits}/src/tracer.rs | 0 .../mpz-circuits}/src/types.rs | 0 .../mpz-cointoss-core}/Cargo.toml | 0 .../mpz-cointoss-core}/src/lib.rs | 0 .../mpz-cointoss-core}/src/msgs.rs | 0 .../mpz-cointoss-core}/src/receiver.rs | 0 .../mpz-cointoss-core}/src/sender.rs | 0 .../mpz-cointoss}/Cargo.toml | 0 .../mpz-cointoss}/src/lib.rs | 0 {mpz-common => crates/mpz-common}/Cargo.toml | 0 .../mpz-common}/src/context.rs | 0 .../mpz-common}/src/executor/mod.rs | 0 .../mpz-common}/src/executor/st.rs | 0 {mpz-common => crates/mpz-common}/src/id.rs | 0 {mpz-common => crates/mpz-common}/src/lib.rs | 0 .../mpz-common}/src/sync/mod.rs | 0 .../mpz-common}/src/sync/mutex.rs | 0 {mpz-core => crates/mpz-core}/Cargo.toml | 0 {mpz-core => crates/mpz-core}/README.md | 0 {mpz-core => crates/mpz-core}/benches/aes.rs | 0 {mpz-core => crates/mpz-core}/benches/ggm.rs | 0 {mpz-core => crates/mpz-core}/benches/lpn.rs | 0 {mpz-core => crates/mpz-core}/benches/prg.rs | 0 {mpz-core => crates/mpz-core}/src/aes.rs | 0 {mpz-core => crates/mpz-core}/src/block.rs | 0 {mpz-core => crates/mpz-core}/src/commit.rs | 0 {mpz-core => crates/mpz-core}/src/ggm_tree.rs | 0 {mpz-core => crates/mpz-core}/src/hash.rs | 0 {mpz-core => crates/mpz-core}/src/lib.rs | 0 {mpz-core => crates/mpz-core}/src/lpn.rs | 0 {mpz-core => crates/mpz-core}/src/prg.rs | 0 {mpz-core => crates/mpz-core}/src/prp.rs | 0 .../mpz-core}/src/serialize.rs | 0 {mpz-core => crates/mpz-core}/src/tkprp.rs | 0 {mpz-core => crates/mpz-core}/src/utils.rs | 0 {mpz-fields => crates/mpz-fields}/Cargo.toml | 0 .../mpz-fields}/benches/inverse_gf2_128.rs | 0 .../mpz-fields}/src/gf2_128.rs | 0 {mpz-fields => crates/mpz-fields}/src/lib.rs | 0 {mpz-fields => crates/mpz-fields}/src/p256.rs | 0 {garble => crates}/mpz-garble-core/Cargo.toml | 0 .../mpz-garble-core/benches/encoder.rs | 0 .../mpz-garble-core/benches/garble.rs | 0 .../mpz-garble-core/src/circuit.rs | 0 .../mpz-garble-core/src/encoding/encoder.rs | 0 .../mpz-garble-core/src/encoding/equality.rs | 0 .../mpz-garble-core/src/encoding/mod.rs | 0 .../mpz-garble-core/src/encoding/ops.rs | 0 .../mpz-garble-core/src/encoding/value.rs | 0 .../mpz-garble-core/src/evaluator.rs | 0 .../mpz-garble-core/src/generator.rs | 0 {garble => crates}/mpz-garble-core/src/lib.rs | 0 {garble => crates}/mpz-garble-core/src/msg.rs | 0 {garble => crates}/mpz-garble/Cargo.toml | 0 {garble => crates}/mpz-garble/benches/deap.rs | 0 {garble => crates}/mpz-garble/src/config.rs | 0 .../mpz-garble/src/evaluator/config.rs | 0 .../mpz-garble/src/evaluator/error.rs | 0 .../mpz-garble/src/evaluator/mod.rs | 0 .../mpz-garble/src/generator/config.rs | 0 .../mpz-garble/src/generator/error.rs | 0 .../mpz-garble/src/generator/mod.rs | 0 .../mpz-garble/src/internal_circuits.rs | 0 {garble => crates}/mpz-garble/src/lib.rs | 0 {garble => crates}/mpz-garble/src/memory.rs | 0 {garble => crates}/mpz-garble/src/ot.rs | 0 .../mpz-garble/src/protocol/deap/error.rs | 0 .../mpz-garble/src/protocol/deap/memory.rs | 0 .../mpz-garble/src/protocol/deap/mock.rs | 0 .../mpz-garble/src/protocol/deap/mod.rs | 0 .../mpz-garble/src/protocol/deap/vm.rs | 0 .../mpz-garble/src/protocol/mod.rs | 0 .../mpz-garble/src/threadpool.rs | 0 {garble => crates}/mpz-garble/src/value.rs | 0 .../mpz-garble/tests/offline-garble.rs | 0 .../mpz-garble/tests/semihonest.rs | 0 {ot => crates}/mpz-ot-core/Cargo.toml | 0 {ot => crates}/mpz-ot-core/benches/ot.rs | 0 {ot => crates}/mpz-ot-core/examples/ot.rs | 0 .../mpz-ot-core/src/chou_orlandi/config.rs | 0 .../mpz-ot-core/src/chou_orlandi/error.rs | 0 .../mpz-ot-core/src/chou_orlandi/mod.rs | 0 .../mpz-ot-core/src/chou_orlandi/msgs.rs | 0 .../mpz-ot-core/src/chou_orlandi/receiver.rs | 0 .../mpz-ot-core/src/chou_orlandi/sender.rs | 0 .../mpz-ot-core/src/ferret/cuckoo.rs | 0 .../mpz-ot-core/src/ferret/error.rs | 0 {ot => crates}/mpz-ot-core/src/ferret/mod.rs | 0 .../mpz-ot-core/src/ferret/mpcot/error.rs | 0 .../mpz-ot-core/src/ferret/mpcot/mod.rs | 0 .../mpz-ot-core/src/ferret/mpcot/msgs.rs | 0 .../mpz-ot-core/src/ferret/mpcot/receiver.rs | 0 .../src/ferret/mpcot/receiver_regular.rs | 0 .../mpz-ot-core/src/ferret/mpcot/sender.rs | 0 .../src/ferret/mpcot/sender_regular.rs | 0 {ot => crates}/mpz-ot-core/src/ferret/msgs.rs | 0 .../mpz-ot-core/src/ferret/receiver.rs | 0 .../mpz-ot-core/src/ferret/sender.rs | 0 .../mpz-ot-core/src/ferret/spcot/error.rs | 0 .../mpz-ot-core/src/ferret/spcot/mod.rs | 0 .../mpz-ot-core/src/ferret/spcot/msgs.rs | 0 .../mpz-ot-core/src/ferret/spcot/receiver.rs | 0 .../mpz-ot-core/src/ferret/spcot/sender.rs | 0 .../mpz-ot-core/src/ideal/ideal_cot.rs | 0 .../mpz-ot-core/src/ideal/ideal_mpcot.rs | 0 .../mpz-ot-core/src/ideal/ideal_spcot.rs | 0 {ot => crates}/mpz-ot-core/src/ideal/mod.rs | 0 {ot => crates}/mpz-ot-core/src/kos/config.rs | 0 {ot => crates}/mpz-ot-core/src/kos/error.rs | 0 {ot => crates}/mpz-ot-core/src/kos/mod.rs | 0 {ot => crates}/mpz-ot-core/src/kos/msgs.rs | 0 .../mpz-ot-core/src/kos/receiver.rs | 0 {ot => crates}/mpz-ot-core/src/kos/sender.rs | 0 {ot => crates}/mpz-ot-core/src/lib.rs | 0 {ot => crates}/mpz-ot-core/src/msgs.rs | 0 {ot => crates}/mpz-ot/Cargo.toml | 0 {ot => crates}/mpz-ot/benches/ot.rs | 0 .../mpz-ot/src/chou_orlandi/error.rs | 0 {ot => crates}/mpz-ot/src/chou_orlandi/mod.rs | 0 .../mpz-ot/src/chou_orlandi/receiver.rs | 0 .../mpz-ot/src/chou_orlandi/sender.rs | 0 {ot => crates}/mpz-ot/src/ideal/cot.rs | 0 {ot => crates}/mpz-ot/src/ideal/mod.rs | 0 {ot => crates}/mpz-ot/src/ideal/ot.rs | 0 {ot => crates}/mpz-ot/src/ideal/rcot.rs | 0 {ot => crates}/mpz-ot/src/ideal/rot.rs | 0 {ot => crates}/mpz-ot/src/kos/error.rs | 0 {ot => crates}/mpz-ot/src/kos/mod.rs | 0 {ot => crates}/mpz-ot/src/kos/receiver.rs | 0 {ot => crates}/mpz-ot/src/kos/sender.rs | 0 .../mpz-ot/src/kos/shared_receiver.rs | 0 .../mpz-ot/src/kos/shared_sender.rs | 0 {ot => crates}/mpz-ot/src/lib.rs | 0 .../mpz-share-conversion-core/Cargo.toml | 0 .../mpz-share-conversion-core/src/lib.rs | 0 .../mpz-share-conversion-core/src/msgs.rs | 0 .../mpz-share-conversion-core/src/shares.rs | 0 .../mpz-share-conversion/Cargo.toml | 0 .../mpz-share-conversion/src/config.rs | 0 .../mpz-share-conversion/src/converter.rs | 0 .../mpz-share-conversion/src/error.rs | 0 .../mpz-share-conversion/src/lib.rs | 0 .../mpz-share-conversion/src/mock.rs | 0 .../mpz-share-conversion/src/ot.rs | 0 .../mpz-share-conversion/src/receiver.rs | 0 .../mpz-share-conversion/src/sender.rs | 0 .../mpz-share-conversion/src/tape.rs | 0 .../mpz-share-conversion/tests/converter.rs | 0 tlsn-banner.png | Bin 20768 -> 0 bytes 194 files changed, 29 insertions(+), 35 deletions(-) rename Cargo.toml => crates/Cargo.toml (81%) rename {clmul => crates/clmul}/Cargo.toml (100%) rename {clmul => crates/clmul}/LICENSE-APACHE (100%) rename {clmul => crates/clmul}/LICENSE-MIT (100%) rename {clmul => crates/clmul}/README.md (100%) rename {clmul => crates/clmul}/benches/clmul.rs (100%) rename {clmul => crates/clmul}/src/backend.rs (100%) rename {clmul => crates/clmul}/src/backend/autodetect.rs (100%) rename {clmul => crates/clmul}/src/backend/clmul.rs (100%) rename {clmul => crates/clmul}/src/backend/pmull.rs (100%) rename {clmul => crates/clmul}/src/backend/soft32.rs (100%) rename {clmul => crates/clmul}/src/backend/soft64.rs (100%) rename {clmul => crates/clmul}/src/lib.rs (100%) rename {matrix-transpose => crates/matrix-transpose}/Cargo.toml (100%) rename {matrix-transpose => crates/matrix-transpose}/benches/transpose.rs (100%) rename {matrix-transpose => crates/matrix-transpose}/src/lib.rs (100%) rename {matrix-transpose => crates/matrix-transpose}/src/scalar.rs (100%) rename {matrix-transpose => crates/matrix-transpose}/src/simd.rs (100%) rename {mpz-circuits-macros => crates/mpz-circuits-macros}/Cargo.toml (100%) rename {mpz-circuits-macros => crates/mpz-circuits-macros}/src/evaluate.rs (100%) rename {mpz-circuits-macros => crates/mpz-circuits-macros}/src/lib.rs (100%) rename {mpz-circuits-macros => crates/mpz-circuits-macros}/src/map.rs (100%) rename {mpz-circuits-macros => crates/mpz-circuits-macros}/src/test.rs (100%) rename {mpz-circuits-macros => crates/mpz-circuits-macros}/src/trace.rs (100%) rename {mpz-circuits-macros => crates/mpz-circuits-macros}/src/traits.rs (100%) rename {mpz-circuits-macros => crates/mpz-circuits-macros}/src/visitors.rs (100%) rename {mpz-circuits => crates/mpz-circuits}/Cargo.toml (100%) rename {mpz-circuits => crates/mpz-circuits}/benches/sha256.rs (100%) rename {mpz-circuits => crates/mpz-circuits}/circuits/bin/aes_128.bin (100%) rename {mpz-circuits => crates/mpz-circuits}/circuits/bin/sha256.bin (100%) rename {mpz-circuits => crates/mpz-circuits}/circuits/bristol/adder64_reverse.txt (100%) rename {mpz-circuits => crates/mpz-circuits}/circuits/bristol/aes_128_reverse.txt (100%) rename {mpz-circuits => crates/mpz-circuits}/circuits/bristol/sha256_reverse.txt (100%) rename {mpz-circuits => crates/mpz-circuits}/src/bin/parse.rs (100%) rename {mpz-circuits => crates/mpz-circuits}/src/builder.rs (100%) rename {mpz-circuits => crates/mpz-circuits}/src/circuit.rs (100%) rename {mpz-circuits => crates/mpz-circuits}/src/circuits/big_num.rs (100%) rename {mpz-circuits => crates/mpz-circuits}/src/circuits/mod.rs (100%) rename {mpz-circuits => crates/mpz-circuits}/src/components.rs (100%) rename {mpz-circuits => crates/mpz-circuits}/src/lib.rs (100%) rename {mpz-circuits => crates/mpz-circuits}/src/ops/binary.rs (100%) rename {mpz-circuits => crates/mpz-circuits}/src/ops/mod.rs (100%) rename {mpz-circuits => crates/mpz-circuits}/src/ops/uint.rs (100%) rename {mpz-circuits => crates/mpz-circuits}/src/parse.rs (100%) rename {mpz-circuits => crates/mpz-circuits}/src/tracer.rs (100%) rename {mpz-circuits => crates/mpz-circuits}/src/types.rs (100%) rename {mpz-cointoss-core => crates/mpz-cointoss-core}/Cargo.toml (100%) rename {mpz-cointoss-core => crates/mpz-cointoss-core}/src/lib.rs (100%) rename {mpz-cointoss-core => crates/mpz-cointoss-core}/src/msgs.rs (100%) rename {mpz-cointoss-core => crates/mpz-cointoss-core}/src/receiver.rs (100%) rename {mpz-cointoss-core => crates/mpz-cointoss-core}/src/sender.rs (100%) rename {mpz-cointoss => crates/mpz-cointoss}/Cargo.toml (100%) rename {mpz-cointoss => crates/mpz-cointoss}/src/lib.rs (100%) rename {mpz-common => crates/mpz-common}/Cargo.toml (100%) rename {mpz-common => crates/mpz-common}/src/context.rs (100%) rename {mpz-common => crates/mpz-common}/src/executor/mod.rs (100%) rename {mpz-common => crates/mpz-common}/src/executor/st.rs (100%) rename {mpz-common => crates/mpz-common}/src/id.rs (100%) rename {mpz-common => crates/mpz-common}/src/lib.rs (100%) rename {mpz-common => crates/mpz-common}/src/sync/mod.rs (100%) rename {mpz-common => crates/mpz-common}/src/sync/mutex.rs (100%) rename {mpz-core => crates/mpz-core}/Cargo.toml (100%) rename {mpz-core => crates/mpz-core}/README.md (100%) rename {mpz-core => crates/mpz-core}/benches/aes.rs (100%) rename {mpz-core => crates/mpz-core}/benches/ggm.rs (100%) rename {mpz-core => crates/mpz-core}/benches/lpn.rs (100%) rename {mpz-core => crates/mpz-core}/benches/prg.rs (100%) rename {mpz-core => crates/mpz-core}/src/aes.rs (100%) rename {mpz-core => crates/mpz-core}/src/block.rs (100%) rename {mpz-core => crates/mpz-core}/src/commit.rs (100%) rename {mpz-core => crates/mpz-core}/src/ggm_tree.rs (100%) rename {mpz-core => crates/mpz-core}/src/hash.rs (100%) rename {mpz-core => crates/mpz-core}/src/lib.rs (100%) rename {mpz-core => crates/mpz-core}/src/lpn.rs (100%) rename {mpz-core => crates/mpz-core}/src/prg.rs (100%) rename {mpz-core => crates/mpz-core}/src/prp.rs (100%) rename {mpz-core => crates/mpz-core}/src/serialize.rs (100%) rename {mpz-core => crates/mpz-core}/src/tkprp.rs (100%) rename {mpz-core => crates/mpz-core}/src/utils.rs (100%) rename {mpz-fields => crates/mpz-fields}/Cargo.toml (100%) rename {mpz-fields => crates/mpz-fields}/benches/inverse_gf2_128.rs (100%) rename {mpz-fields => crates/mpz-fields}/src/gf2_128.rs (100%) rename {mpz-fields => crates/mpz-fields}/src/lib.rs (100%) rename {mpz-fields => crates/mpz-fields}/src/p256.rs (100%) rename {garble => crates}/mpz-garble-core/Cargo.toml (100%) rename {garble => crates}/mpz-garble-core/benches/encoder.rs (100%) rename {garble => crates}/mpz-garble-core/benches/garble.rs (100%) rename {garble => crates}/mpz-garble-core/src/circuit.rs (100%) rename {garble => crates}/mpz-garble-core/src/encoding/encoder.rs (100%) rename {garble => crates}/mpz-garble-core/src/encoding/equality.rs (100%) rename {garble => crates}/mpz-garble-core/src/encoding/mod.rs (100%) rename {garble => crates}/mpz-garble-core/src/encoding/ops.rs (100%) rename {garble => crates}/mpz-garble-core/src/encoding/value.rs (100%) rename {garble => crates}/mpz-garble-core/src/evaluator.rs (100%) rename {garble => crates}/mpz-garble-core/src/generator.rs (100%) rename {garble => crates}/mpz-garble-core/src/lib.rs (100%) rename {garble => crates}/mpz-garble-core/src/msg.rs (100%) rename {garble => crates}/mpz-garble/Cargo.toml (100%) rename {garble => crates}/mpz-garble/benches/deap.rs (100%) rename {garble => crates}/mpz-garble/src/config.rs (100%) rename {garble => crates}/mpz-garble/src/evaluator/config.rs (100%) rename {garble => crates}/mpz-garble/src/evaluator/error.rs (100%) rename {garble => crates}/mpz-garble/src/evaluator/mod.rs (100%) rename {garble => crates}/mpz-garble/src/generator/config.rs (100%) rename {garble => crates}/mpz-garble/src/generator/error.rs (100%) rename {garble => crates}/mpz-garble/src/generator/mod.rs (100%) rename {garble => crates}/mpz-garble/src/internal_circuits.rs (100%) rename {garble => crates}/mpz-garble/src/lib.rs (100%) rename {garble => crates}/mpz-garble/src/memory.rs (100%) rename {garble => crates}/mpz-garble/src/ot.rs (100%) rename {garble => crates}/mpz-garble/src/protocol/deap/error.rs (100%) rename {garble => crates}/mpz-garble/src/protocol/deap/memory.rs (100%) rename {garble => crates}/mpz-garble/src/protocol/deap/mock.rs (100%) rename {garble => crates}/mpz-garble/src/protocol/deap/mod.rs (100%) rename {garble => crates}/mpz-garble/src/protocol/deap/vm.rs (100%) rename {garble => crates}/mpz-garble/src/protocol/mod.rs (100%) rename {garble => crates}/mpz-garble/src/threadpool.rs (100%) rename {garble => crates}/mpz-garble/src/value.rs (100%) rename {garble => crates}/mpz-garble/tests/offline-garble.rs (100%) rename {garble => crates}/mpz-garble/tests/semihonest.rs (100%) rename {ot => crates}/mpz-ot-core/Cargo.toml (100%) rename {ot => crates}/mpz-ot-core/benches/ot.rs (100%) rename {ot => crates}/mpz-ot-core/examples/ot.rs (100%) rename {ot => crates}/mpz-ot-core/src/chou_orlandi/config.rs (100%) rename {ot => crates}/mpz-ot-core/src/chou_orlandi/error.rs (100%) rename {ot => crates}/mpz-ot-core/src/chou_orlandi/mod.rs (100%) rename {ot => crates}/mpz-ot-core/src/chou_orlandi/msgs.rs (100%) rename {ot => crates}/mpz-ot-core/src/chou_orlandi/receiver.rs (100%) rename {ot => crates}/mpz-ot-core/src/chou_orlandi/sender.rs (100%) rename {ot => crates}/mpz-ot-core/src/ferret/cuckoo.rs (100%) rename {ot => crates}/mpz-ot-core/src/ferret/error.rs (100%) rename {ot => crates}/mpz-ot-core/src/ferret/mod.rs (100%) rename {ot => crates}/mpz-ot-core/src/ferret/mpcot/error.rs (100%) rename {ot => crates}/mpz-ot-core/src/ferret/mpcot/mod.rs (100%) rename {ot => crates}/mpz-ot-core/src/ferret/mpcot/msgs.rs (100%) rename {ot => crates}/mpz-ot-core/src/ferret/mpcot/receiver.rs (100%) rename {ot => crates}/mpz-ot-core/src/ferret/mpcot/receiver_regular.rs (100%) rename {ot => crates}/mpz-ot-core/src/ferret/mpcot/sender.rs (100%) rename {ot => crates}/mpz-ot-core/src/ferret/mpcot/sender_regular.rs (100%) rename {ot => crates}/mpz-ot-core/src/ferret/msgs.rs (100%) rename {ot => crates}/mpz-ot-core/src/ferret/receiver.rs (100%) rename {ot => crates}/mpz-ot-core/src/ferret/sender.rs (100%) rename {ot => crates}/mpz-ot-core/src/ferret/spcot/error.rs (100%) rename {ot => crates}/mpz-ot-core/src/ferret/spcot/mod.rs (100%) rename {ot => crates}/mpz-ot-core/src/ferret/spcot/msgs.rs (100%) rename {ot => crates}/mpz-ot-core/src/ferret/spcot/receiver.rs (100%) rename {ot => crates}/mpz-ot-core/src/ferret/spcot/sender.rs (100%) rename {ot => crates}/mpz-ot-core/src/ideal/ideal_cot.rs (100%) rename {ot => crates}/mpz-ot-core/src/ideal/ideal_mpcot.rs (100%) rename {ot => crates}/mpz-ot-core/src/ideal/ideal_spcot.rs (100%) rename {ot => crates}/mpz-ot-core/src/ideal/mod.rs (100%) rename {ot => crates}/mpz-ot-core/src/kos/config.rs (100%) rename {ot => crates}/mpz-ot-core/src/kos/error.rs (100%) rename {ot => crates}/mpz-ot-core/src/kos/mod.rs (100%) rename {ot => crates}/mpz-ot-core/src/kos/msgs.rs (100%) rename {ot => crates}/mpz-ot-core/src/kos/receiver.rs (100%) rename {ot => crates}/mpz-ot-core/src/kos/sender.rs (100%) rename {ot => crates}/mpz-ot-core/src/lib.rs (100%) rename {ot => crates}/mpz-ot-core/src/msgs.rs (100%) rename {ot => crates}/mpz-ot/Cargo.toml (100%) rename {ot => crates}/mpz-ot/benches/ot.rs (100%) rename {ot => crates}/mpz-ot/src/chou_orlandi/error.rs (100%) rename {ot => crates}/mpz-ot/src/chou_orlandi/mod.rs (100%) rename {ot => crates}/mpz-ot/src/chou_orlandi/receiver.rs (100%) rename {ot => crates}/mpz-ot/src/chou_orlandi/sender.rs (100%) rename {ot => crates}/mpz-ot/src/ideal/cot.rs (100%) rename {ot => crates}/mpz-ot/src/ideal/mod.rs (100%) rename {ot => crates}/mpz-ot/src/ideal/ot.rs (100%) rename {ot => crates}/mpz-ot/src/ideal/rcot.rs (100%) rename {ot => crates}/mpz-ot/src/ideal/rot.rs (100%) rename {ot => crates}/mpz-ot/src/kos/error.rs (100%) rename {ot => crates}/mpz-ot/src/kos/mod.rs (100%) rename {ot => crates}/mpz-ot/src/kos/receiver.rs (100%) rename {ot => crates}/mpz-ot/src/kos/sender.rs (100%) rename {ot => crates}/mpz-ot/src/kos/shared_receiver.rs (100%) rename {ot => crates}/mpz-ot/src/kos/shared_sender.rs (100%) rename {ot => crates}/mpz-ot/src/lib.rs (100%) rename {share-conversion => crates}/mpz-share-conversion-core/Cargo.toml (100%) rename {share-conversion => crates}/mpz-share-conversion-core/src/lib.rs (100%) rename {share-conversion => crates}/mpz-share-conversion-core/src/msgs.rs (100%) rename {share-conversion => crates}/mpz-share-conversion-core/src/shares.rs (100%) rename {share-conversion => crates}/mpz-share-conversion/Cargo.toml (100%) rename {share-conversion => crates}/mpz-share-conversion/src/config.rs (100%) rename {share-conversion => crates}/mpz-share-conversion/src/converter.rs (100%) rename {share-conversion => crates}/mpz-share-conversion/src/error.rs (100%) rename {share-conversion => crates}/mpz-share-conversion/src/lib.rs (100%) rename {share-conversion => crates}/mpz-share-conversion/src/mock.rs (100%) rename {share-conversion => crates}/mpz-share-conversion/src/ot.rs (100%) rename {share-conversion => crates}/mpz-share-conversion/src/receiver.rs (100%) rename {share-conversion => crates}/mpz-share-conversion/src/sender.rs (100%) rename {share-conversion => crates}/mpz-share-conversion/src/tape.rs (100%) rename {share-conversion => crates}/mpz-share-conversion/tests/converter.rs (100%) delete mode 100644 tlsn-banner.png diff --git a/README.md b/README.md index d0ff2929..633a9bfc 100644 --- a/README.md +++ b/README.md @@ -14,26 +14,16 @@ This project is currently under active development and should not be used in pro ## Crates -**Core** - - `mpz-core` - Assortment of low-level primitives. - - `matrix-transpose` - Bit-wise matrix transposition. - - `clmul` - Carry-less multiplication - -**Circuits** - - `mpz-circuits` - Boolean circuit DSL - - `mpz-circuits-macros` - Proc-macros for `mpz-circuits` - -**Oblivious Transfer** - - `mpz-ot` - High-level async APIs - - `mpz-ot-core` - Low-level types for OT, and core implementations of OT protocols. - -**Garbled Circuits** - - `mpz-garble` - High-level APIs for boolean garbled circuit protocols, including VM abstractions. - - `mpz-garble-core` - Low-level types for boolean half-gate garbling algorithm. - -**Share Conversion** - - `mpz-share-conversion` - High-level APIs for Multiplicative-to-Additive and Additive-to-Multiplicative share conversion protocols for a variety of fields. - - `mpz-share-conversion-core` - Low-level types for share conversion protocols. + - [`mpz-core`](./crates/mpz-core/) - Core cryptographic primitives. + - [`mpz-common`](./crates/mpz-common) - Common functionalities needed for modeling protocol execution, I/O, and multi-threading. + - [`mpz-fields`](./crates/mpz-fields/) - Finite-fields. + - [`mpz-circuits`](./crates/mpz-circuits/) ([`macros`](./crates/mpz-circuits-macros/)) - Boolean circuit DSL. + - [`mpz-ot`](./crates/mpz-ot) ([`core`](./crates/mpz-ot-core/)) - Oblivious transfer protocols. + - [`mpz-garble`](./crates/mpz-garble/) ([`core`](./crates/mpz-garble-core/)) - Boolean garbled circuit protocols. + - [`mpz-share-conversion`](./crates/mpz-share-conversion/) ([`core`](./crates/mpz-share-conversion-core/)) - Multiplicative-to-Additive and Additive-to-Multiplicative share conversion protocols for a variety of fields. + - [`mpz-cointoss`](./crates/mpz-cointoss/) ([`core`](./crates/mpz-cointoss-core/)) - 2-party cointoss protocol. + - [`matrix-transpose`](./crates/matrix-transpose/) - Bit-wise matrix transposition. + - [`clmul`](./crates/clmul/) - Carry-less multiplication. ## License All crates in this repository are licensed under either of diff --git a/Cargo.toml b/crates/Cargo.toml similarity index 81% rename from Cargo.toml rename to crates/Cargo.toml index 71c8a684..55c61fe8 100644 --- a/Cargo.toml +++ b/crates/Cargo.toml @@ -1,17 +1,20 @@ [workspace] members = [ "mpz-core", - "garble/*", - "ot/*", + "mpz-common", + "mpz-fields", "mpz-circuits", "mpz-circuits-macros", - "mpz-fields", - "share-conversion/*", - "matrix-transpose", - "clmul", - "mpz-common", "mpz-cointoss", "mpz-cointoss-core", + "mpz-ot", + "mpz-ot-core", + "mpz-garble", + "mpz-garble-core", + "mpz-share-conversion", + "mpz-share-conversion-core", + "matrix-transpose", + "clmul", ] resolver = "2" @@ -24,16 +27,17 @@ resolver = "2" [workspace.dependencies] mpz-core = { path = "mpz-core" } mpz-common = { path = "mpz-common" } +mpz-fields = { path = "mpz-fields" } mpz-circuits = { path = "mpz-circuits" } -mpz-cointoss-core = { path = "mpz-cointoss-core" } +mpz-circuits-macros = { path = "mpz-circuits-macros" } mpz-cointoss = { path = "mpz-cointoss" } -mpz-ot-core = { path = "ot/mpz-ot-core" } -mpz-ot = { path = "ot/mpz-ot" } -mpz-garble-core = { path = "garble/mpz-garble-core" } -mpz-garble = { path = "garble/mpz-garble" } -mpz-share-conversion-core = { path = "share-conversion/mpz-share-conversion-core" } -mpz-share-conversion = { path = "share-conversion/mpz-share-conversion" } -mpz-fields = { path = "mpz-fields" } +mpz-cointoss-core = { path = "mpz-cointoss-core" } +mpz-ot = { path = "mpz-ot" } +mpz-ot-core = { path = "mpz-ot-core" } +mpz-garble = { path = "mpz-garble" } +mpz-garble-core = { path = "mpz-garble-core" } +mpz-share-conversion = { path = "mpz-share-conversion" } +mpz-share-conversion-core = { path = "mpz-share-conversion-core" } clmul = { path = "clmul" } matrix-transpose = { path = "matrix-transpose" } diff --git a/clmul/Cargo.toml b/crates/clmul/Cargo.toml similarity index 100% rename from clmul/Cargo.toml rename to crates/clmul/Cargo.toml diff --git a/clmul/LICENSE-APACHE b/crates/clmul/LICENSE-APACHE similarity index 100% rename from clmul/LICENSE-APACHE rename to crates/clmul/LICENSE-APACHE diff --git a/clmul/LICENSE-MIT b/crates/clmul/LICENSE-MIT similarity index 100% rename from clmul/LICENSE-MIT rename to crates/clmul/LICENSE-MIT diff --git a/clmul/README.md b/crates/clmul/README.md similarity index 100% rename from clmul/README.md rename to crates/clmul/README.md diff --git a/clmul/benches/clmul.rs b/crates/clmul/benches/clmul.rs similarity index 100% rename from clmul/benches/clmul.rs rename to crates/clmul/benches/clmul.rs diff --git a/clmul/src/backend.rs b/crates/clmul/src/backend.rs similarity index 100% rename from clmul/src/backend.rs rename to crates/clmul/src/backend.rs diff --git a/clmul/src/backend/autodetect.rs b/crates/clmul/src/backend/autodetect.rs similarity index 100% rename from clmul/src/backend/autodetect.rs rename to crates/clmul/src/backend/autodetect.rs diff --git a/clmul/src/backend/clmul.rs b/crates/clmul/src/backend/clmul.rs similarity index 100% rename from clmul/src/backend/clmul.rs rename to crates/clmul/src/backend/clmul.rs diff --git a/clmul/src/backend/pmull.rs b/crates/clmul/src/backend/pmull.rs similarity index 100% rename from clmul/src/backend/pmull.rs rename to crates/clmul/src/backend/pmull.rs diff --git a/clmul/src/backend/soft32.rs b/crates/clmul/src/backend/soft32.rs similarity index 100% rename from clmul/src/backend/soft32.rs rename to crates/clmul/src/backend/soft32.rs diff --git a/clmul/src/backend/soft64.rs b/crates/clmul/src/backend/soft64.rs similarity index 100% rename from clmul/src/backend/soft64.rs rename to crates/clmul/src/backend/soft64.rs diff --git a/clmul/src/lib.rs b/crates/clmul/src/lib.rs similarity index 100% rename from clmul/src/lib.rs rename to crates/clmul/src/lib.rs diff --git a/matrix-transpose/Cargo.toml b/crates/matrix-transpose/Cargo.toml similarity index 100% rename from matrix-transpose/Cargo.toml rename to crates/matrix-transpose/Cargo.toml diff --git a/matrix-transpose/benches/transpose.rs b/crates/matrix-transpose/benches/transpose.rs similarity index 100% rename from matrix-transpose/benches/transpose.rs rename to crates/matrix-transpose/benches/transpose.rs diff --git a/matrix-transpose/src/lib.rs b/crates/matrix-transpose/src/lib.rs similarity index 100% rename from matrix-transpose/src/lib.rs rename to crates/matrix-transpose/src/lib.rs diff --git a/matrix-transpose/src/scalar.rs b/crates/matrix-transpose/src/scalar.rs similarity index 100% rename from matrix-transpose/src/scalar.rs rename to crates/matrix-transpose/src/scalar.rs diff --git a/matrix-transpose/src/simd.rs b/crates/matrix-transpose/src/simd.rs similarity index 100% rename from matrix-transpose/src/simd.rs rename to crates/matrix-transpose/src/simd.rs diff --git a/mpz-circuits-macros/Cargo.toml b/crates/mpz-circuits-macros/Cargo.toml similarity index 100% rename from mpz-circuits-macros/Cargo.toml rename to crates/mpz-circuits-macros/Cargo.toml diff --git a/mpz-circuits-macros/src/evaluate.rs b/crates/mpz-circuits-macros/src/evaluate.rs similarity index 100% rename from mpz-circuits-macros/src/evaluate.rs rename to crates/mpz-circuits-macros/src/evaluate.rs diff --git a/mpz-circuits-macros/src/lib.rs b/crates/mpz-circuits-macros/src/lib.rs similarity index 100% rename from mpz-circuits-macros/src/lib.rs rename to crates/mpz-circuits-macros/src/lib.rs diff --git a/mpz-circuits-macros/src/map.rs b/crates/mpz-circuits-macros/src/map.rs similarity index 100% rename from mpz-circuits-macros/src/map.rs rename to crates/mpz-circuits-macros/src/map.rs diff --git a/mpz-circuits-macros/src/test.rs b/crates/mpz-circuits-macros/src/test.rs similarity index 100% rename from mpz-circuits-macros/src/test.rs rename to crates/mpz-circuits-macros/src/test.rs diff --git a/mpz-circuits-macros/src/trace.rs b/crates/mpz-circuits-macros/src/trace.rs similarity index 100% rename from mpz-circuits-macros/src/trace.rs rename to crates/mpz-circuits-macros/src/trace.rs diff --git a/mpz-circuits-macros/src/traits.rs b/crates/mpz-circuits-macros/src/traits.rs similarity index 100% rename from mpz-circuits-macros/src/traits.rs rename to crates/mpz-circuits-macros/src/traits.rs diff --git a/mpz-circuits-macros/src/visitors.rs b/crates/mpz-circuits-macros/src/visitors.rs similarity index 100% rename from mpz-circuits-macros/src/visitors.rs rename to crates/mpz-circuits-macros/src/visitors.rs diff --git a/mpz-circuits/Cargo.toml b/crates/mpz-circuits/Cargo.toml similarity index 100% rename from mpz-circuits/Cargo.toml rename to crates/mpz-circuits/Cargo.toml diff --git a/mpz-circuits/benches/sha256.rs b/crates/mpz-circuits/benches/sha256.rs similarity index 100% rename from mpz-circuits/benches/sha256.rs rename to crates/mpz-circuits/benches/sha256.rs diff --git a/mpz-circuits/circuits/bin/aes_128.bin b/crates/mpz-circuits/circuits/bin/aes_128.bin similarity index 100% rename from mpz-circuits/circuits/bin/aes_128.bin rename to crates/mpz-circuits/circuits/bin/aes_128.bin diff --git a/mpz-circuits/circuits/bin/sha256.bin b/crates/mpz-circuits/circuits/bin/sha256.bin similarity index 100% rename from mpz-circuits/circuits/bin/sha256.bin rename to crates/mpz-circuits/circuits/bin/sha256.bin diff --git a/mpz-circuits/circuits/bristol/adder64_reverse.txt b/crates/mpz-circuits/circuits/bristol/adder64_reverse.txt similarity index 100% rename from mpz-circuits/circuits/bristol/adder64_reverse.txt rename to crates/mpz-circuits/circuits/bristol/adder64_reverse.txt diff --git a/mpz-circuits/circuits/bristol/aes_128_reverse.txt b/crates/mpz-circuits/circuits/bristol/aes_128_reverse.txt similarity index 100% rename from mpz-circuits/circuits/bristol/aes_128_reverse.txt rename to crates/mpz-circuits/circuits/bristol/aes_128_reverse.txt diff --git a/mpz-circuits/circuits/bristol/sha256_reverse.txt b/crates/mpz-circuits/circuits/bristol/sha256_reverse.txt similarity index 100% rename from mpz-circuits/circuits/bristol/sha256_reverse.txt rename to crates/mpz-circuits/circuits/bristol/sha256_reverse.txt diff --git a/mpz-circuits/src/bin/parse.rs b/crates/mpz-circuits/src/bin/parse.rs similarity index 100% rename from mpz-circuits/src/bin/parse.rs rename to crates/mpz-circuits/src/bin/parse.rs diff --git a/mpz-circuits/src/builder.rs b/crates/mpz-circuits/src/builder.rs similarity index 100% rename from mpz-circuits/src/builder.rs rename to crates/mpz-circuits/src/builder.rs diff --git a/mpz-circuits/src/circuit.rs b/crates/mpz-circuits/src/circuit.rs similarity index 100% rename from mpz-circuits/src/circuit.rs rename to crates/mpz-circuits/src/circuit.rs diff --git a/mpz-circuits/src/circuits/big_num.rs b/crates/mpz-circuits/src/circuits/big_num.rs similarity index 100% rename from mpz-circuits/src/circuits/big_num.rs rename to crates/mpz-circuits/src/circuits/big_num.rs diff --git a/mpz-circuits/src/circuits/mod.rs b/crates/mpz-circuits/src/circuits/mod.rs similarity index 100% rename from mpz-circuits/src/circuits/mod.rs rename to crates/mpz-circuits/src/circuits/mod.rs diff --git a/mpz-circuits/src/components.rs b/crates/mpz-circuits/src/components.rs similarity index 100% rename from mpz-circuits/src/components.rs rename to crates/mpz-circuits/src/components.rs diff --git a/mpz-circuits/src/lib.rs b/crates/mpz-circuits/src/lib.rs similarity index 100% rename from mpz-circuits/src/lib.rs rename to crates/mpz-circuits/src/lib.rs diff --git a/mpz-circuits/src/ops/binary.rs b/crates/mpz-circuits/src/ops/binary.rs similarity index 100% rename from mpz-circuits/src/ops/binary.rs rename to crates/mpz-circuits/src/ops/binary.rs diff --git a/mpz-circuits/src/ops/mod.rs b/crates/mpz-circuits/src/ops/mod.rs similarity index 100% rename from mpz-circuits/src/ops/mod.rs rename to crates/mpz-circuits/src/ops/mod.rs diff --git a/mpz-circuits/src/ops/uint.rs b/crates/mpz-circuits/src/ops/uint.rs similarity index 100% rename from mpz-circuits/src/ops/uint.rs rename to crates/mpz-circuits/src/ops/uint.rs diff --git a/mpz-circuits/src/parse.rs b/crates/mpz-circuits/src/parse.rs similarity index 100% rename from mpz-circuits/src/parse.rs rename to crates/mpz-circuits/src/parse.rs diff --git a/mpz-circuits/src/tracer.rs b/crates/mpz-circuits/src/tracer.rs similarity index 100% rename from mpz-circuits/src/tracer.rs rename to crates/mpz-circuits/src/tracer.rs diff --git a/mpz-circuits/src/types.rs b/crates/mpz-circuits/src/types.rs similarity index 100% rename from mpz-circuits/src/types.rs rename to crates/mpz-circuits/src/types.rs diff --git a/mpz-cointoss-core/Cargo.toml b/crates/mpz-cointoss-core/Cargo.toml similarity index 100% rename from mpz-cointoss-core/Cargo.toml rename to crates/mpz-cointoss-core/Cargo.toml diff --git a/mpz-cointoss-core/src/lib.rs b/crates/mpz-cointoss-core/src/lib.rs similarity index 100% rename from mpz-cointoss-core/src/lib.rs rename to crates/mpz-cointoss-core/src/lib.rs diff --git a/mpz-cointoss-core/src/msgs.rs b/crates/mpz-cointoss-core/src/msgs.rs similarity index 100% rename from mpz-cointoss-core/src/msgs.rs rename to crates/mpz-cointoss-core/src/msgs.rs diff --git a/mpz-cointoss-core/src/receiver.rs b/crates/mpz-cointoss-core/src/receiver.rs similarity index 100% rename from mpz-cointoss-core/src/receiver.rs rename to crates/mpz-cointoss-core/src/receiver.rs diff --git a/mpz-cointoss-core/src/sender.rs b/crates/mpz-cointoss-core/src/sender.rs similarity index 100% rename from mpz-cointoss-core/src/sender.rs rename to crates/mpz-cointoss-core/src/sender.rs diff --git a/mpz-cointoss/Cargo.toml b/crates/mpz-cointoss/Cargo.toml similarity index 100% rename from mpz-cointoss/Cargo.toml rename to crates/mpz-cointoss/Cargo.toml diff --git a/mpz-cointoss/src/lib.rs b/crates/mpz-cointoss/src/lib.rs similarity index 100% rename from mpz-cointoss/src/lib.rs rename to crates/mpz-cointoss/src/lib.rs diff --git a/mpz-common/Cargo.toml b/crates/mpz-common/Cargo.toml similarity index 100% rename from mpz-common/Cargo.toml rename to crates/mpz-common/Cargo.toml diff --git a/mpz-common/src/context.rs b/crates/mpz-common/src/context.rs similarity index 100% rename from mpz-common/src/context.rs rename to crates/mpz-common/src/context.rs diff --git a/mpz-common/src/executor/mod.rs b/crates/mpz-common/src/executor/mod.rs similarity index 100% rename from mpz-common/src/executor/mod.rs rename to crates/mpz-common/src/executor/mod.rs diff --git a/mpz-common/src/executor/st.rs b/crates/mpz-common/src/executor/st.rs similarity index 100% rename from mpz-common/src/executor/st.rs rename to crates/mpz-common/src/executor/st.rs diff --git a/mpz-common/src/id.rs b/crates/mpz-common/src/id.rs similarity index 100% rename from mpz-common/src/id.rs rename to crates/mpz-common/src/id.rs diff --git a/mpz-common/src/lib.rs b/crates/mpz-common/src/lib.rs similarity index 100% rename from mpz-common/src/lib.rs rename to crates/mpz-common/src/lib.rs diff --git a/mpz-common/src/sync/mod.rs b/crates/mpz-common/src/sync/mod.rs similarity index 100% rename from mpz-common/src/sync/mod.rs rename to crates/mpz-common/src/sync/mod.rs diff --git a/mpz-common/src/sync/mutex.rs b/crates/mpz-common/src/sync/mutex.rs similarity index 100% rename from mpz-common/src/sync/mutex.rs rename to crates/mpz-common/src/sync/mutex.rs diff --git a/mpz-core/Cargo.toml b/crates/mpz-core/Cargo.toml similarity index 100% rename from mpz-core/Cargo.toml rename to crates/mpz-core/Cargo.toml diff --git a/mpz-core/README.md b/crates/mpz-core/README.md similarity index 100% rename from mpz-core/README.md rename to crates/mpz-core/README.md diff --git a/mpz-core/benches/aes.rs b/crates/mpz-core/benches/aes.rs similarity index 100% rename from mpz-core/benches/aes.rs rename to crates/mpz-core/benches/aes.rs diff --git a/mpz-core/benches/ggm.rs b/crates/mpz-core/benches/ggm.rs similarity index 100% rename from mpz-core/benches/ggm.rs rename to crates/mpz-core/benches/ggm.rs diff --git a/mpz-core/benches/lpn.rs b/crates/mpz-core/benches/lpn.rs similarity index 100% rename from mpz-core/benches/lpn.rs rename to crates/mpz-core/benches/lpn.rs diff --git a/mpz-core/benches/prg.rs b/crates/mpz-core/benches/prg.rs similarity index 100% rename from mpz-core/benches/prg.rs rename to crates/mpz-core/benches/prg.rs diff --git a/mpz-core/src/aes.rs b/crates/mpz-core/src/aes.rs similarity index 100% rename from mpz-core/src/aes.rs rename to crates/mpz-core/src/aes.rs diff --git a/mpz-core/src/block.rs b/crates/mpz-core/src/block.rs similarity index 100% rename from mpz-core/src/block.rs rename to crates/mpz-core/src/block.rs diff --git a/mpz-core/src/commit.rs b/crates/mpz-core/src/commit.rs similarity index 100% rename from mpz-core/src/commit.rs rename to crates/mpz-core/src/commit.rs diff --git a/mpz-core/src/ggm_tree.rs b/crates/mpz-core/src/ggm_tree.rs similarity index 100% rename from mpz-core/src/ggm_tree.rs rename to crates/mpz-core/src/ggm_tree.rs diff --git a/mpz-core/src/hash.rs b/crates/mpz-core/src/hash.rs similarity index 100% rename from mpz-core/src/hash.rs rename to crates/mpz-core/src/hash.rs diff --git a/mpz-core/src/lib.rs b/crates/mpz-core/src/lib.rs similarity index 100% rename from mpz-core/src/lib.rs rename to crates/mpz-core/src/lib.rs diff --git a/mpz-core/src/lpn.rs b/crates/mpz-core/src/lpn.rs similarity index 100% rename from mpz-core/src/lpn.rs rename to crates/mpz-core/src/lpn.rs diff --git a/mpz-core/src/prg.rs b/crates/mpz-core/src/prg.rs similarity index 100% rename from mpz-core/src/prg.rs rename to crates/mpz-core/src/prg.rs diff --git a/mpz-core/src/prp.rs b/crates/mpz-core/src/prp.rs similarity index 100% rename from mpz-core/src/prp.rs rename to crates/mpz-core/src/prp.rs diff --git a/mpz-core/src/serialize.rs b/crates/mpz-core/src/serialize.rs similarity index 100% rename from mpz-core/src/serialize.rs rename to crates/mpz-core/src/serialize.rs diff --git a/mpz-core/src/tkprp.rs b/crates/mpz-core/src/tkprp.rs similarity index 100% rename from mpz-core/src/tkprp.rs rename to crates/mpz-core/src/tkprp.rs diff --git a/mpz-core/src/utils.rs b/crates/mpz-core/src/utils.rs similarity index 100% rename from mpz-core/src/utils.rs rename to crates/mpz-core/src/utils.rs diff --git a/mpz-fields/Cargo.toml b/crates/mpz-fields/Cargo.toml similarity index 100% rename from mpz-fields/Cargo.toml rename to crates/mpz-fields/Cargo.toml diff --git a/mpz-fields/benches/inverse_gf2_128.rs b/crates/mpz-fields/benches/inverse_gf2_128.rs similarity index 100% rename from mpz-fields/benches/inverse_gf2_128.rs rename to crates/mpz-fields/benches/inverse_gf2_128.rs diff --git a/mpz-fields/src/gf2_128.rs b/crates/mpz-fields/src/gf2_128.rs similarity index 100% rename from mpz-fields/src/gf2_128.rs rename to crates/mpz-fields/src/gf2_128.rs diff --git a/mpz-fields/src/lib.rs b/crates/mpz-fields/src/lib.rs similarity index 100% rename from mpz-fields/src/lib.rs rename to crates/mpz-fields/src/lib.rs diff --git a/mpz-fields/src/p256.rs b/crates/mpz-fields/src/p256.rs similarity index 100% rename from mpz-fields/src/p256.rs rename to crates/mpz-fields/src/p256.rs diff --git a/garble/mpz-garble-core/Cargo.toml b/crates/mpz-garble-core/Cargo.toml similarity index 100% rename from garble/mpz-garble-core/Cargo.toml rename to crates/mpz-garble-core/Cargo.toml diff --git a/garble/mpz-garble-core/benches/encoder.rs b/crates/mpz-garble-core/benches/encoder.rs similarity index 100% rename from garble/mpz-garble-core/benches/encoder.rs rename to crates/mpz-garble-core/benches/encoder.rs diff --git a/garble/mpz-garble-core/benches/garble.rs b/crates/mpz-garble-core/benches/garble.rs similarity index 100% rename from garble/mpz-garble-core/benches/garble.rs rename to crates/mpz-garble-core/benches/garble.rs diff --git a/garble/mpz-garble-core/src/circuit.rs b/crates/mpz-garble-core/src/circuit.rs similarity index 100% rename from garble/mpz-garble-core/src/circuit.rs rename to crates/mpz-garble-core/src/circuit.rs diff --git a/garble/mpz-garble-core/src/encoding/encoder.rs b/crates/mpz-garble-core/src/encoding/encoder.rs similarity index 100% rename from garble/mpz-garble-core/src/encoding/encoder.rs rename to crates/mpz-garble-core/src/encoding/encoder.rs diff --git a/garble/mpz-garble-core/src/encoding/equality.rs b/crates/mpz-garble-core/src/encoding/equality.rs similarity index 100% rename from garble/mpz-garble-core/src/encoding/equality.rs rename to crates/mpz-garble-core/src/encoding/equality.rs diff --git a/garble/mpz-garble-core/src/encoding/mod.rs b/crates/mpz-garble-core/src/encoding/mod.rs similarity index 100% rename from garble/mpz-garble-core/src/encoding/mod.rs rename to crates/mpz-garble-core/src/encoding/mod.rs diff --git a/garble/mpz-garble-core/src/encoding/ops.rs b/crates/mpz-garble-core/src/encoding/ops.rs similarity index 100% rename from garble/mpz-garble-core/src/encoding/ops.rs rename to crates/mpz-garble-core/src/encoding/ops.rs diff --git a/garble/mpz-garble-core/src/encoding/value.rs b/crates/mpz-garble-core/src/encoding/value.rs similarity index 100% rename from garble/mpz-garble-core/src/encoding/value.rs rename to crates/mpz-garble-core/src/encoding/value.rs diff --git a/garble/mpz-garble-core/src/evaluator.rs b/crates/mpz-garble-core/src/evaluator.rs similarity index 100% rename from garble/mpz-garble-core/src/evaluator.rs rename to crates/mpz-garble-core/src/evaluator.rs diff --git a/garble/mpz-garble-core/src/generator.rs b/crates/mpz-garble-core/src/generator.rs similarity index 100% rename from garble/mpz-garble-core/src/generator.rs rename to crates/mpz-garble-core/src/generator.rs diff --git a/garble/mpz-garble-core/src/lib.rs b/crates/mpz-garble-core/src/lib.rs similarity index 100% rename from garble/mpz-garble-core/src/lib.rs rename to crates/mpz-garble-core/src/lib.rs diff --git a/garble/mpz-garble-core/src/msg.rs b/crates/mpz-garble-core/src/msg.rs similarity index 100% rename from garble/mpz-garble-core/src/msg.rs rename to crates/mpz-garble-core/src/msg.rs diff --git a/garble/mpz-garble/Cargo.toml b/crates/mpz-garble/Cargo.toml similarity index 100% rename from garble/mpz-garble/Cargo.toml rename to crates/mpz-garble/Cargo.toml diff --git a/garble/mpz-garble/benches/deap.rs b/crates/mpz-garble/benches/deap.rs similarity index 100% rename from garble/mpz-garble/benches/deap.rs rename to crates/mpz-garble/benches/deap.rs diff --git a/garble/mpz-garble/src/config.rs b/crates/mpz-garble/src/config.rs similarity index 100% rename from garble/mpz-garble/src/config.rs rename to crates/mpz-garble/src/config.rs diff --git a/garble/mpz-garble/src/evaluator/config.rs b/crates/mpz-garble/src/evaluator/config.rs similarity index 100% rename from garble/mpz-garble/src/evaluator/config.rs rename to crates/mpz-garble/src/evaluator/config.rs diff --git a/garble/mpz-garble/src/evaluator/error.rs b/crates/mpz-garble/src/evaluator/error.rs similarity index 100% rename from garble/mpz-garble/src/evaluator/error.rs rename to crates/mpz-garble/src/evaluator/error.rs diff --git a/garble/mpz-garble/src/evaluator/mod.rs b/crates/mpz-garble/src/evaluator/mod.rs similarity index 100% rename from garble/mpz-garble/src/evaluator/mod.rs rename to crates/mpz-garble/src/evaluator/mod.rs diff --git a/garble/mpz-garble/src/generator/config.rs b/crates/mpz-garble/src/generator/config.rs similarity index 100% rename from garble/mpz-garble/src/generator/config.rs rename to crates/mpz-garble/src/generator/config.rs diff --git a/garble/mpz-garble/src/generator/error.rs b/crates/mpz-garble/src/generator/error.rs similarity index 100% rename from garble/mpz-garble/src/generator/error.rs rename to crates/mpz-garble/src/generator/error.rs diff --git a/garble/mpz-garble/src/generator/mod.rs b/crates/mpz-garble/src/generator/mod.rs similarity index 100% rename from garble/mpz-garble/src/generator/mod.rs rename to crates/mpz-garble/src/generator/mod.rs diff --git a/garble/mpz-garble/src/internal_circuits.rs b/crates/mpz-garble/src/internal_circuits.rs similarity index 100% rename from garble/mpz-garble/src/internal_circuits.rs rename to crates/mpz-garble/src/internal_circuits.rs diff --git a/garble/mpz-garble/src/lib.rs b/crates/mpz-garble/src/lib.rs similarity index 100% rename from garble/mpz-garble/src/lib.rs rename to crates/mpz-garble/src/lib.rs diff --git a/garble/mpz-garble/src/memory.rs b/crates/mpz-garble/src/memory.rs similarity index 100% rename from garble/mpz-garble/src/memory.rs rename to crates/mpz-garble/src/memory.rs diff --git a/garble/mpz-garble/src/ot.rs b/crates/mpz-garble/src/ot.rs similarity index 100% rename from garble/mpz-garble/src/ot.rs rename to crates/mpz-garble/src/ot.rs diff --git a/garble/mpz-garble/src/protocol/deap/error.rs b/crates/mpz-garble/src/protocol/deap/error.rs similarity index 100% rename from garble/mpz-garble/src/protocol/deap/error.rs rename to crates/mpz-garble/src/protocol/deap/error.rs diff --git a/garble/mpz-garble/src/protocol/deap/memory.rs b/crates/mpz-garble/src/protocol/deap/memory.rs similarity index 100% rename from garble/mpz-garble/src/protocol/deap/memory.rs rename to crates/mpz-garble/src/protocol/deap/memory.rs diff --git a/garble/mpz-garble/src/protocol/deap/mock.rs b/crates/mpz-garble/src/protocol/deap/mock.rs similarity index 100% rename from garble/mpz-garble/src/protocol/deap/mock.rs rename to crates/mpz-garble/src/protocol/deap/mock.rs diff --git a/garble/mpz-garble/src/protocol/deap/mod.rs b/crates/mpz-garble/src/protocol/deap/mod.rs similarity index 100% rename from garble/mpz-garble/src/protocol/deap/mod.rs rename to crates/mpz-garble/src/protocol/deap/mod.rs diff --git a/garble/mpz-garble/src/protocol/deap/vm.rs b/crates/mpz-garble/src/protocol/deap/vm.rs similarity index 100% rename from garble/mpz-garble/src/protocol/deap/vm.rs rename to crates/mpz-garble/src/protocol/deap/vm.rs diff --git a/garble/mpz-garble/src/protocol/mod.rs b/crates/mpz-garble/src/protocol/mod.rs similarity index 100% rename from garble/mpz-garble/src/protocol/mod.rs rename to crates/mpz-garble/src/protocol/mod.rs diff --git a/garble/mpz-garble/src/threadpool.rs b/crates/mpz-garble/src/threadpool.rs similarity index 100% rename from garble/mpz-garble/src/threadpool.rs rename to crates/mpz-garble/src/threadpool.rs diff --git a/garble/mpz-garble/src/value.rs b/crates/mpz-garble/src/value.rs similarity index 100% rename from garble/mpz-garble/src/value.rs rename to crates/mpz-garble/src/value.rs diff --git a/garble/mpz-garble/tests/offline-garble.rs b/crates/mpz-garble/tests/offline-garble.rs similarity index 100% rename from garble/mpz-garble/tests/offline-garble.rs rename to crates/mpz-garble/tests/offline-garble.rs diff --git a/garble/mpz-garble/tests/semihonest.rs b/crates/mpz-garble/tests/semihonest.rs similarity index 100% rename from garble/mpz-garble/tests/semihonest.rs rename to crates/mpz-garble/tests/semihonest.rs diff --git a/ot/mpz-ot-core/Cargo.toml b/crates/mpz-ot-core/Cargo.toml similarity index 100% rename from ot/mpz-ot-core/Cargo.toml rename to crates/mpz-ot-core/Cargo.toml diff --git a/ot/mpz-ot-core/benches/ot.rs b/crates/mpz-ot-core/benches/ot.rs similarity index 100% rename from ot/mpz-ot-core/benches/ot.rs rename to crates/mpz-ot-core/benches/ot.rs diff --git a/ot/mpz-ot-core/examples/ot.rs b/crates/mpz-ot-core/examples/ot.rs similarity index 100% rename from ot/mpz-ot-core/examples/ot.rs rename to crates/mpz-ot-core/examples/ot.rs diff --git a/ot/mpz-ot-core/src/chou_orlandi/config.rs b/crates/mpz-ot-core/src/chou_orlandi/config.rs similarity index 100% rename from ot/mpz-ot-core/src/chou_orlandi/config.rs rename to crates/mpz-ot-core/src/chou_orlandi/config.rs diff --git a/ot/mpz-ot-core/src/chou_orlandi/error.rs b/crates/mpz-ot-core/src/chou_orlandi/error.rs similarity index 100% rename from ot/mpz-ot-core/src/chou_orlandi/error.rs rename to crates/mpz-ot-core/src/chou_orlandi/error.rs diff --git a/ot/mpz-ot-core/src/chou_orlandi/mod.rs b/crates/mpz-ot-core/src/chou_orlandi/mod.rs similarity index 100% rename from ot/mpz-ot-core/src/chou_orlandi/mod.rs rename to crates/mpz-ot-core/src/chou_orlandi/mod.rs diff --git a/ot/mpz-ot-core/src/chou_orlandi/msgs.rs b/crates/mpz-ot-core/src/chou_orlandi/msgs.rs similarity index 100% rename from ot/mpz-ot-core/src/chou_orlandi/msgs.rs rename to crates/mpz-ot-core/src/chou_orlandi/msgs.rs diff --git a/ot/mpz-ot-core/src/chou_orlandi/receiver.rs b/crates/mpz-ot-core/src/chou_orlandi/receiver.rs similarity index 100% rename from ot/mpz-ot-core/src/chou_orlandi/receiver.rs rename to crates/mpz-ot-core/src/chou_orlandi/receiver.rs diff --git a/ot/mpz-ot-core/src/chou_orlandi/sender.rs b/crates/mpz-ot-core/src/chou_orlandi/sender.rs similarity index 100% rename from ot/mpz-ot-core/src/chou_orlandi/sender.rs rename to crates/mpz-ot-core/src/chou_orlandi/sender.rs diff --git a/ot/mpz-ot-core/src/ferret/cuckoo.rs b/crates/mpz-ot-core/src/ferret/cuckoo.rs similarity index 100% rename from ot/mpz-ot-core/src/ferret/cuckoo.rs rename to crates/mpz-ot-core/src/ferret/cuckoo.rs diff --git a/ot/mpz-ot-core/src/ferret/error.rs b/crates/mpz-ot-core/src/ferret/error.rs similarity index 100% rename from ot/mpz-ot-core/src/ferret/error.rs rename to crates/mpz-ot-core/src/ferret/error.rs diff --git a/ot/mpz-ot-core/src/ferret/mod.rs b/crates/mpz-ot-core/src/ferret/mod.rs similarity index 100% rename from ot/mpz-ot-core/src/ferret/mod.rs rename to crates/mpz-ot-core/src/ferret/mod.rs diff --git a/ot/mpz-ot-core/src/ferret/mpcot/error.rs b/crates/mpz-ot-core/src/ferret/mpcot/error.rs similarity index 100% rename from ot/mpz-ot-core/src/ferret/mpcot/error.rs rename to crates/mpz-ot-core/src/ferret/mpcot/error.rs diff --git a/ot/mpz-ot-core/src/ferret/mpcot/mod.rs b/crates/mpz-ot-core/src/ferret/mpcot/mod.rs similarity index 100% rename from ot/mpz-ot-core/src/ferret/mpcot/mod.rs rename to crates/mpz-ot-core/src/ferret/mpcot/mod.rs diff --git a/ot/mpz-ot-core/src/ferret/mpcot/msgs.rs b/crates/mpz-ot-core/src/ferret/mpcot/msgs.rs similarity index 100% rename from ot/mpz-ot-core/src/ferret/mpcot/msgs.rs rename to crates/mpz-ot-core/src/ferret/mpcot/msgs.rs diff --git a/ot/mpz-ot-core/src/ferret/mpcot/receiver.rs b/crates/mpz-ot-core/src/ferret/mpcot/receiver.rs similarity index 100% rename from ot/mpz-ot-core/src/ferret/mpcot/receiver.rs rename to crates/mpz-ot-core/src/ferret/mpcot/receiver.rs diff --git a/ot/mpz-ot-core/src/ferret/mpcot/receiver_regular.rs b/crates/mpz-ot-core/src/ferret/mpcot/receiver_regular.rs similarity index 100% rename from ot/mpz-ot-core/src/ferret/mpcot/receiver_regular.rs rename to crates/mpz-ot-core/src/ferret/mpcot/receiver_regular.rs diff --git a/ot/mpz-ot-core/src/ferret/mpcot/sender.rs b/crates/mpz-ot-core/src/ferret/mpcot/sender.rs similarity index 100% rename from ot/mpz-ot-core/src/ferret/mpcot/sender.rs rename to crates/mpz-ot-core/src/ferret/mpcot/sender.rs diff --git a/ot/mpz-ot-core/src/ferret/mpcot/sender_regular.rs b/crates/mpz-ot-core/src/ferret/mpcot/sender_regular.rs similarity index 100% rename from ot/mpz-ot-core/src/ferret/mpcot/sender_regular.rs rename to crates/mpz-ot-core/src/ferret/mpcot/sender_regular.rs diff --git a/ot/mpz-ot-core/src/ferret/msgs.rs b/crates/mpz-ot-core/src/ferret/msgs.rs similarity index 100% rename from ot/mpz-ot-core/src/ferret/msgs.rs rename to crates/mpz-ot-core/src/ferret/msgs.rs diff --git a/ot/mpz-ot-core/src/ferret/receiver.rs b/crates/mpz-ot-core/src/ferret/receiver.rs similarity index 100% rename from ot/mpz-ot-core/src/ferret/receiver.rs rename to crates/mpz-ot-core/src/ferret/receiver.rs diff --git a/ot/mpz-ot-core/src/ferret/sender.rs b/crates/mpz-ot-core/src/ferret/sender.rs similarity index 100% rename from ot/mpz-ot-core/src/ferret/sender.rs rename to crates/mpz-ot-core/src/ferret/sender.rs diff --git a/ot/mpz-ot-core/src/ferret/spcot/error.rs b/crates/mpz-ot-core/src/ferret/spcot/error.rs similarity index 100% rename from ot/mpz-ot-core/src/ferret/spcot/error.rs rename to crates/mpz-ot-core/src/ferret/spcot/error.rs diff --git a/ot/mpz-ot-core/src/ferret/spcot/mod.rs b/crates/mpz-ot-core/src/ferret/spcot/mod.rs similarity index 100% rename from ot/mpz-ot-core/src/ferret/spcot/mod.rs rename to crates/mpz-ot-core/src/ferret/spcot/mod.rs diff --git a/ot/mpz-ot-core/src/ferret/spcot/msgs.rs b/crates/mpz-ot-core/src/ferret/spcot/msgs.rs similarity index 100% rename from ot/mpz-ot-core/src/ferret/spcot/msgs.rs rename to crates/mpz-ot-core/src/ferret/spcot/msgs.rs diff --git a/ot/mpz-ot-core/src/ferret/spcot/receiver.rs b/crates/mpz-ot-core/src/ferret/spcot/receiver.rs similarity index 100% rename from ot/mpz-ot-core/src/ferret/spcot/receiver.rs rename to crates/mpz-ot-core/src/ferret/spcot/receiver.rs diff --git a/ot/mpz-ot-core/src/ferret/spcot/sender.rs b/crates/mpz-ot-core/src/ferret/spcot/sender.rs similarity index 100% rename from ot/mpz-ot-core/src/ferret/spcot/sender.rs rename to crates/mpz-ot-core/src/ferret/spcot/sender.rs diff --git a/ot/mpz-ot-core/src/ideal/ideal_cot.rs b/crates/mpz-ot-core/src/ideal/ideal_cot.rs similarity index 100% rename from ot/mpz-ot-core/src/ideal/ideal_cot.rs rename to crates/mpz-ot-core/src/ideal/ideal_cot.rs diff --git a/ot/mpz-ot-core/src/ideal/ideal_mpcot.rs b/crates/mpz-ot-core/src/ideal/ideal_mpcot.rs similarity index 100% rename from ot/mpz-ot-core/src/ideal/ideal_mpcot.rs rename to crates/mpz-ot-core/src/ideal/ideal_mpcot.rs diff --git a/ot/mpz-ot-core/src/ideal/ideal_spcot.rs b/crates/mpz-ot-core/src/ideal/ideal_spcot.rs similarity index 100% rename from ot/mpz-ot-core/src/ideal/ideal_spcot.rs rename to crates/mpz-ot-core/src/ideal/ideal_spcot.rs diff --git a/ot/mpz-ot-core/src/ideal/mod.rs b/crates/mpz-ot-core/src/ideal/mod.rs similarity index 100% rename from ot/mpz-ot-core/src/ideal/mod.rs rename to crates/mpz-ot-core/src/ideal/mod.rs diff --git a/ot/mpz-ot-core/src/kos/config.rs b/crates/mpz-ot-core/src/kos/config.rs similarity index 100% rename from ot/mpz-ot-core/src/kos/config.rs rename to crates/mpz-ot-core/src/kos/config.rs diff --git a/ot/mpz-ot-core/src/kos/error.rs b/crates/mpz-ot-core/src/kos/error.rs similarity index 100% rename from ot/mpz-ot-core/src/kos/error.rs rename to crates/mpz-ot-core/src/kos/error.rs diff --git a/ot/mpz-ot-core/src/kos/mod.rs b/crates/mpz-ot-core/src/kos/mod.rs similarity index 100% rename from ot/mpz-ot-core/src/kos/mod.rs rename to crates/mpz-ot-core/src/kos/mod.rs diff --git a/ot/mpz-ot-core/src/kos/msgs.rs b/crates/mpz-ot-core/src/kos/msgs.rs similarity index 100% rename from ot/mpz-ot-core/src/kos/msgs.rs rename to crates/mpz-ot-core/src/kos/msgs.rs diff --git a/ot/mpz-ot-core/src/kos/receiver.rs b/crates/mpz-ot-core/src/kos/receiver.rs similarity index 100% rename from ot/mpz-ot-core/src/kos/receiver.rs rename to crates/mpz-ot-core/src/kos/receiver.rs diff --git a/ot/mpz-ot-core/src/kos/sender.rs b/crates/mpz-ot-core/src/kos/sender.rs similarity index 100% rename from ot/mpz-ot-core/src/kos/sender.rs rename to crates/mpz-ot-core/src/kos/sender.rs diff --git a/ot/mpz-ot-core/src/lib.rs b/crates/mpz-ot-core/src/lib.rs similarity index 100% rename from ot/mpz-ot-core/src/lib.rs rename to crates/mpz-ot-core/src/lib.rs diff --git a/ot/mpz-ot-core/src/msgs.rs b/crates/mpz-ot-core/src/msgs.rs similarity index 100% rename from ot/mpz-ot-core/src/msgs.rs rename to crates/mpz-ot-core/src/msgs.rs diff --git a/ot/mpz-ot/Cargo.toml b/crates/mpz-ot/Cargo.toml similarity index 100% rename from ot/mpz-ot/Cargo.toml rename to crates/mpz-ot/Cargo.toml diff --git a/ot/mpz-ot/benches/ot.rs b/crates/mpz-ot/benches/ot.rs similarity index 100% rename from ot/mpz-ot/benches/ot.rs rename to crates/mpz-ot/benches/ot.rs diff --git a/ot/mpz-ot/src/chou_orlandi/error.rs b/crates/mpz-ot/src/chou_orlandi/error.rs similarity index 100% rename from ot/mpz-ot/src/chou_orlandi/error.rs rename to crates/mpz-ot/src/chou_orlandi/error.rs diff --git a/ot/mpz-ot/src/chou_orlandi/mod.rs b/crates/mpz-ot/src/chou_orlandi/mod.rs similarity index 100% rename from ot/mpz-ot/src/chou_orlandi/mod.rs rename to crates/mpz-ot/src/chou_orlandi/mod.rs diff --git a/ot/mpz-ot/src/chou_orlandi/receiver.rs b/crates/mpz-ot/src/chou_orlandi/receiver.rs similarity index 100% rename from ot/mpz-ot/src/chou_orlandi/receiver.rs rename to crates/mpz-ot/src/chou_orlandi/receiver.rs diff --git a/ot/mpz-ot/src/chou_orlandi/sender.rs b/crates/mpz-ot/src/chou_orlandi/sender.rs similarity index 100% rename from ot/mpz-ot/src/chou_orlandi/sender.rs rename to crates/mpz-ot/src/chou_orlandi/sender.rs diff --git a/ot/mpz-ot/src/ideal/cot.rs b/crates/mpz-ot/src/ideal/cot.rs similarity index 100% rename from ot/mpz-ot/src/ideal/cot.rs rename to crates/mpz-ot/src/ideal/cot.rs diff --git a/ot/mpz-ot/src/ideal/mod.rs b/crates/mpz-ot/src/ideal/mod.rs similarity index 100% rename from ot/mpz-ot/src/ideal/mod.rs rename to crates/mpz-ot/src/ideal/mod.rs diff --git a/ot/mpz-ot/src/ideal/ot.rs b/crates/mpz-ot/src/ideal/ot.rs similarity index 100% rename from ot/mpz-ot/src/ideal/ot.rs rename to crates/mpz-ot/src/ideal/ot.rs diff --git a/ot/mpz-ot/src/ideal/rcot.rs b/crates/mpz-ot/src/ideal/rcot.rs similarity index 100% rename from ot/mpz-ot/src/ideal/rcot.rs rename to crates/mpz-ot/src/ideal/rcot.rs diff --git a/ot/mpz-ot/src/ideal/rot.rs b/crates/mpz-ot/src/ideal/rot.rs similarity index 100% rename from ot/mpz-ot/src/ideal/rot.rs rename to crates/mpz-ot/src/ideal/rot.rs diff --git a/ot/mpz-ot/src/kos/error.rs b/crates/mpz-ot/src/kos/error.rs similarity index 100% rename from ot/mpz-ot/src/kos/error.rs rename to crates/mpz-ot/src/kos/error.rs diff --git a/ot/mpz-ot/src/kos/mod.rs b/crates/mpz-ot/src/kos/mod.rs similarity index 100% rename from ot/mpz-ot/src/kos/mod.rs rename to crates/mpz-ot/src/kos/mod.rs diff --git a/ot/mpz-ot/src/kos/receiver.rs b/crates/mpz-ot/src/kos/receiver.rs similarity index 100% rename from ot/mpz-ot/src/kos/receiver.rs rename to crates/mpz-ot/src/kos/receiver.rs diff --git a/ot/mpz-ot/src/kos/sender.rs b/crates/mpz-ot/src/kos/sender.rs similarity index 100% rename from ot/mpz-ot/src/kos/sender.rs rename to crates/mpz-ot/src/kos/sender.rs diff --git a/ot/mpz-ot/src/kos/shared_receiver.rs b/crates/mpz-ot/src/kos/shared_receiver.rs similarity index 100% rename from ot/mpz-ot/src/kos/shared_receiver.rs rename to crates/mpz-ot/src/kos/shared_receiver.rs diff --git a/ot/mpz-ot/src/kos/shared_sender.rs b/crates/mpz-ot/src/kos/shared_sender.rs similarity index 100% rename from ot/mpz-ot/src/kos/shared_sender.rs rename to crates/mpz-ot/src/kos/shared_sender.rs diff --git a/ot/mpz-ot/src/lib.rs b/crates/mpz-ot/src/lib.rs similarity index 100% rename from ot/mpz-ot/src/lib.rs rename to crates/mpz-ot/src/lib.rs diff --git a/share-conversion/mpz-share-conversion-core/Cargo.toml b/crates/mpz-share-conversion-core/Cargo.toml similarity index 100% rename from share-conversion/mpz-share-conversion-core/Cargo.toml rename to crates/mpz-share-conversion-core/Cargo.toml diff --git a/share-conversion/mpz-share-conversion-core/src/lib.rs b/crates/mpz-share-conversion-core/src/lib.rs similarity index 100% rename from share-conversion/mpz-share-conversion-core/src/lib.rs rename to crates/mpz-share-conversion-core/src/lib.rs diff --git a/share-conversion/mpz-share-conversion-core/src/msgs.rs b/crates/mpz-share-conversion-core/src/msgs.rs similarity index 100% rename from share-conversion/mpz-share-conversion-core/src/msgs.rs rename to crates/mpz-share-conversion-core/src/msgs.rs diff --git a/share-conversion/mpz-share-conversion-core/src/shares.rs b/crates/mpz-share-conversion-core/src/shares.rs similarity index 100% rename from share-conversion/mpz-share-conversion-core/src/shares.rs rename to crates/mpz-share-conversion-core/src/shares.rs diff --git a/share-conversion/mpz-share-conversion/Cargo.toml b/crates/mpz-share-conversion/Cargo.toml similarity index 100% rename from share-conversion/mpz-share-conversion/Cargo.toml rename to crates/mpz-share-conversion/Cargo.toml diff --git a/share-conversion/mpz-share-conversion/src/config.rs b/crates/mpz-share-conversion/src/config.rs similarity index 100% rename from share-conversion/mpz-share-conversion/src/config.rs rename to crates/mpz-share-conversion/src/config.rs diff --git a/share-conversion/mpz-share-conversion/src/converter.rs b/crates/mpz-share-conversion/src/converter.rs similarity index 100% rename from share-conversion/mpz-share-conversion/src/converter.rs rename to crates/mpz-share-conversion/src/converter.rs diff --git a/share-conversion/mpz-share-conversion/src/error.rs b/crates/mpz-share-conversion/src/error.rs similarity index 100% rename from share-conversion/mpz-share-conversion/src/error.rs rename to crates/mpz-share-conversion/src/error.rs diff --git a/share-conversion/mpz-share-conversion/src/lib.rs b/crates/mpz-share-conversion/src/lib.rs similarity index 100% rename from share-conversion/mpz-share-conversion/src/lib.rs rename to crates/mpz-share-conversion/src/lib.rs diff --git a/share-conversion/mpz-share-conversion/src/mock.rs b/crates/mpz-share-conversion/src/mock.rs similarity index 100% rename from share-conversion/mpz-share-conversion/src/mock.rs rename to crates/mpz-share-conversion/src/mock.rs diff --git a/share-conversion/mpz-share-conversion/src/ot.rs b/crates/mpz-share-conversion/src/ot.rs similarity index 100% rename from share-conversion/mpz-share-conversion/src/ot.rs rename to crates/mpz-share-conversion/src/ot.rs diff --git a/share-conversion/mpz-share-conversion/src/receiver.rs b/crates/mpz-share-conversion/src/receiver.rs similarity index 100% rename from share-conversion/mpz-share-conversion/src/receiver.rs rename to crates/mpz-share-conversion/src/receiver.rs diff --git a/share-conversion/mpz-share-conversion/src/sender.rs b/crates/mpz-share-conversion/src/sender.rs similarity index 100% rename from share-conversion/mpz-share-conversion/src/sender.rs rename to crates/mpz-share-conversion/src/sender.rs diff --git a/share-conversion/mpz-share-conversion/src/tape.rs b/crates/mpz-share-conversion/src/tape.rs similarity index 100% rename from share-conversion/mpz-share-conversion/src/tape.rs rename to crates/mpz-share-conversion/src/tape.rs diff --git a/share-conversion/mpz-share-conversion/tests/converter.rs b/crates/mpz-share-conversion/tests/converter.rs similarity index 100% rename from share-conversion/mpz-share-conversion/tests/converter.rs rename to crates/mpz-share-conversion/tests/converter.rs diff --git a/tlsn-banner.png b/tlsn-banner.png deleted file mode 100644 index 7ef31c6eb77440b4bd24bd452ade815209a840ec..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 20768 zcmeHPc~n!^)=#UIs-PgsJXr@&1f_r=vlA$YSfMfqf}jLZjEq61M1562MAQ;2Q=k|I z2M|%2i36jS0D=UWf<$HrMj}%fzDv%zVB2qf|GlrTeaTuZ*2&#DXP>=)`?vQw_nsSe z=%9(vGO1-43`S`GzCDLAnB}z?%;K}(E9g0y#}eo2gFo(d5`)L%RZpEg?d@{>+(}iO7dDQiCxyW%VD|6XY2_b3*hYvD=LA=< z$HoHjGKQ-s>O>{9oc3()oVxI)_s5)d%O6K1r{7Pem%AL@i8sBs*!~yVt=(NFKL=FZ z?_Iy@IjxpdaO9rl&9hIC+4hE=2%sApf786Rusf(2lxDlv`*KS1;x)v@mxRlD_z< z!Z%;(e{pfsx4mC2H23W^TDj0NTK09oLJM>F-!o)#K2SDEP4mZlo{g>V)Ub^lH}X`8 zgoH#W*|JKmCo;kA%lGW75Ub#1+-e^k!4YPw zdZ`0u?534usqT~DCnq)n8!Ry&2qiV0>nihnf2HQU31c=5XDAnkYZ0xP8T@JOu{q!% z9}#m=*Z7iT&bM=oB(*csoL4pl51FzAf-(0)uMRHcfV;H3#Z+&fHm5vpcixIQF${4K zSp8X&P01Z~)#)aA>HziLk$Y_JFj++2c1l1^Sj2Fgo#Q$F@y2s`Ue_3-fM`)2Yr&u8 zcs^*zO?B6l%g34>NYG%XdA|! z<$LVnJm`z8VT{r}8~btuy5_KteD(nM5_g_s2^^H;#3|Oq%HeT^oBi4!Z$B9S&Y*V; zc)!vFI9}$-=q8Wdeud149i9wXY3G5-=(_Emtx?5bY$K*9fSrkl)j;UlV#fzZocmrx z`j4}unV(oAE)A89Yl8uTh~?{n$@|NDe^|%7rA#WP&zwE&v-PNixw$z-5sZ7t1Q^Yz zO_I=>?fLnn{539~Q}!$EJf#QB;E*CJ5xc{~lruJ3N{geH#oN}K)_^XO%9rvWOe~&_ja~Kzyz6=4jI`{qf=}hlM!L95vA6GDM`KYbg3w9j(**#th>D&QTB%nD^rWF zc|u9s;Apk3k1fJy+7p|+2i|&iZ_1h1R{;n_y~xPHmiJ83D~7Z}Hm6!7SOoweVZMP* zv+5=X+Xa2j97w^L;}6IfKIO;&WiQ_V%I-_c&)-Da+7}UAs8!L=8cFfpW7fAH$OtZi z!!#o1cljJnVSmgt&kov;wYnGm<`$5V*aZSyp}5LJ^jBn%p!ZKtGw;`9V-kVCp9zZq ze^0%t%1NzgYsm~x(0Xu96#H~uLIEOTYO5^vw=gcNN%$x|E8=Mw6P>S96r`AT<0p1u zl;ygeHyq-ehhCjjbLCW`nrNE>O^6I<1Vc7&pJEoN+KX^Bp$$OH=EonGX* zF#BH{NR18mUfr88f{xXp4>_u6xq6y;*qrsxj}+WiKW&GCp=demV=T#qwLcplh(jQ? zhx_x>H%OM4`}hk$@*MtwaySg>yE8dKt5h=vU)JPe9Fw@1C-e*lk)Un*f50Ud3Q4T5 zxF#!l+FJE$)?kywRh^!_l*5})OgXLtn36c5-mJKnfU_9P|J<)V^0O@(03Vg1#%sO$ z2Y+Gb&wTdeUL%M1St>?DFGVE+I5>q?8*(3y_dC!{7_qF|+97AqS)T$Sg1NlY+uL%B z;~Pn?A1?B3TaO9ChNuhPKvxT<)TJ1g_pdQyzDN8tag&yQL>Ud&J8(uyPF^kl>OER7 z>zFsxtUbVahboKa8l~P3w)ISwhjke(uCY8!y~PYhtD75~ja02?d3@e*q)@i+^eeYG z?Mw)6;$_Gi=^}64H;_~ZLrwfV!k;L|l-;gdX9k1JO$qHq-TlPr`~7w@NKC8EMM7$7 zDmo!4m=u$YWoJt~>vB_dS&TYy#Qdn;4vj%qYo6_Xys3`SBC3l!Ca##U?E$Jw!3N-* zbWvGvi}0;&?b6f5`gI1B1p(;2^mWmu8^nBRSFiZB3)Ah}*HlDG{ur=|2Nt6?2+D?J z5~(|H{MT=?hZFzEElJ(bMg2{A*??PK<44ObdUuncmk-rLZG}3oA*cC>Bgnf# zjD^T?b8@*Z=@0<8(x@6*M&n_sJB0&cYhDy|`5#xW`~@Wvf5?AR?fGA6*lM_v*yckb zYZ;8dyAqdt2M9H3}%3;RU;!FyJAKyWLy@L+ZUgN!|scMUW^C)!UgoE?qDOf-$z6ZgSj2v!{>Q=-+?rPWp$P?pxytPSVrSS&qrn&)u(O1W_Bl`=AK zv{uLkxa=DSDMXOu-Uo69FxNI2m^nZbtr$Ry&-R$VVh#QmfQvsQKd1e@HmdlD{ofHw zO!@R?hTf@Iqh}oebHc0{$gt0TIN$Yz?qXY0o;T7iz^uG+0bOQ?tb^IsWT-kfM5M)U z@Y;39{2htY@0O#LN0AB?xzx=y^xsVSY%d=u=l__qnwKhwv%BFKNdeOx$$2c2gJ+fF z=ZdRaix0z%lxMRrHEmm8GLxX_+_yp6nPEuCLVE~BFaPUUNS9I2r-GXDXzARFdjc!a zHP?DrLO4}Uzf56VTfTMZD&hQK61~{IOJp(owWFLWtgH6zg5`?H zm6h_5y2HWS3No8yEM_Z4P)jX^i!`PFFhz3YoR)J^kus7>XldpI3#;%zW_2!afG`Wf z#*i8ER&*mr1MZSxG?_;k+~e`oM_QwLAKm&k@vLpMXcgE9I%J6yjH~HwkCZceTjaQo z`iI~=YK@>V8tz=7&a`O{ix#t=;0%rg%x%wOFtrM?W^iMW@qs!@6^n7;YI#1tVjxkU zCg%wIIMjpoQA8zth^w>uoN|}<>t}Ur27p%oi}&kHOf7idV*2C3iWao^Y=ZfZE}v$r zGp7svcM3Sk%$|$Cao+31F2ktP->TiYm?V7h+%~rz7sXCRky5{#y+BHhwevW2>f19> z_RGGTR9n4s!)mcLrVg+6YW|eh)yZnk<@zwj20n}Hwd53iMO+M70)SvC1UhJ~`dz8H z9)=0Hwhu->Xhr@0Cdu!){`YrR{;mT))CruMtCjx5_-){jKvt<3_$#Q`oDzyXrUFN#5picRX z&TaKn+Wqq7ohXdoKf}!bd?4{>I2T8}51)NdOCbOMf&A*Otcl!n1J43r_}OH^*?-8F z$9+fVuBA_Q^~*DhS5j~5U)q3gNz`{4Da}T5g^d?uwn$TTc9c6Pxh4O>5Y^Q}p>x`z zL~6D*Pc5)~m)`iZa*!X8PKdK>cq#pW*ZWS2C-V1B-Np-_IV@hg=p&iik&{)?(qj;- zzsPCrFLCNLp&J1(jub!zKaRr4YP?ng$rz>EIIn(}KYZtx``91^|;FIt? z5-@)t;eX9 zLv(<*FELZfr@5n%Pl5xnHBMEsHVnf+-eVOH7xOEiFDgJI{M%WLkpH`^c_WqIvHx7jh?O z8Cmpor(2qE>3i;62y*&U)sd46U~=QEK;#qM@(v*#K|Qg()x2J7ajrVm1Qv>U@*ebbMFOM zeg=!h2CygFdL=Pj=V@;DF}e=wBaJT)(qm+n z@Sj9)Lcr=khry4FYXz228UYE@FV zU!tvPzbjAhgVC-`;jiE8NV0N|=N*(_39nKx+NZET4R<}RF4p^m-l9I1Bi=BJUO;9H zCvZmVzu1kATE67VYU9Jj-ytF22|VfxjANuK@w=Bi@P7(HgPLhe%V6O|!_uixEnKh` zxHkI|)Oj{f(=4}IDt?qx&%wEbBuDAM^Q@%fX1M+c`(`}nOi&>Gx;U_BNCecyJ8f%QgnA5) zLaU6XIB#mi$sb4n$GU181mO!9Y_hX;@4nsQYkYQ4N?Xi=Of~(JNM11EyA?8qWSw>5 z-R&x+-TLe1XPpQ~(jt3EhdO7(>!b{M^y>)cc#r&9#DZKL;V39;kx!z&cRQ${$5uMkG+hdNL!@Xl|z{ zhj%odm7X{MO{ni>ySLd|kG7a4)IIVW))l#~=y(V1Wj{KQ19f`aifazYlx}v5FUvkP zwhzTF=_J6eM(bUb;2$k ztn=SKt>bH4&-EE;N6ujWN#wxs3<+sJA;d85Fx6l6T$Xpb_0O1EY7^5KfQdTXSYpMEOab*4!( z9)-&ggp0Y$XHp4|Fm4VEN?z-u=b$rghO|(tA*XjIf?9R?C@DuZw+4F9Cd%?H;^MU97;kIOZ4!Xh|FqIID3MI3<^Bs1tH)T zKt9tfjl9Fb*SOlFMOUgO)e()-N(h0ZzBYp1noCz|QfcWKzr4$>d#4@?Eu&x!=R|tw z$2Hm_7M`K*-aV4QWwuQ@qrqbj(}&%Qt1-CFt1}4ixjQ?%>mX1;!S(@l@b}w?<-)Ah zy))EF9==$@YO^lXGWjkbN*_l|{Iu&#yZ%ib7u&NzW7}4QoLBP&CuEFNp=DIM#JLAc znN{K$>IThstBY@(w4GN50>RES!z$9ZMZgjp^mFzIojDkdvxFJu0}0S^t=9?}s<76u zo@oMmCqnKBp`ysI)Px4^LV0amVYdmbbi7z`-o7Xv_KRn>M_R_5y+a${PYS2lP+gQz zeOai!1NG*Cyc{=W=g5%_tLn*`w+!Ti+DB&@YKd5*s@+>FXneWDoW+BuRy5K1Y%{z{5B?(5LO1eMj5r zXJvVr2ow**VN_Ebs|~Tf`b`~XOlygu$jgcv)FvGQaFC}DPj}cHFd#(hFbTnrG8E_X zB5)AK5LS7Q5iK`04ojFOh=_>vP$jR|$DBpM+hGm)z{91t@|W>Z7W0mfEvZaVI`HOp zpz6mEIN_G`BRMw3l&z;;e#{>69HFJ$fp@Em$k2sH(9+-o>u`q50A6rIzBFJ2M>NuO zmA8-Xc@nER)t;HmWcz>G`x32-(jah~X^3Av&kZ{79*z&pMdE*j2InA9#Q+uwwWPUp zn{9QrDOfgeMR{C4UZ@am%dNyh;8Kv9sVQf8&u&)0jMqj#AsLTK2hdB99)y#JN3V`B zu196lz( zhIrP1-;841s4?YmM#}^gLF24(nOWI*P|r+3d~jbgUd?aD&VdGelr)OEkxuBfY7N$~ ztyj<4ay44ESW{n=*9&nH#!&MyiruvzHRTHBr3zOwS_`b})dAC`Z-u!-{9t^s6yo2k zD%&ov4M^%vud)T2Xh2P(q?L68*1djolAMDbf9GB~%^;Kfl8Xq;hrHcmkKs z?jd}tV4D!exoSummw3Ru!n!A`f-~^0;XD|+Arx2*v@rP}<1)Uu6@y6<0n>n&(L@28 tUe5u@K$B>{4J1v_R1p6U{ONn@SB6q?OPXSY*34 Date: Thu, 7 Mar 2024 18:15:00 +0100 Subject: [PATCH 10/39] Adds an ideal ROT functionality to mpz-ot-core (#102) * Adds an ideal ROT functionality to mpz-ot-core * Update ot/mpz-ot-core/src/ideal/ideal_rot.rs Derive Debug for IdealROT Co-authored-by: sinu.eth <65924192+sinui0@users.noreply.github.com> * Add feedback * Add more feedback --------- Co-authored-by: sinu.eth <65924192+sinui0@users.noreply.github.com> --- crates/mpz-core/src/prg.rs | 2 + crates/mpz-ot-core/src/ideal/ideal_rot.rs | 89 +++++++++++++++++++++++ crates/mpz-ot-core/src/ideal/mod.rs | 1 + 3 files changed, 92 insertions(+) create mode 100644 crates/mpz-ot-core/src/ideal/ideal_rot.rs diff --git a/crates/mpz-core/src/prg.rs b/crates/mpz-core/src/prg.rs index 9d62587b..d49f8d03 100644 --- a/crates/mpz-core/src/prg.rs +++ b/crates/mpz-core/src/prg.rs @@ -71,6 +71,8 @@ impl CryptoRng for PrgCore {} #[derive(Clone)] pub struct Prg(BlockRng); +opaque_debug::implement!(Prg); + impl RngCore for Prg { #[inline(always)] fn next_u32(&mut self) -> u32 { diff --git a/crates/mpz-ot-core/src/ideal/ideal_rot.rs b/crates/mpz-ot-core/src/ideal/ideal_rot.rs new file mode 100644 index 00000000..a5f2dfb8 --- /dev/null +++ b/crates/mpz-ot-core/src/ideal/ideal_rot.rs @@ -0,0 +1,89 @@ +//! Define ideal functionality of ROT with random choice bit. + +use mpz_core::{prg::Prg, Block}; +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +/// The message that sender receives from the ROT functionality. +pub struct RotMsgForSender { + /// The random blocks that sender receives from the ROT functionality. + pub qs: Vec<[Block; 2]>, +} + +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +/// The message that receiver receives from the ROT functionality. +pub struct RotMsgForReceiver { + /// The random bits that receiver receives from the ROT functionality. + pub rs: Vec, + /// The chosen blocks that receiver receives from the ROT functionality. + pub ts: Vec, +} + +/// An ideal functionality for random OT +#[derive(Debug)] +pub struct IdealROT { + counter: usize, + prg: Prg, +} + +impl IdealROT { + /// Initiate the functionality + pub fn new() -> Self { + let prg = Prg::new(); + IdealROT { counter: 0, prg } + } + + /// Performs the extension with random choice bits. + /// + /// # Argument + /// + /// * `counter` - The number of ROT to extend. + pub fn extend(&mut self, counter: usize) -> (RotMsgForSender, RotMsgForReceiver) { + let mut qs1 = vec![Block::ZERO; counter]; + let mut qs2 = vec![Block::ZERO; counter]; + + self.prg.random_blocks(&mut qs1); + self.prg.random_blocks(&mut qs2); + + let qs: Vec<[Block; 2]> = qs1.iter().zip(qs2).map(|(&q1, q2)| [q1, q2]).collect(); + + let mut rs = vec![false; counter]; + + self.prg.random_bools(&mut rs); + + let ts: Vec = qs + .iter() + .zip(rs.iter()) + .map(|(&q, &r)| q[r as usize]) + .collect(); + + self.counter += counter; + (RotMsgForSender { qs }, RotMsgForReceiver { rs, ts }) + } +} + +impl Default for IdealROT { + fn default() -> Self { + Self::new() + } +} + +#[cfg(test)] +mod tests { + use super::{IdealROT, RotMsgForReceiver}; + + #[test] + fn ideal_rot_test() { + let num = 100; + let mut ideal_rot = IdealROT::new(); + let (sender, receiver) = ideal_rot.extend(num); + + let qs = sender.qs; + let RotMsgForReceiver { rs, ts } = receiver; + + qs.iter() + .zip(ts) + .zip(rs) + .for_each(|((q, t), r)| assert_eq!(q[r as usize], t)); + } +} diff --git a/crates/mpz-ot-core/src/ideal/mod.rs b/crates/mpz-ot-core/src/ideal/mod.rs index 1fb56072..ed22897e 100644 --- a/crates/mpz-ot-core/src/ideal/mod.rs +++ b/crates/mpz-ot-core/src/ideal/mod.rs @@ -1,4 +1,5 @@ //! Define ideal functionalities of OTs. pub mod ideal_cot; pub mod ideal_mpcot; +pub mod ideal_rot; pub mod ideal_spcot; From 7720ed6c0a6a0846855840f849bf603b1406d22d Mon Sep 17 00:00:00 2001 From: "sinu.eth" <65924192+sinui0@users.noreply.github.com> Date: Tue, 7 May 2024 18:06:07 -0800 Subject: [PATCH 11/39] refactor(mpz-ot): Normalize OT and ideal functionalities (#122) * add transfer id * update co15 and kos15 * add Output type * feat(mpz-common): ideal functionality utils * refactor ideal functionalities and traits * pr feedback * impl ideal rot * Update crates/mpz-ot/src/ideal/rot.rs Co-authored-by: th4s --------- Co-authored-by: th4s --- crates/mpz-common/Cargo.toml | 1 + crates/mpz-common/src/ideal.rs | 191 ++++++++++++++ crates/mpz-common/src/lib.rs | 2 + crates/mpz-ot-core/src/chou_orlandi/error.rs | 6 + crates/mpz-ot-core/src/chou_orlandi/msgs.rs | 6 + .../mpz-ot-core/src/chou_orlandi/receiver.rs | 21 +- crates/mpz-ot-core/src/chou_orlandi/sender.rs | 32 ++- crates/mpz-ot-core/src/ferret/mod.rs | 75 +++--- crates/mpz-ot-core/src/ferret/mpcot/mod.rs | 19 +- crates/mpz-ot-core/src/ferret/msgs.rs | 5 +- crates/mpz-ot-core/src/ferret/receiver.rs | 8 +- crates/mpz-ot-core/src/ferret/spcot/mod.rs | 38 +-- crates/mpz-ot-core/src/ideal/cot.rs | 167 +++++++++++++ crates/mpz-ot-core/src/ideal/ideal_cot.rs | 116 --------- crates/mpz-ot-core/src/ideal/ideal_mpcot.rs | 118 --------- crates/mpz-ot-core/src/ideal/ideal_rot.rs | 89 ------- crates/mpz-ot-core/src/ideal/mod.rs | 10 +- crates/mpz-ot-core/src/ideal/mpcot.rs | 97 ++++++++ crates/mpz-ot-core/src/ideal/ot.rs | 93 +++++++ crates/mpz-ot-core/src/ideal/rot.rs | 162 ++++++++++++ .../src/ideal/{ideal_spcot.rs => spcot.rs} | 82 +++--- crates/mpz-ot-core/src/kos/error.rs | 8 +- crates/mpz-ot-core/src/kos/mod.rs | 8 +- crates/mpz-ot-core/src/kos/msgs.rs | 4 +- crates/mpz-ot-core/src/kos/receiver.rs | 19 +- crates/mpz-ot-core/src/kos/sender.rs | 12 +- crates/mpz-ot-core/src/lib.rs | 137 ++++++++++ crates/mpz-ot-core/src/msgs.rs | 10 +- crates/mpz-ot-core/src/test.rs | 27 ++ crates/mpz-ot/Cargo.toml | 6 +- crates/mpz-ot/src/chou_orlandi/mod.rs | 30 +-- crates/mpz-ot/src/chou_orlandi/receiver.rs | 18 +- crates/mpz-ot/src/chou_orlandi/sender.rs | 14 +- crates/mpz-ot/src/ideal/cot.rs | 159 +++++------- crates/mpz-ot/src/ideal/mod.rs | 1 - crates/mpz-ot/src/ideal/ot.rs | 202 +++++---------- crates/mpz-ot/src/ideal/rot.rs | 234 +++--------------- crates/mpz-ot/src/kos/mod.rs | 73 +++--- crates/mpz-ot/src/kos/receiver.rs | 83 ++++--- crates/mpz-ot/src/kos/sender.rs | 61 +++-- crates/mpz-ot/src/kos/shared_receiver.rs | 14 +- crates/mpz-ot/src/kos/shared_sender.rs | 10 +- crates/mpz-ot/src/lib.rs | 98 +++----- 43 files changed, 1459 insertions(+), 1107 deletions(-) create mode 100644 crates/mpz-common/src/ideal.rs create mode 100644 crates/mpz-ot-core/src/ideal/cot.rs delete mode 100644 crates/mpz-ot-core/src/ideal/ideal_cot.rs delete mode 100644 crates/mpz-ot-core/src/ideal/ideal_mpcot.rs delete mode 100644 crates/mpz-ot-core/src/ideal/ideal_rot.rs create mode 100644 crates/mpz-ot-core/src/ideal/mpcot.rs create mode 100644 crates/mpz-ot-core/src/ideal/ot.rs create mode 100644 crates/mpz-ot-core/src/ideal/rot.rs rename crates/mpz-ot-core/src/ideal/{ideal_spcot.rs => spcot.rs} (51%) create mode 100644 crates/mpz-ot-core/src/test.rs diff --git a/crates/mpz-common/Cargo.toml b/crates/mpz-common/Cargo.toml index c8e158a9..8a048c5a 100644 --- a/crates/mpz-common/Cargo.toml +++ b/crates/mpz-common/Cargo.toml @@ -7,6 +7,7 @@ edition = "2021" default = ["sync"] sync = [] test-utils = [] +ideal = [] [dependencies] mpz-core.workspace = true diff --git a/crates/mpz-common/src/ideal.rs b/crates/mpz-common/src/ideal.rs new file mode 100644 index 00000000..804472ef --- /dev/null +++ b/crates/mpz-common/src/ideal.rs @@ -0,0 +1,191 @@ +//! Ideal functionality utilities. + +use futures::channel::oneshot; +use std::{ + any::Any, + collections::HashMap, + sync::{Arc, Mutex, MutexGuard}, +}; + +use crate::{Context, ThreadId}; + +type BoxAny = Box; + +#[derive(Debug, Default)] +struct Buffer { + alice: HashMap)>, + bob: HashMap)>, +} + +/// The ideal functionality from the perspective of Alice. +#[derive(Debug)] +pub struct Alice { + f: Arc>, + buffer: Arc>, +} + +impl Clone for Alice { + fn clone(&self) -> Self { + Self { + f: self.f.clone(), + buffer: self.buffer.clone(), + } + } +} + +impl Alice { + /// Returns a lock to the ideal functionality. + pub fn get_mut(&mut self) -> MutexGuard<'_, F> { + self.f.lock().unwrap() + } + + /// Calls the ideal functionality. + pub async fn call(&mut self, ctx: &mut Ctx, input: IA, call: C) -> OA + where + Ctx: Context, + C: FnOnce(&mut F, IA, IB) -> (OA, OB), + IA: Send + 'static, + IB: Send + 'static, + OA: Send + 'static, + OB: Send + 'static, + { + let receiver = { + let mut buffer = self.buffer.lock().unwrap(); + if let Some((input_bob, ret_bob)) = buffer.bob.remove(ctx.id()) { + let input_bob = *input_bob + .downcast() + .expect("alice received correct input type for bob"); + + let (output_alice, output_bob) = + call(&mut self.f.lock().unwrap(), input, input_bob); + + _ = ret_bob.send(Box::new(output_bob)); + + return output_alice; + } + + let (sender, receiver) = oneshot::channel(); + buffer + .alice + .insert(ctx.id().clone(), (Box::new(input), sender)); + receiver + }; + + let output_alice = receiver.await.expect("bob did not drop the channel"); + *output_alice + .downcast() + .expect("bob sent correct output type for alice") + } +} + +/// The ideal functionality from the perspective of Bob. +#[derive(Debug)] +pub struct Bob { + f: Arc>, + buffer: Arc>, +} + +impl Clone for Bob { + fn clone(&self) -> Self { + Self { + f: self.f.clone(), + buffer: self.buffer.clone(), + } + } +} + +impl Bob { + /// Returns a lock to the ideal functionality. + pub fn get_mut(&mut self) -> MutexGuard<'_, F> { + self.f.lock().unwrap() + } + + /// Calls the ideal functionality. + pub async fn call(&mut self, ctx: &mut Ctx, input: IB, call: C) -> OB + where + Ctx: Context, + C: FnOnce(&mut F, IA, IB) -> (OA, OB), + IA: Send + 'static, + IB: Send + 'static, + OA: Send + 'static, + OB: Send + 'static, + { + let receiver = { + let mut buffer = self.buffer.lock().unwrap(); + if let Some((input_alice, ret_alice)) = buffer.alice.remove(ctx.id()) { + let input_alice = *input_alice + .downcast() + .expect("bob received correct input type for alice"); + + let (output_alice, output_bob) = + call(&mut self.f.lock().unwrap(), input_alice, input); + + _ = ret_alice.send(Box::new(output_alice)); + + return output_bob; + } + + let (sender, receiver) = oneshot::channel(); + buffer + .bob + .insert(ctx.id().clone(), (Box::new(input), sender)); + receiver + }; + + let output_bob = receiver.await.expect("alice did not drop the channel"); + *output_bob + .downcast() + .expect("alice sent correct output type for bob") + } +} + +/// Creates an ideal functionality, returning the perspectives of Alice and Bob. +pub fn ideal_f2p(f: F) -> (Alice, Bob) { + let f = Arc::new(Mutex::new(f)); + let buffer = Arc::new(Mutex::new(Buffer::default())); + + ( + Alice { + f: f.clone(), + buffer: buffer.clone(), + }, + Bob { f, buffer }, + ) +} + +#[cfg(test)] +mod test { + use crate::executor::test_st_executor; + + use super::*; + + #[test] + fn test_ideal() { + let (mut alice, mut bob) = ideal_f2p(()); + let (mut ctx_a, mut ctx_b) = test_st_executor(8); + + let (output_a, output_b) = futures::executor::block_on(async { + futures::join!( + alice.call(&mut ctx_a, 1u8, |&mut (), a: u8, b: u8| (a + b, a + b)), + bob.call(&mut ctx_b, 2u8, |&mut (), a: u8, b: u8| (a + b, a + b)), + ) + }); + + assert_eq!(output_a, 3); + assert_eq!(output_b, 3); + } + + #[test] + #[should_panic] + fn test_ideal_wrong_input_type() { + let (mut alice, mut bob) = ideal_f2p(()); + let (mut ctx_a, mut ctx_b) = test_st_executor(8); + + futures::executor::block_on(async { + futures::join!( + alice.call(&mut ctx_a, 1u16, |&mut (), a: u16, b: u16| (a + b, a + b)), + bob.call(&mut ctx_b, 2u8, |&mut (), a: u8, b: u8| (a + b, a + b)), + ) + }); + } +} diff --git a/crates/mpz-common/src/lib.rs b/crates/mpz-common/src/lib.rs index 35447c3b..53fc6458 100644 --- a/crates/mpz-common/src/lib.rs +++ b/crates/mpz-common/src/lib.rs @@ -17,6 +17,8 @@ mod context; pub mod executor; mod id; +#[cfg(any(test, feature = "ideal"))] +pub mod ideal; #[cfg(feature = "sync")] pub mod sync; diff --git a/crates/mpz-ot-core/src/chou_orlandi/error.rs b/crates/mpz-ot-core/src/chou_orlandi/error.rs index 89dd00ed..2939baa4 100644 --- a/crates/mpz-ot-core/src/chou_orlandi/error.rs +++ b/crates/mpz-ot-core/src/chou_orlandi/error.rs @@ -1,9 +1,13 @@ +use crate::TransferId; + /// Errors that can occur when using the CO15 sender. #[derive(Debug, thiserror::Error)] #[allow(missing_docs)] pub enum SenderError { #[error("invalid state: expected {0}")] InvalidState(String), + #[error("id mismatch: expected {0}, got {1}")] + IdMismatch(TransferId, TransferId), #[error("count mismatch: sender expected {0} but receiver sent {1}")] CountMismatch(usize, usize), #[error(transparent)] @@ -16,6 +20,8 @@ pub enum SenderError { pub enum ReceiverError { #[error("invalid state: expected {0}")] InvalidState(String), + #[error("id mismatch: expected {0}, got {1}")] + IdMismatch(TransferId, TransferId), #[error("count mismatch: receiver expected {0} but sender sent {1}")] CountMismatch(usize, usize), } diff --git a/crates/mpz-ot-core/src/chou_orlandi/msgs.rs b/crates/mpz-ot-core/src/chou_orlandi/msgs.rs index 3c714410..f19c1b8f 100644 --- a/crates/mpz-ot-core/src/chou_orlandi/msgs.rs +++ b/crates/mpz-ot-core/src/chou_orlandi/msgs.rs @@ -4,6 +4,8 @@ use curve25519_dalek::RistrettoPoint; use mpz_core::Block; use serde::{Deserialize, Serialize}; +use crate::TransferId; + /// Sender setup message. #[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)] pub struct SenderSetup { @@ -14,6 +16,8 @@ pub struct SenderSetup { /// Sender payload message. #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] pub struct SenderPayload { + /// The transfer ID. + pub id: TransferId, /// The sender's ciphertexts pub payload: Vec<[Block; 2]>, } @@ -21,6 +25,8 @@ pub struct SenderPayload { /// Receiver payload message. #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] pub struct ReceiverPayload { + /// The transfer ID. + pub id: TransferId, /// The receiver's blinded choices. pub blinded_choices: Vec, } diff --git a/crates/mpz-ot-core/src/chou_orlandi/receiver.rs b/crates/mpz-ot-core/src/chou_orlandi/receiver.rs index 2f49b5b2..403802f9 100644 --- a/crates/mpz-ot-core/src/chou_orlandi/receiver.rs +++ b/crates/mpz-ot-core/src/chou_orlandi/receiver.rs @@ -3,6 +3,7 @@ use crate::chou_orlandi::{ msgs::{ReceiverPayload, ReceiverReveal, SenderPayload, SenderSetup}, ReceiverConfig, ReceiverError, }; +use crate::TransferId; use itybity::{BitIterable, FromBitIterator, ToBits}; use mpz_core::Block; @@ -89,6 +90,7 @@ impl Receiver { state: state::Setup { rng, sender_base_table: RistrettoBasepointTable::create(&sender_setup.public_key), + transfer_id: TransferId::default(), counter: 0, choice_log: Vec::default(), decryption_keys: Vec::default(), @@ -129,7 +131,10 @@ impl Receiver { choice_log.extend(choices.iter_lsb0()); } - ReceiverPayload { blinded_choices } + ReceiverPayload { + id: self.state.transfer_id, + blinded_choices, + } } /// Receives the encrypted payload from the Sender, returning the plaintext messages corresponding @@ -140,10 +145,18 @@ impl Receiver { /// * `payload` - The encrypted payload from the Sender pub fn receive(&mut self, payload: SenderPayload) -> Result, ReceiverError> { let state::Setup { - decryption_keys, .. + transfer_id: current_id, + decryption_keys, + .. } = &mut self.state; - let SenderPayload { payload } = payload; + let SenderPayload { id, payload } = payload; + + // Check that the transfer id matches + let expected_id = current_id.next(); + if id != expected_id { + return Err(ReceiverError::IdMismatch(expected_id, id)); + } // Check that the number of ciphertexts does not exceed the number of pending keys if payload.len() > decryption_keys.len() { @@ -267,6 +280,8 @@ pub mod state { pub(super) rng: ChaCha20Rng, /// Sender's public key (precomputed table) pub(super) sender_base_table: RistrettoBasepointTable, + /// Current transfer id. + pub(super) transfer_id: TransferId, /// Counts how many decryption keys we've computed so far pub(super) counter: usize, /// Log of the receiver's choice bits diff --git a/crates/mpz-ot-core/src/chou_orlandi/sender.rs b/crates/mpz-ot-core/src/chou_orlandi/sender.rs index 755277c6..09a8b5a6 100644 --- a/crates/mpz-ot-core/src/chou_orlandi/sender.rs +++ b/crates/mpz-ot-core/src/chou_orlandi/sender.rs @@ -1,7 +1,10 @@ -use crate::chou_orlandi::{ - hash_point, - msgs::{ReceiverPayload, ReceiverReveal, SenderPayload, SenderSetup}, - Receiver, ReceiverConfig, SenderConfig, SenderError, SenderVerifyError, +use crate::{ + chou_orlandi::{ + hash_point, + msgs::{ReceiverPayload, ReceiverReveal, SenderPayload, SenderSetup}, + Receiver, ReceiverConfig, SenderConfig, SenderError, SenderVerifyError, + }, + TransferId, }; use itybity::IntoBitIterator; @@ -101,6 +104,7 @@ impl Sender { state: state::Setup { private_key, public_key, + transfer_id: TransferId::default(), counter: 0, }, tape: self.tape, @@ -124,11 +128,21 @@ impl Sender { let state::Setup { private_key, public_key, + transfer_id: current_id, counter, .. } = &mut self.state; - let ReceiverPayload { blinded_choices } = receiver_payload; + let ReceiverPayload { + id, + blinded_choices, + } = receiver_payload; + + // Check that the transfer id matches + let expected_id = current_id.next(); + if id != expected_id { + return Err(SenderError::IdMismatch(expected_id, id)); + } // Check that the number of inputs matches the number of choices if inputs.len() != blinded_choices.len() { @@ -154,7 +168,7 @@ impl Sender { payload[1] = input[1] ^ payload[1]; } - Ok(SenderPayload { payload }) + Ok(SenderPayload { id, payload }) } /// Returns the Receiver choices after verifying them against the tape. @@ -199,7 +213,9 @@ impl Sender { let mut receiver = receiver.setup(SenderSetup { public_key }); - let ReceiverPayload { blinded_choices } = receiver.receive_random(&choices); + let ReceiverPayload { + blinded_choices, .. + } = receiver.receive_random(&choices); // Check that the simulated receiver's choices match the ones recorded in the tape if blinded_choices != tape.receiver_choices { @@ -296,6 +312,8 @@ pub mod state { pub(super) private_key: Scalar, // The public_key is `A == g^a` in [ref1] pub(super) public_key: RistrettoPoint, + /// Current transfer id. + pub(super) transfer_id: TransferId, /// Number of OTs sent so far pub(super) counter: usize, } diff --git a/crates/mpz-ot-core/src/ferret/mod.rs b/crates/mpz-ot-core/src/ferret/mod.rs index 4ea60c3f..3ad7701e 100644 --- a/crates/mpz-ot-core/src/ferret/mod.rs +++ b/crates/mpz-ot-core/src/ferret/mod.rs @@ -36,6 +36,7 @@ pub const LPN_PARAMETERS_UNIFORM: LpnParameters = LpnParameters { }; /// The type of Lpn parameters. +#[derive(Debug)] pub enum LpnType { /// Uniform error distribution. Uniform, @@ -45,14 +46,15 @@ pub enum LpnType { #[cfg(test)] mod tests { - use super::{ - msgs::LpnMatrixSeed, receiver::Receiver as FerretReceiver, sender::Sender as FerretSender, - LpnType, - }; - use crate::ideal::{ - ideal_cot::{CotMsgForReceiver, CotMsgForSender, IdealCOT}, - ideal_mpcot::{IdealMpcot, MpcotMsgForReceiver, MpcotMsgForSender}, - }; + use super::*; + + use msgs::LpnMatrixSeed; + use receiver::Receiver; + use sender::Sender; + + use crate::ideal::{cot::IdealCOT, mpcot::IdealMpcot}; + use crate::test::assert_cot; + use crate::{MPCOTReceiverOutput, MPCOTSenderOutput, RCOTReceiverOutput, RCOTSenderOutput}; use mpz_core::{lpn::LpnParameters, prg::Prg}; use rand::SeedableRng; @@ -66,17 +68,24 @@ mod tests { fn ferret_test() { let mut prg = Prg::from_seed([1u8; 16].into()); let delta = prg.random_block(); - let mut ideal_cot = IdealCOT::new_with_delta(delta); - let mut ideal_mpcot = IdealMpcot::init_with_delta(delta); + let mut ideal_cot = IdealCOT::default(); + let mut ideal_mpcot = IdealMpcot::default(); - let sender = FerretSender::new(); - let receiver = FerretReceiver::new(); + ideal_cot.set_delta(delta); + ideal_mpcot.set_delta(delta); + + let sender = Sender::new(); + let receiver = Receiver::new(); // Invoke Ideal COT to init the Ferret setup phase. - let (sender_cot, receiver_cot) = ideal_cot.extend(LPN_PARAMETERS_TEST.k); + let (sender_cot, receiver_cot) = ideal_cot.random_correlated(LPN_PARAMETERS_TEST.k); - let CotMsgForSender { qs: v } = sender_cot; - let CotMsgForReceiver { rs: u, ts: w } = receiver_cot; + let RCOTSenderOutput { msgs: v, .. } = sender_cot; + let RCOTReceiverOutput { + choices: u, + msgs: w, + .. + } = receiver_cot; // receiver generates the random seed of lpn matrix. let lpn_matrix_seed = prg.random_block(); @@ -110,40 +119,24 @@ mod tests { let _ = sender.get_mpcot_query(); let query = receiver.get_mpcot_query(); - let (sender_mpcot, receiver_mpcot) = ideal_mpcot.extend(&query.0, query.1, query.2); - - let MpcotMsgForSender { s } = sender_mpcot; - let MpcotMsgForReceiver { r } = receiver_mpcot; + let (MPCOTSenderOutput { s, .. }, MPCOTReceiverOutput { r, .. }) = + ideal_mpcot.extend(&query.0, query.1); - let sender_out = sender.extend(&s).unwrap(); - let receiver_out = receiver.extend(&r).unwrap(); + let msgs = sender.extend(&s).unwrap(); + let (choices, received) = receiver.extend(&r).unwrap(); - assert!(ideal_cot.check( - CotMsgForSender { qs: sender_out }, - CotMsgForReceiver { - rs: receiver_out.0, - ts: receiver_out.1, - }, - )); + assert_cot(delta, &choices, &msgs, &received); // extend twice let _ = sender.get_mpcot_query(); let query = receiver.get_mpcot_query(); - let (sender_mpcot, receiver_mpcot) = ideal_mpcot.extend(&query.0, query.1, query.2); - - let MpcotMsgForSender { s } = sender_mpcot; - let MpcotMsgForReceiver { r } = receiver_mpcot; + let (MPCOTSenderOutput { s, .. }, MPCOTReceiverOutput { r, .. }) = + ideal_mpcot.extend(&query.0, query.1); - let sender_out = sender.extend(&s).unwrap(); - let receiver_out = receiver.extend(&r).unwrap(); + let msgs = sender.extend(&s).unwrap(); + let (choices, received) = receiver.extend(&r).unwrap(); - assert!(ideal_cot.check( - CotMsgForSender { qs: sender_out }, - CotMsgForReceiver { - rs: receiver_out.0, - ts: receiver_out.1, - }, - )); + assert_cot(delta, &choices, &msgs, &received); } } diff --git a/crates/mpz-ot-core/src/ferret/mpcot/mod.rs b/crates/mpz-ot-core/src/ferret/mpcot/mod.rs index e8c3043c..e74dc38a 100644 --- a/crates/mpz-ot-core/src/ferret/mpcot/mod.rs +++ b/crates/mpz-ot-core/src/ferret/mpcot/mod.rs @@ -13,7 +13,8 @@ mod tests { receiver::Receiver as MpcotReceiver, receiver_regular::Receiver as RegularReceiver, sender::Sender as MpcotSender, sender_regular::Sender as RegularSender, }; - use crate::ideal::ideal_spcot::{IdealSpcot, SpcotMsgForReceiver, SpcotMsgForSender}; + use crate::ideal::spcot::IdealSpcot; + use crate::{SPCOTReceiverOutput, SPCOTSenderOutput}; use mpz_core::prg::Prg; use rand::SeedableRng; @@ -50,8 +51,8 @@ mod tests { let (sender_spcot_msg, receiver_spcot_msg) = ideal_spcot.extend(&queries); - let SpcotMsgForSender { v: st } = sender_spcot_msg; - let SpcotMsgForReceiver { w: rt } = receiver_spcot_msg; + let SPCOTSenderOutput { v: st, .. } = sender_spcot_msg; + let SPCOTReceiverOutput { w: rt, .. } = receiver_spcot_msg; let (sender_pre, mut output_sender) = sender.extend(&st).unwrap(); let (receiver_pre, output_receiver) = receiver.extend(&rt).unwrap(); @@ -80,8 +81,8 @@ mod tests { let (sender_spcot_msg, receiver_spcot_msg) = ideal_spcot.extend(&queries); - let SpcotMsgForSender { v: st } = sender_spcot_msg; - let SpcotMsgForReceiver { w: rt } = receiver_spcot_msg; + let SPCOTSenderOutput { v: st, .. } = sender_spcot_msg; + let SPCOTReceiverOutput { w: rt, .. } = receiver_spcot_msg; let (_, mut output_sender) = sender.extend(&st).unwrap(); let (_, output_receiver) = receiver.extend(&rt).unwrap(); @@ -123,8 +124,8 @@ mod tests { let (sender_spcot_msg, receiver_spcot_msg) = ideal_spcot.extend(&queries); - let SpcotMsgForSender { v: st } = sender_spcot_msg; - let SpcotMsgForReceiver { w: rt } = receiver_spcot_msg; + let SPCOTSenderOutput { v: st, .. } = sender_spcot_msg; + let SPCOTReceiverOutput { w: rt, .. } = receiver_spcot_msg; let (sender_pre, mut output_sender) = sender.extend(&st).unwrap(); let (receiver_pre, output_receiver) = receiver.extend(&rt).unwrap(); @@ -153,8 +154,8 @@ mod tests { let (sender_spcot_msg, receiver_spcot_msg) = ideal_spcot.extend(&queries); - let SpcotMsgForSender { v: st } = sender_spcot_msg; - let SpcotMsgForReceiver { w: rt } = receiver_spcot_msg; + let SPCOTSenderOutput { v: st, .. } = sender_spcot_msg; + let SPCOTReceiverOutput { w: rt, .. } = receiver_spcot_msg; let (_, mut output_sender) = sender.extend(&st).unwrap(); let (_, output_receiver) = receiver.extend(&rt).unwrap(); diff --git a/crates/mpz-ot-core/src/ferret/msgs.rs b/crates/mpz-ot-core/src/ferret/msgs.rs index da2b1e52..4c4a426f 100644 --- a/crates/mpz-ot-core/src/ferret/msgs.rs +++ b/crates/mpz-ot-core/src/ferret/msgs.rs @@ -1,9 +1,10 @@ -//! Messages for the Ferret protocol. +//! Ferret protocol messages. + use mpz_core::Block; use serde::{Deserialize, Serialize}; -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] /// The seed to generate Lpn matrix. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] pub struct LpnMatrixSeed { /// The seed. pub seed: Block, diff --git a/crates/mpz-ot-core/src/ferret/receiver.rs b/crates/mpz-ot-core/src/ferret/receiver.rs index 4f94e6e6..4d08c69b 100644 --- a/crates/mpz-ot-core/src/ferret/receiver.rs +++ b/crates/mpz-ot-core/src/ferret/receiver.rs @@ -73,7 +73,7 @@ impl Receiver { /// # Arguments. /// /// * `lpn_type` - The type of LPN parameters. - pub fn get_mpcot_query(&mut self) -> (Vec, usize, usize) { + pub fn get_mpcot_query(&mut self) -> (Vec, usize) { match self.state.lpn_type { LpnType::Uniform => { self.state.e = self.state.lpn_parameters.sample_uniform_error_vector(); @@ -89,11 +89,7 @@ impl Receiver { alphas.push(i as u32); } } - ( - alphas, - self.state.lpn_parameters.t, - self.state.lpn_parameters.n, - ) + (alphas, self.state.lpn_parameters.n) } /// Performs the Ferret extension. diff --git a/crates/mpz-ot-core/src/ferret/spcot/mod.rs b/crates/mpz-ot-core/src/ferret/spcot/mod.rs index 8a69549a..802efb66 100644 --- a/crates/mpz-ot-core/src/ferret/spcot/mod.rs +++ b/crates/mpz-ot-core/src/ferret/spcot/mod.rs @@ -10,14 +10,11 @@ mod tests { use mpz_core::prg::Prg; use super::{receiver::Receiver as SpcotReceiver, sender::Sender as SpcotSender}; - use crate::{ - ferret::CSP, - ideal::ideal_cot::{CotMsgForReceiver, CotMsgForSender, IdealCOT}, - }; + use crate::{ferret::CSP, ideal::cot::IdealCOT, RCOTReceiverOutput, RCOTSenderOutput}; #[test] fn spcot_test() { - let mut ideal_cot = IdealCOT::new(); + let mut ideal_cot = IdealCOT::default(); let sender = SpcotSender::new(); let receiver = SpcotReceiver::new(); @@ -32,10 +29,14 @@ mod tests { let alpha1 = 3; // Extend once - let (msg_for_sender, msg_for_receiver) = ideal_cot.extend(h1); + let (msg_for_sender, msg_for_receiver) = ideal_cot.random_correlated(h1); - let CotMsgForReceiver { rs, ts } = msg_for_receiver; - let CotMsgForSender { qs } = msg_for_sender; + let RCOTReceiverOutput { + choices: rs, + msgs: ts, + .. + } = msg_for_receiver; + let RCOTSenderOutput { msgs: qs, .. } = msg_for_sender; let maskbits = receiver.extend_mask_bits(h1, alpha1, &rs).unwrap(); let msg_from_sender = sender.extend(h1, &qs, maskbits).unwrap(); @@ -46,10 +47,14 @@ mod tests { let h2 = 4; let alpha2 = 2; - let (msg_for_sender, msg_for_receiver) = ideal_cot.extend(h2); + let (msg_for_sender, msg_for_receiver) = ideal_cot.random_correlated(h2); - let CotMsgForReceiver { rs, ts } = msg_for_receiver; - let CotMsgForSender { qs } = msg_for_sender; + let RCOTReceiverOutput { + choices: rs, + msgs: ts, + .. + } = msg_for_receiver; + let RCOTSenderOutput { msgs: qs, .. } = msg_for_sender; let maskbits = receiver.extend_mask_bits(h2, alpha2, &rs).unwrap(); @@ -58,14 +63,15 @@ mod tests { receiver.extend(h2, alpha2, &ts, msg_from_sender).unwrap(); // Check - let (msg_for_sender, msg_for_receiver) = ideal_cot.extend(CSP); + let (msg_for_sender, msg_for_receiver) = ideal_cot.random_correlated(CSP); - let CotMsgForReceiver { - rs: x_star, - ts: z_star, + let RCOTReceiverOutput { + choices: x_star, + msgs: z_star, + .. } = msg_for_receiver; - let CotMsgForSender { qs: y_star } = msg_for_sender; + let RCOTSenderOutput { msgs: y_star, .. } = msg_for_sender; let check_from_receiver = receiver.check_pre(&x_star).unwrap(); diff --git a/crates/mpz-ot-core/src/ideal/cot.rs b/crates/mpz-ot-core/src/ideal/cot.rs new file mode 100644 index 00000000..a28abef8 --- /dev/null +++ b/crates/mpz-ot-core/src/ideal/cot.rs @@ -0,0 +1,167 @@ +//! Ideal Correlated Oblivious Transfer functionality. + +use mpz_core::{prg::Prg, Block}; +use rand::{Rng, SeedableRng}; +use rand_chacha::ChaCha8Rng; + +use crate::TransferId; +use crate::{COTReceiverOutput, COTSenderOutput, RCOTReceiverOutput, RCOTSenderOutput}; + +/// The ideal COT functionality. +#[derive(Debug)] +pub struct IdealCOT { + delta: Block, + transfer_id: TransferId, + counter: usize, + prg: Prg, +} + +impl IdealCOT { + /// Creates a new ideal OT functionality. + /// + /// # Arguments + /// + /// * `seed` - The seed for the PRG. + /// * `delta` - The correlation. + pub fn new(seed: Block, delta: Block) -> Self { + IdealCOT { + delta, + transfer_id: TransferId::default(), + counter: 0, + prg: Prg::from_seed(seed), + } + } + + /// Returns the correlation, delta. + pub fn delta(&self) -> Block { + self.delta + } + + /// Sets the correlation, delta. + pub fn set_delta(&mut self, delta: Block) { + self.delta = delta; + } + + /// Returns the current transfer id. + pub fn transfer_id(&self) -> TransferId { + self.transfer_id + } + + /// Returns the number of OTs executed. + pub fn count(&self) -> usize { + self.counter + } + + /// Executes random correlated oblivious transfers. + /// + /// The functionality deals random choices to the receiver, along with the corresponding messages. + /// + /// # Arguments + /// + /// * `count` - The number of COTs to execute. + pub fn random_correlated( + &mut self, + count: usize, + ) -> (RCOTSenderOutput, RCOTReceiverOutput) { + let mut msgs = vec![Block::ZERO; count]; + let mut choices = vec![false; count]; + + self.prg.random_blocks(&mut msgs); + self.prg.random_bools(&mut choices); + + let chosen: Vec = msgs + .iter() + .zip(choices.iter()) + .map(|(&q, &r)| if r { q ^ self.delta } else { q }) + .collect(); + + self.counter += count; + let id = self.transfer_id.next(); + + ( + RCOTSenderOutput { id, msgs }, + RCOTReceiverOutput { + id, + choices, + msgs: chosen, + }, + ) + } + + /// Executes correlated oblivious transfers with choices provided by the receiver. + /// + /// # Arguments + /// + /// * `choices` - The choices made by the receiver. + pub fn correlated( + &mut self, + choices: Vec, + ) -> (COTSenderOutput, COTReceiverOutput) { + let (sender_output, mut receiver_output) = self.random_correlated(choices.len()); + + receiver_output + .msgs + .iter_mut() + .zip(choices.iter().zip(receiver_output.choices)) + .for_each(|(msg, (&actual_choice, random_choice))| { + if actual_choice ^ random_choice { + *msg ^= self.delta + } + }); + + ( + COTSenderOutput { + id: sender_output.id, + msgs: sender_output.msgs, + }, + COTReceiverOutput { + id: receiver_output.id, + msgs: receiver_output.msgs, + }, + ) + } +} + +impl Default for IdealCOT { + fn default() -> Self { + let mut rng = ChaCha8Rng::seed_from_u64(0); + Self::new(rng.gen(), rng.gen()) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + use crate::test::assert_cot; + + #[test] + fn test_ideal_rcot() { + let mut ideal = IdealCOT::default(); + + let ( + RCOTSenderOutput { msgs, .. }, + RCOTReceiverOutput { + choices, + msgs: received, + .. + }, + ) = ideal.random_correlated(100); + + assert_cot(ideal.delta(), &choices, &msgs, &received) + } + + #[test] + fn test_ideal_cot() { + let mut ideal = IdealCOT::default(); + + let mut rng = ChaCha8Rng::seed_from_u64(0); + let mut choices = vec![false; 100]; + rng.fill(&mut choices[..]); + + let (COTSenderOutput { msgs, .. }, COTReceiverOutput { msgs: received, .. }) = + ideal.correlated(choices.clone()); + + assert_cot(ideal.delta(), &choices, &msgs, &received) + } +} diff --git a/crates/mpz-ot-core/src/ideal/ideal_cot.rs b/crates/mpz-ot-core/src/ideal/ideal_cot.rs deleted file mode 100644 index c8a27142..00000000 --- a/crates/mpz-ot-core/src/ideal/ideal_cot.rs +++ /dev/null @@ -1,116 +0,0 @@ -//! Define ideal functionality of COT with random choice bit. - -use mpz_core::{prg::Prg, Block}; -use serde::{Deserialize, Serialize}; - -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] -/// The message that sender receives from the COT functionality. -pub struct CotMsgForSender { - /// The random blocks that sender receives from the COT functionality. - pub qs: Vec, -} - -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] -/// The message that receiver receives from the COT functionality. -pub struct CotMsgForReceiver { - /// The random bits that receiver receives from the COT functionality. - pub rs: Vec, - /// The chosen blocks that receiver receives from the COT functionality. - pub ts: Vec, -} -#[allow(missing_docs)] -pub struct IdealCOT { - delta: Block, - counter: usize, - prg: Prg, -} - -impl IdealCOT { - /// Initiate the functionality - pub fn new() -> Self { - let mut prg = Prg::new(); - let delta = prg.random_block(); - IdealCOT { - delta, - counter: 0, - prg, - } - } - - /// Initiate with a given delta - pub fn new_with_delta(delta: Block) -> Self { - let prg = Prg::new(); - IdealCOT { - delta, - counter: 0, - prg, - } - } - - /// Output delta - pub fn delta(&self) -> Block { - self.delta - } - - /// Performs the extension with random choice bits. - /// - /// # Argument - /// - /// * `counter` - The number of COT to extend. - pub fn extend(&mut self, counter: usize) -> (CotMsgForSender, CotMsgForReceiver) { - let mut qs = vec![Block::ZERO; counter]; - let mut rs = vec![false; counter]; - - self.prg.random_blocks(&mut qs); - self.prg.random_bools(&mut rs); - - let ts: Vec = qs - .iter() - .zip(rs.iter()) - .map(|(&q, &r)| if r { q ^ self.delta } else { q }) - .collect(); - - self.counter += counter; - (CotMsgForSender { qs }, CotMsgForReceiver { rs, ts }) - } - - /// Checks if the outputs satisfy the relation with Delta, this is only used for test. - /// - /// # Arguments - /// - /// * `sender_msg` - The message that the ideal COT sends to the sender. - /// * `receiver_msg` - The message that the ideal COT sends to the receiver. - pub fn check(&self, sender_msg: CotMsgForSender, receiver_msg: CotMsgForReceiver) -> bool { - let CotMsgForSender { qs } = sender_msg; - let CotMsgForReceiver { rs, ts } = receiver_msg; - - qs.into_iter().zip(ts).zip(rs).all( - |((q, t), r)| { - if !r { - q == t - } else { - q == t ^ self.delta - } - }, - ) - } -} - -impl Default for IdealCOT { - fn default() -> Self { - Self::new() - } -} -#[cfg(test)] -mod tests { - use crate::ideal::ideal_cot::IdealCOT; - - #[test] - fn ideal_cot_test() { - let num = 100; - let mut ideal_cot = IdealCOT::new(); - let (sender, receiver) = ideal_cot.extend(num); - - assert!(ideal_cot.check(sender, receiver)); - } -} diff --git a/crates/mpz-ot-core/src/ideal/ideal_mpcot.rs b/crates/mpz-ot-core/src/ideal/ideal_mpcot.rs deleted file mode 100644 index 8eca097e..00000000 --- a/crates/mpz-ot-core/src/ideal/ideal_mpcot.rs +++ /dev/null @@ -1,118 +0,0 @@ -//! Define ideal functionality of MPCOT. - -use mpz_core::{prg::Prg, Block}; -use serde::{Deserialize, Serialize}; - -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] -/// The message that sender receives from the MPCOT functionality. -pub struct MpcotMsgForSender { - /// The random blocks that sender receives from the MPCOT functionality. - pub s: Vec, -} - -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] -/// The message that receiver receives from the MPCOT functionality. -pub struct MpcotMsgForReceiver { - /// The random blocks that receiver receives from the MPCOT functionality. - pub r: Vec, -} - -#[allow(missing_docs)] -pub struct IdealMpcot { - pub delta: Block, - pub counter: usize, - pub prg: Prg, -} - -impl IdealMpcot { - /// Initiate the functionality. - pub fn init() -> Self { - let mut prg = Prg::new(); - let delta = prg.random_block(); - IdealMpcot { - delta, - counter: 0, - prg, - } - } - - /// Initiate with a given delta. - pub fn init_with_delta(delta: Block) -> Self { - let prg = Prg::new(); - IdealMpcot { - delta, - counter: 0, - prg, - } - } - - /// Performs the extension of MPCOT. - /// - /// # Argument - /// - /// * `alphas` - The positions in each extension. - /// * `n` - The length of the vector. - pub fn extend( - &mut self, - alphas: &[u32], - t: usize, - n: usize, - ) -> (MpcotMsgForSender, MpcotMsgForReceiver) { - assert_eq!(alphas.len(), t); - assert!(t < n); - let mut s = vec![Block::ZERO; n]; - let mut r = vec![Block::ZERO; n]; - self.prg.random_blocks(&mut s); - r.copy_from_slice(&s); - - for alpha in alphas { - assert!((*alpha as usize) < n); - r[*alpha as usize] ^= self.delta; - - self.counter += 1; - } - (MpcotMsgForSender { s }, MpcotMsgForReceiver { r }) - } - - /// Performs the checks. - /// - /// # Arguments - /// - /// * `sender_msg` - The message that the ideal MPCOT sends to the sender. - /// * `receiver_msg` - The message that the ideal MPCOT sends to the receiver. - /// * `alphas` - The positions in each extension. - /// * `n` - The length of the vector. - pub fn check( - &self, - sender_msg: MpcotMsgForSender, - receiver_msg: MpcotMsgForReceiver, - alphas: &[u32], - t: usize, - n: usize, - ) -> bool { - assert_eq!(alphas.len(), t); - let MpcotMsgForSender { mut s } = sender_msg; - let MpcotMsgForReceiver { r } = receiver_msg; - - for alpha in alphas { - assert!((*alpha as usize) < n); - s[*alpha as usize] ^= self.delta; - } - - let res = s.iter_mut().zip(r.iter()).all(|(s, r)| *s == *r); - res - } -} - -#[cfg(test)] -mod tests { - use crate::ideal::ideal_mpcot::IdealMpcot; - - #[test] - fn ideal_mpcot_test() { - let mut ideal_mpcot = IdealMpcot::init(); - - let (sender_msg, receiver_msg) = ideal_mpcot.extend(&[1, 3, 4, 6], 4, 20); - assert!(ideal_mpcot.check(sender_msg, receiver_msg, &[1, 3, 4, 6], 4, 20)); - } -} diff --git a/crates/mpz-ot-core/src/ideal/ideal_rot.rs b/crates/mpz-ot-core/src/ideal/ideal_rot.rs deleted file mode 100644 index a5f2dfb8..00000000 --- a/crates/mpz-ot-core/src/ideal/ideal_rot.rs +++ /dev/null @@ -1,89 +0,0 @@ -//! Define ideal functionality of ROT with random choice bit. - -use mpz_core::{prg::Prg, Block}; -use serde::{Deserialize, Serialize}; - -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] -/// The message that sender receives from the ROT functionality. -pub struct RotMsgForSender { - /// The random blocks that sender receives from the ROT functionality. - pub qs: Vec<[Block; 2]>, -} - -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] -/// The message that receiver receives from the ROT functionality. -pub struct RotMsgForReceiver { - /// The random bits that receiver receives from the ROT functionality. - pub rs: Vec, - /// The chosen blocks that receiver receives from the ROT functionality. - pub ts: Vec, -} - -/// An ideal functionality for random OT -#[derive(Debug)] -pub struct IdealROT { - counter: usize, - prg: Prg, -} - -impl IdealROT { - /// Initiate the functionality - pub fn new() -> Self { - let prg = Prg::new(); - IdealROT { counter: 0, prg } - } - - /// Performs the extension with random choice bits. - /// - /// # Argument - /// - /// * `counter` - The number of ROT to extend. - pub fn extend(&mut self, counter: usize) -> (RotMsgForSender, RotMsgForReceiver) { - let mut qs1 = vec![Block::ZERO; counter]; - let mut qs2 = vec![Block::ZERO; counter]; - - self.prg.random_blocks(&mut qs1); - self.prg.random_blocks(&mut qs2); - - let qs: Vec<[Block; 2]> = qs1.iter().zip(qs2).map(|(&q1, q2)| [q1, q2]).collect(); - - let mut rs = vec![false; counter]; - - self.prg.random_bools(&mut rs); - - let ts: Vec = qs - .iter() - .zip(rs.iter()) - .map(|(&q, &r)| q[r as usize]) - .collect(); - - self.counter += counter; - (RotMsgForSender { qs }, RotMsgForReceiver { rs, ts }) - } -} - -impl Default for IdealROT { - fn default() -> Self { - Self::new() - } -} - -#[cfg(test)] -mod tests { - use super::{IdealROT, RotMsgForReceiver}; - - #[test] - fn ideal_rot_test() { - let num = 100; - let mut ideal_rot = IdealROT::new(); - let (sender, receiver) = ideal_rot.extend(num); - - let qs = sender.qs; - let RotMsgForReceiver { rs, ts } = receiver; - - qs.iter() - .zip(ts) - .zip(rs) - .for_each(|((q, t), r)| assert_eq!(q[r as usize], t)); - } -} diff --git a/crates/mpz-ot-core/src/ideal/mod.rs b/crates/mpz-ot-core/src/ideal/mod.rs index ed22897e..8e1bcb61 100644 --- a/crates/mpz-ot-core/src/ideal/mod.rs +++ b/crates/mpz-ot-core/src/ideal/mod.rs @@ -1,5 +1,7 @@ //! Define ideal functionalities of OTs. -pub mod ideal_cot; -pub mod ideal_mpcot; -pub mod ideal_rot; -pub mod ideal_spcot; + +pub mod cot; +pub mod mpcot; +pub mod ot; +pub mod rot; +pub mod spcot; diff --git a/crates/mpz-ot-core/src/ideal/mpcot.rs b/crates/mpz-ot-core/src/ideal/mpcot.rs new file mode 100644 index 00000000..44a5595f --- /dev/null +++ b/crates/mpz-ot-core/src/ideal/mpcot.rs @@ -0,0 +1,97 @@ +//! Ideal functionality for the multi-point correlated OT. + +use mpz_core::{prg::Prg, Block}; +use rand::{Rng, SeedableRng}; +use rand_chacha::ChaCha8Rng; + +use crate::{MPCOTReceiverOutput, MPCOTSenderOutput, TransferId}; + +/// The ideal MPCOT functionality. +#[derive(Debug)] +pub struct IdealMpcot { + delta: Block, + transfer_id: TransferId, + counter: usize, + prg: Prg, +} + +impl IdealMpcot { + /// Creates a new ideal MPCOT functionality. + pub fn new(seed: Block, delta: Block) -> Self { + IdealMpcot { + delta, + transfer_id: TransferId::default(), + counter: 0, + prg: Prg::from_seed(seed), + } + } + + /// Returns the correlation, delta. + pub fn delta(&self) -> Block { + self.delta + } + + /// Sets the correlation, delta. + pub fn set_delta(&mut self, delta: Block) { + self.delta = delta; + } + + /// Performs the extension of MPCOT. + /// + /// # Argument + /// + /// * `alphas` - The positions in each extension. + /// * `n` - The length of the vector. + pub fn extend( + &mut self, + alphas: &[u32], + n: usize, + ) -> (MPCOTSenderOutput, MPCOTReceiverOutput) { + assert!(alphas.len() < n); + let mut s = vec![Block::ZERO; n]; + let mut r = vec![Block::ZERO; n]; + self.prg.random_blocks(&mut s); + r.copy_from_slice(&s); + + for alpha in alphas { + assert!((*alpha as usize) < n); + r[*alpha as usize] ^= self.delta; + + self.counter += 1; + } + + let id = self.transfer_id.next(); + + (MPCOTSenderOutput { id, s }, MPCOTReceiverOutput { id, r }) + } +} + +impl Default for IdealMpcot { + fn default() -> Self { + let mut rng = ChaCha8Rng::seed_from_u64(0); + IdealMpcot::new(rng.gen(), rng.gen()) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn ideal_mpcot_test() { + let mut ideal = IdealMpcot::default(); + + let alphas = [1, 3, 4, 6]; + let n = 20; + + let (MPCOTSenderOutput { mut s, .. }, MPCOTReceiverOutput { r, .. }) = + ideal.extend(&alphas, n); + + for alpha in alphas { + assert!((alpha as usize) < n); + s[alpha as usize] ^= ideal.delta(); + } + + assert!(s.iter_mut().zip(r.iter()).all(|(s, r)| *s == *r)); + } +} diff --git a/crates/mpz-ot-core/src/ideal/ot.rs b/crates/mpz-ot-core/src/ideal/ot.rs new file mode 100644 index 00000000..e389066e --- /dev/null +++ b/crates/mpz-ot-core/src/ideal/ot.rs @@ -0,0 +1,93 @@ +//! Ideal Chosen-Message Oblivious Transfer functionality. + +use crate::{OTReceiverOutput, OTSenderOutput, TransferId}; + +/// The ideal OT functionality. +#[derive(Debug, Default)] +pub struct IdealOT { + transfer_id: TransferId, + counter: usize, + /// Log of choices made by the receiver. + choices: Vec, +} + +impl IdealOT { + /// Creates a new ideal OT functionality. + pub fn new() -> Self { + IdealOT { + transfer_id: TransferId::default(), + counter: 0, + choices: Vec::new(), + } + } + + /// Returns the current transfer id. + pub fn transfer_id(&self) -> TransferId { + self.transfer_id + } + + /// Returns the number of OTs executed. + pub fn count(&self) -> usize { + self.counter + } + + /// Returns the choices made by the receiver. + pub fn choices(&self) -> &[bool] { + &self.choices + } + + /// Executes chosen-message oblivious transfers. + /// + /// # Arguments + /// + /// * `choices` - The choices made by the receiver. + /// * `msgs` - The sender's messages. + pub fn chosen( + &mut self, + choices: Vec, + msgs: Vec<[T; 2]>, + ) -> (OTSenderOutput, OTReceiverOutput) { + let chosen = choices + .iter() + .zip(msgs.iter()) + .map(|(&choice, [zero, one])| if choice { *one } else { *zero }) + .collect(); + + self.counter += choices.len(); + self.choices.extend(choices); + let id = self.transfer_id.next(); + + (OTSenderOutput { id }, OTReceiverOutput { id, msgs: chosen }) + } +} + +#[cfg(test)] +mod tests { + use mpz_core::Block; + use rand::{Rng, SeedableRng}; + use rand_chacha::ChaCha8Rng; + + use super::*; + + #[test] + fn test_ideal_ot() { + let mut rng = ChaCha8Rng::seed_from_u64(0); + let mut choices = vec![false; 100]; + rng.fill(&mut choices[..]); + + let msgs: Vec<[Block; 2]> = (0..100).map(|_| [rng.gen(), rng.gen()]).collect(); + + let (OTSenderOutput { .. }, OTReceiverOutput { msgs: chosen, .. }) = + IdealOT::default().chosen(choices.clone(), msgs.clone()); + + assert!(choices.into_iter().zip(msgs.into_iter().zip(chosen)).all( + |(choice, (msg, chosen))| { + if choice { + chosen == msg[1] + } else { + chosen == msg[0] + } + } + )); + } +} diff --git a/crates/mpz-ot-core/src/ideal/rot.rs b/crates/mpz-ot-core/src/ideal/rot.rs new file mode 100644 index 00000000..dd171c67 --- /dev/null +++ b/crates/mpz-ot-core/src/ideal/rot.rs @@ -0,0 +1,162 @@ +//! Ideal Random Oblivious Transfer functionality. + +use mpz_core::{prg::Prg, Block}; +use rand::{Rng, SeedableRng}; +use rand_chacha::ChaCha8Rng; + +use crate::{ROTReceiverOutput, ROTSenderOutput, TransferId}; + +/// The ideal ROT functionality. +#[derive(Debug)] +pub struct IdealROT { + transfer_id: TransferId, + counter: usize, + prg: Prg, +} + +impl IdealROT { + /// Creates a new ideal ROT functionality. + /// + /// # Arguments + /// + /// * `seed` - The seed for the PRG. + pub fn new(seed: Block) -> Self { + IdealROT { + transfer_id: TransferId::default(), + counter: 0, + prg: Prg::from_seed(seed), + } + } + + /// Returns the current transfer id. + pub fn transfer_id(&self) -> TransferId { + self.transfer_id + } + + /// Returns the number of OTs executed. + pub fn count(&self) -> usize { + self.counter + } + + /// Executes random oblivious transfers. + /// + /// # Arguments + /// + /// * `count` - The number of OTs to execute. + pub fn random( + &mut self, + count: usize, + ) -> (ROTSenderOutput<[Block; 2]>, ROTReceiverOutput) { + let mut choices = vec![false; count]; + + self.prg.random_bools(&mut choices); + + let msgs: Vec<[Block; 2]> = (0..count) + .map(|_| { + let mut msg = [Block::ZERO, Block::ZERO]; + self.prg.random_blocks(&mut msg); + msg + }) + .collect(); + + let chosen = choices + .iter() + .zip(msgs.iter()) + .map(|(&choice, [zero, one])| if choice { *one } else { *zero }) + .collect(); + + self.counter += count; + let id = self.transfer_id.next(); + + ( + ROTSenderOutput { id, msgs }, + ROTReceiverOutput { + id, + choices, + msgs: chosen, + }, + ) + } + + /// Executes random oblivious transfers with choices provided by the receiver. + /// + /// # Arguments + /// + /// * `choices` - The choices made by the receiver. + pub fn random_with_choices( + &mut self, + choices: Vec, + ) -> (ROTSenderOutput<[Block; 2]>, ROTReceiverOutput) { + let msgs: Vec<[Block; 2]> = (0..choices.len()) + .map(|_| { + let mut msg = [Block::ZERO, Block::ZERO]; + self.prg.random_blocks(&mut msg); + msg + }) + .collect(); + + let chosen = choices + .iter() + .zip(msgs.iter()) + .map(|(&choice, [zero, one])| if choice { *one } else { *zero }) + .collect(); + + self.counter += choices.len(); + let id = self.transfer_id.next(); + + ( + ROTSenderOutput { id, msgs }, + ROTReceiverOutput { + id, + choices, + msgs: chosen, + }, + ) + } +} + +impl Default for IdealROT { + fn default() -> Self { + let mut rng = ChaCha8Rng::seed_from_u64(0); + Self::new(rng.gen()) + } +} + +#[cfg(test)] +mod tests { + use crate::test::assert_rot; + + use super::*; + + #[test] + fn test_ideal_rot() { + let ( + ROTSenderOutput { msgs, .. }, + ROTReceiverOutput { + choices, + msgs: received, + .. + }, + ) = IdealROT::default().random(100); + + assert_rot(&choices, &msgs, &received) + } + + #[test] + fn test_ideal_rot_with_choices() { + let mut rng = ChaCha8Rng::seed_from_u64(0); + let mut choices = vec![false; 100]; + rng.fill(&mut choices[..]); + + let ( + ROTSenderOutput { msgs, .. }, + ROTReceiverOutput { + choices, + msgs: received, + .. + }, + ) = IdealROT::default().random_with_choices(choices); + + assert_rot(&choices, &msgs, &received) + } +} diff --git a/crates/mpz-ot-core/src/ideal/ideal_spcot.rs b/crates/mpz-ot-core/src/ideal/spcot.rs similarity index 51% rename from crates/mpz-ot-core/src/ideal/ideal_spcot.rs rename to crates/mpz-ot-core/src/ideal/spcot.rs index c30a5fb9..12c5f829 100644 --- a/crates/mpz-ot-core/src/ideal/ideal_spcot.rs +++ b/crates/mpz-ot-core/src/ideal/spcot.rs @@ -1,25 +1,14 @@ -//! Define ideal functionality of SPCOT. +//! Ideal functionality for single-point correlated OT. use mpz_core::{prg::Prg, Block}; -use serde::{Deserialize, Serialize}; -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] -/// The message that sender receivers from the SPCOT functionality. -pub struct SpcotMsgForSender { - /// The random blocks that sender receives from the SPCOT functionality. - pub v: Vec>, -} - -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] -/// The message that receiver receives from the SPCOT functionality. -pub struct SpcotMsgForReceiver { - /// The random blocks that receiver receives from the SPCOT functionality. - pub w: Vec>, -} +use crate::{SPCOTReceiverOutput, SPCOTSenderOutput, TransferId}; -#[allow(missing_docs)] +/// The ideal SPCOT functionality. +#[derive(Debug)] pub struct IdealSpcot { delta: Block, + transfer_id: TransferId, counter: usize, prg: Prg, } @@ -31,6 +20,7 @@ impl IdealSpcot { let delta = prg.random_block(); IdealSpcot { delta, + transfer_id: TransferId::default(), counter: 0, prg, } @@ -41,6 +31,7 @@ impl IdealSpcot { let prg = Prg::new(); IdealSpcot { delta, + transfer_id: TransferId::default(), counter: 0, prg, } @@ -51,7 +42,10 @@ impl IdealSpcot { /// # Argument /// /// * `pos` - The positions in each extension. - pub fn extend(&mut self, pos: &[(usize, u32)]) -> (SpcotMsgForSender, SpcotMsgForReceiver) { + pub fn extend( + &mut self, + pos: &[(usize, u32)], + ) -> (SPCOTSenderOutput, SPCOTReceiverOutput) { let mut v = vec![]; let mut w = vec![]; @@ -66,38 +60,10 @@ impl IdealSpcot { w.push(w_tmp); self.counter += n; } - (SpcotMsgForSender { v }, SpcotMsgForReceiver { w }) - } - /// Checks if the outputs satisfy the relation with Delta, this is only used for test. - /// - /// # Arguments - /// - /// * `sender_msg` - The message that the ideal SPCOT sends to the sender. - /// * `receiver_msg` - The message that the ideal SPCOT sends to the receiver. - pub fn check( - &self, - sender_msg: SpcotMsgForSender, - receiver_msg: SpcotMsgForReceiver, - pos: &[(usize, u32)], - ) -> bool { - let SpcotMsgForSender { mut v } = sender_msg; - let SpcotMsgForReceiver { w } = receiver_msg; + let id = self.transfer_id.next(); - v.iter_mut() - .zip(w.iter()) - .zip(pos.iter()) - .for_each(|((v, w), (n, p))| { - assert_eq!(v.len(), *n); - assert_eq!(w.len(), *n); - v[*p as usize] ^= self.delta; - }); - - let res = v - .iter() - .zip(w.iter()) - .all(|(v, w)| v.iter().zip(w.iter()).all(|(x, y)| *x == *y)); - res + (SPCOTSenderOutput { id, v }, SPCOTReceiverOutput { id, w }) } } @@ -109,14 +75,30 @@ impl Default for IdealSpcot { #[cfg(test)] mod tests { - use crate::ideal::ideal_spcot::IdealSpcot; + use super::*; #[test] fn ideal_spcot_test() { let mut ideal_spcot = IdealSpcot::new(); + let delta = ideal_spcot.delta; + + let pos = [(10, 2), (20, 3)]; - let (sender_msg, receiver_msg) = ideal_spcot.extend(&[(10, 2), (20, 3)]); + let (SPCOTSenderOutput { mut v, .. }, SPCOTReceiverOutput { w, .. }) = + ideal_spcot.extend(&pos); + + v.iter_mut() + .zip(w.iter()) + .zip(pos.iter()) + .for_each(|((v, w), (n, p))| { + assert_eq!(v.len(), *n); + assert_eq!(w.len(), *n); + v[*p as usize] ^= delta; + }); - assert!(ideal_spcot.check(sender_msg, receiver_msg, &[(10, 2), (20, 3)])); + assert!(v + .iter() + .zip(w.iter()) + .all(|(v, w)| v.iter().zip(w.iter()).all(|(x, y)| *x == *y))); } } diff --git a/crates/mpz-ot-core/src/kos/error.rs b/crates/mpz-ot-core/src/kos/error.rs index 3e230367..7acbcd3d 100644 --- a/crates/mpz-ot-core/src/kos/error.rs +++ b/crates/mpz-ot-core/src/kos/error.rs @@ -1,3 +1,5 @@ +use crate::TransferId; + /// Errors that can occur when using the KOS15 sender. #[derive(Debug, thiserror::Error)] #[allow(missing_docs)] @@ -9,7 +11,7 @@ pub enum SenderError { #[error("count mismatch: expected {0}, got {1}")] CountMismatch(usize, usize), #[error("id mismatch: expected {0}, got {1}")] - IdMismatch(u32, u32), + IdMismatch(TransferId, TransferId), #[error("invalid extend")] InvalidExtend, #[error("consistency check failed")] @@ -29,7 +31,7 @@ pub enum ReceiverError { #[error("count mismatch: expected {0}, got {1}")] CountMismatch(usize, usize), #[error("id mismatch: expected {0}, got {1}")] - IdMismatch(u32, u32), + IdMismatch(TransferId, TransferId), #[error("not enough OTs are setup: expected {0}, actual {1}")] InsufficientSetup(usize, usize), #[error("invalid payload")] @@ -45,7 +47,7 @@ pub enum ReceiverVerifyError { #[error("tape was not recorded")] TapeNotRecorded, #[error("invalid transfer id: {0}")] - InvalidTransferId(u32), + InvalidTransferId(TransferId), #[error("payload inconsistent")] InconsistentPayload, } diff --git a/crates/mpz-ot-core/src/kos/mod.rs b/crates/mpz-ot-core/src/kos/mod.rs index 42288251..bf3e2b41 100644 --- a/crates/mpz-ot-core/src/kos/mod.rs +++ b/crates/mpz-ot-core/src/kos/mod.rs @@ -321,13 +321,15 @@ mod tests { sender_keys.derandomize(derandomize).unwrap(); let payload = sender_keys.encrypt_blocks(&data).unwrap(); + let id = payload.id; + let received = receiver_keys.decrypt_blocks(payload).unwrap(); assert_eq!(received, expected); let receiver = receiver.start_verification(delta).unwrap(); - receiver.remove_record(0).unwrap().verify(&data).unwrap(); + receiver.remove_record(id).unwrap().verify(&data).unwrap(); } #[rstest] @@ -359,6 +361,8 @@ mod tests { sender_keys.derandomize(derandomize).unwrap(); let payload = sender_keys.encrypt_blocks(&data).unwrap(); + let id = payload.id; + let received = receiver_keys.decrypt_blocks(payload).unwrap(); assert_eq!(received, expected); @@ -368,7 +372,7 @@ mod tests { let receiver = receiver.start_verification(delta).unwrap(); let err = receiver - .remove_record(0) + .remove_record(id) .unwrap() .verify(&data) .unwrap_err(); diff --git a/crates/mpz-ot-core/src/kos/msgs.rs b/crates/mpz-ot-core/src/kos/msgs.rs index d332ddd0..6710f274 100644 --- a/crates/mpz-ot-core/src/kos/msgs.rs +++ b/crates/mpz-ot-core/src/kos/msgs.rs @@ -3,6 +3,8 @@ use mpz_core::Block; use serde::{Deserialize, Serialize}; +use crate::TransferId; + /// Extension message sent by the receiver to agree upon the number of OTs to set up. #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] pub struct StartExtend { @@ -60,7 +62,7 @@ pub struct Check { #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] pub struct SenderPayload { /// Transfer ID - pub id: u32, + pub id: TransferId, /// Sender's ciphertexts pub ciphertexts: Ciphertexts, } diff --git a/crates/mpz-ot-core/src/kos/receiver.rs b/crates/mpz-ot-core/src/kos/receiver.rs index fdc43b12..fdcad328 100644 --- a/crates/mpz-ot-core/src/kos/receiver.rs +++ b/crates/mpz-ot-core/src/kos/receiver.rs @@ -10,6 +10,7 @@ use crate::{ Aes128Ctr, ReceiverConfig, ReceiverError, Rng, RngSeed, CSP, SSP, }, msgs::Derandomize, + TransferId, }; use itybity::{FromBitIterator, IntoBits, ToBits}; @@ -26,7 +27,7 @@ use rayon::prelude::*; #[derive(Debug, Default)] struct Tape { - records: HashMap, + records: HashMap, } /// KOS15 receiver. @@ -94,7 +95,7 @@ impl Receiver { keys: Vec::default(), choices: Vec::default(), index: 0, - transfer_id: 0, + transfer_id: TransferId::default(), extended: false, unchecked_ts: Vec::default(), unchecked_choices: Vec::default(), @@ -106,7 +107,7 @@ impl Receiver { impl Receiver { /// Returns the current transfer id. - pub fn current_transfer_id(&self) -> u32 { + pub fn current_transfer_id(&self) -> TransferId { self.state.transfer_id } @@ -329,11 +330,9 @@ impl Receiver { )); } - let id = self.state.transfer_id; + let id = self.state.transfer_id.next(); let index = self.state.index - self.state.keys.len(); - self.state.transfer_id += 1; - Ok(ReceiverKeys { id, index, @@ -383,7 +382,7 @@ impl Receiver { /// # Arguments /// /// * `id` - The transfer id - pub fn remove_record(&self, id: u32) -> Result { + pub fn remove_record(&self, id: TransferId) -> Result { let PayloadRecordNoDelta { index, choices, @@ -418,7 +417,7 @@ impl Receiver { /// payload. pub struct ReceiverKeys { /// Transfer ID - id: u32, + id: TransferId, /// Start index of the OTs index: usize, /// Decryption keys @@ -437,7 +436,7 @@ opaque_debug::implement!(ReceiverKeys); impl ReceiverKeys { /// Returns the transfer ID. - pub fn id(&self) -> u32 { + pub fn id(&self) -> TransferId { self.id } @@ -713,7 +712,7 @@ pub mod state { /// Current OT index pub(super) index: usize, /// Current transfer id - pub(super) transfer_id: u32, + pub(super) transfer_id: TransferId, /// Whether extension has occurred yet /// diff --git a/crates/mpz-ot-core/src/kos/sender.rs b/crates/mpz-ot-core/src/kos/sender.rs index 59bfd5bb..24917940 100644 --- a/crates/mpz-ot-core/src/kos/sender.rs +++ b/crates/mpz-ot-core/src/kos/sender.rs @@ -5,6 +5,7 @@ use crate::{ Aes128Ctr, Rng, RngSeed, SenderConfig, SenderError, CSP, SSP, }, msgs::Derandomize, + TransferId, }; use cipher::{KeyIvInit, StreamCipher}; @@ -80,7 +81,7 @@ impl Sender { delta, rngs, keys: Vec::default(), - transfer_id: 0, + transfer_id: TransferId::default(), counter: 0, extended: false, unchecked_qs: Vec::default(), @@ -293,8 +294,7 @@ impl Sender { return Err(SenderError::InsufficientSetup(count, self.state.keys.len())); } - let id = self.state.transfer_id; - self.state.transfer_id += 1; + let id = self.state.transfer_id.next(); Ok(SenderKeys { id, @@ -311,7 +311,7 @@ impl Sender { /// other payloads. pub struct SenderKeys { /// Transfer ID - id: u32, + id: TransferId, /// Encryption keys keys: Vec<[Block; 2]>, /// Derandomization @@ -320,7 +320,7 @@ pub struct SenderKeys { impl SenderKeys { /// Returns the transfer ID. - pub fn id(&self) -> u32 { + pub fn id(&self) -> TransferId { self.id } @@ -486,7 +486,7 @@ pub mod state { pub(super) keys: Vec<[Block; 2]>, /// Current transfer id - pub(super) transfer_id: u32, + pub(super) transfer_id: TransferId, /// Current OT counter pub(super) counter: usize, diff --git a/crates/mpz-ot-core/src/lib.rs b/crates/mpz-ot-core/src/lib.rs index f357bf8b..1c932212 100644 --- a/crates/mpz-ot-core/src/lib.rs +++ b/crates/mpz-ot-core/src/lib.rs @@ -19,8 +19,145 @@ clippy::all )] +use serde::{Deserialize, Serialize}; + pub mod chou_orlandi; pub mod ferret; pub mod ideal; pub mod kos; pub mod msgs; +#[cfg(test)] +pub(crate) mod test; + +/// An oblivious transfer identifier. +/// +/// Multiple transfers may be batched together under the same transfer ID. +#[derive( + Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize, +)] +pub struct TransferId(u64); + +impl std::fmt::Display for TransferId { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "TransferId({})", self.0) + } +} + +impl TransferId { + /// Returns the current transfer ID, incrementing `self` in-place. + pub(crate) fn next(&mut self) -> Self { + let id = *self; + self.0 += 1; + id + } +} + +/// The output the sender receives from the COT functionality. +#[derive(Debug)] +pub struct COTSenderOutput { + /// The transfer id. + pub id: TransferId, + /// The `0-bit` messages. + pub msgs: Vec, +} + +/// The output the receiver receives from the COT functionality. +#[derive(Debug)] +pub struct COTReceiverOutput { + /// The transfer id. + pub id: TransferId, + /// The chosen messages. + pub msgs: Vec, +} + +/// The output the sender receives from the random COT functionality. +#[derive(Debug)] +pub struct RCOTSenderOutput { + /// The transfer id. + pub id: TransferId, + /// The msgs. + pub msgs: Vec, +} + +/// The output the receiver receives from the random COT functionality. +#[derive(Debug)] +pub struct RCOTReceiverOutput { + /// The transfer id. + pub id: TransferId, + /// The choice bits. + pub choices: Vec, + /// The chosen messages. + pub msgs: Vec, +} + +/// The output the sender receives from the ROT functionality. +#[derive(Debug)] +pub struct ROTSenderOutput { + /// The transfer id. + pub id: TransferId, + /// The random messages. + pub msgs: Vec, +} + +/// The output the receiver receives from the ROT functionality. +#[derive(Debug)] +pub struct ROTReceiverOutput { + /// The transfer id. + pub id: TransferId, + /// The choice bits. + pub choices: Vec, + /// The chosen messages. + pub msgs: Vec, +} + +/// The output the sender receives from the OT functionality. +#[derive(Debug)] +pub struct OTSenderOutput { + /// The transfer id. + pub id: TransferId, +} + +/// The output the receiver receives from the OT functionality. +#[derive(Debug)] +pub struct OTReceiverOutput { + /// The transfer id. + pub id: TransferId, + /// The chosen messages. + pub msgs: Vec, +} + +/// The output that sender receivers from the SPCOT functionality. +#[derive(Debug)] +pub struct SPCOTSenderOutput { + /// The transfer id. + pub id: TransferId, + /// The random blocks that sender receives from the SPCOT functionality. + pub v: Vec>, +} + +/// The output that receiver receives from the SPCOT functionality. +#[derive(Debug)] +pub struct SPCOTReceiverOutput { + /// The transfer id. + pub id: TransferId, + /// The random blocks that receiver receives from the SPCOT functionality. + pub w: Vec>, +} + +/// The output that sender receives from the MPCOT functionality. +#[derive(Debug)] +pub struct MPCOTSenderOutput { + /// The transfer id. + pub id: TransferId, + /// The random blocks that sender receives from the MPCOT functionality. + pub s: Vec, +} + +/// The output that receiver receives from the MPCOT functionality. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct MPCOTReceiverOutput { + /// The transfer id. + pub id: TransferId, + /// The random blocks that receiver receives from the MPCOT functionality. + pub r: Vec, +} diff --git a/crates/mpz-ot-core/src/msgs.rs b/crates/mpz-ot-core/src/msgs.rs index 1800cb53..809443a3 100644 --- a/crates/mpz-ot-core/src/msgs.rs +++ b/crates/mpz-ot-core/src/msgs.rs @@ -2,13 +2,15 @@ use serde::{Deserialize, Serialize}; +use crate::TransferId; + /// A message sent by the receiver which a sender can use to perform /// Beaver derandomization. #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] #[serde(try_from = "UncheckedDerandomize")] pub struct Derandomize { /// Transfer ID - pub id: u32, + pub id: TransferId, /// The number of choices to derandomize. pub count: u32, /// Correction bits @@ -17,7 +19,7 @@ pub struct Derandomize { #[derive(Debug, Deserialize)] struct UncheckedDerandomize { - id: u32, + id: TransferId, count: u32, flip: Vec, } @@ -51,14 +53,14 @@ mod tests { #[test] fn test_unchecked_derandomize() { assert!(Derandomize::try_from(UncheckedDerandomize { - id: 0, + id: TransferId::default(), count: 0, flip: vec![], }) .is_ok()); assert!(Derandomize::try_from(UncheckedDerandomize { - id: 0, + id: TransferId::default(), count: 9, flip: vec![0], }) diff --git a/crates/mpz-ot-core/src/test.rs b/crates/mpz-ot-core/src/test.rs new file mode 100644 index 00000000..010c6e71 --- /dev/null +++ b/crates/mpz-ot-core/src/test.rs @@ -0,0 +1,27 @@ +use mpz_core::Block; + +/// Asserts the correctness of correlated oblivious transfer. +pub(crate) fn assert_cot(delta: Block, choices: &[bool], msgs: &[Block], received: &[Block]) { + assert!(choices.into_iter().zip(msgs.into_iter().zip(received)).all( + |(&choice, (&msg, &received))| { + if choice { + received == msg ^ delta + } else { + received == msg + } + } + )); +} + +/// Asserts the correctness of random oblivious transfer. +pub(crate) fn assert_rot(choices: &[bool], msgs: &[[T; 2]], received: &[T]) { + assert!(choices.into_iter().zip(msgs.into_iter().zip(received)).all( + |(&choice, (&msg, &received))| { + if choice { + received == msg[1] + } else { + received == msg[0] + } + } + )); +} diff --git a/crates/mpz-ot/Cargo.toml b/crates/mpz-ot/Cargo.toml index 16fec565..96b45c73 100644 --- a/crates/mpz-ot/Cargo.toml +++ b/crates/mpz-ot/Cargo.toml @@ -10,9 +10,9 @@ workspace = true name = "mpz_ot" [features] -default = ["ideal", "rayon"] +default = ["rayon"] rayon = ["mpz-ot-core/rayon"] -ideal = [] +ideal = ["mpz-common/ideal"] [dependencies] mpz-core.workspace = true @@ -38,7 +38,7 @@ serio.workspace = true cfg-if.workspace = true [dev-dependencies] -mpz-common = { workspace = true, features = ["test-utils"] } +mpz-common = { workspace = true, features = ["test-utils", "ideal"] } rstest = { workspace = true } criterion = { workspace = true, features = ["async_tokio"] } tokio = { workspace = true, features = [ diff --git a/crates/mpz-ot/src/chou_orlandi/mod.rs b/crates/mpz-ot/src/chou_orlandi/mod.rs index 6b58edbb..df3fda7a 100644 --- a/crates/mpz-ot/src/chou_orlandi/mod.rs +++ b/crates/mpz-ot/src/chou_orlandi/mod.rs @@ -16,21 +16,21 @@ //! let mut sender = Sender::default(); //! let mut receiver = Receiver::default(); //! -//! // Perform the setup phase. -//! let (sender_res, receiver_res) = futures::try_join!( +//! // Perform the setup. +//! futures::try_join!( //! sender.setup(&mut ctx_sender), //! receiver.setup(&mut ctx_receiver) //! ).unwrap(); //! -//! // Perform the transfer phase. +//! // Perform the transfer. //! let messages = vec![[Block::ZERO, Block::ONES], [Block::ZERO, Block::ONES]]; //! -//! let (_, received) = futures::try_join!( +//! let (_, output_receiver) = futures::try_join!( //! sender.send(&mut ctx_sender, &messages), //! receiver.receive(&mut ctx_receiver, &[true, false]) //! ).unwrap(); //! -//! assert_eq!(received, vec![Block::ONES, Block::ZERO]); +//! assert_eq!(output_receiver.msgs, vec![Block::ONES, Block::ZERO]); //! # }); //! ``` @@ -49,6 +49,7 @@ pub use mpz_ot_core::chou_orlandi::{ #[cfg(test)] mod tests { + use futures::TryFutureExt; use itybity::ToBits; use mpz_common::executor::test_st_executor; use mpz_common::Context; @@ -57,7 +58,7 @@ mod tests { use rand_chacha::ChaCha12Rng; use rand_core::SeedableRng; - use crate::{CommittedOTReceiver, OTReceiver, OTSender, OTSetup, VerifiableOTSender}; + use crate::{CommittedOTReceiver, OTError, OTReceiver, OTSender, OTSetup, VerifiableOTSender}; use super::*; use rstest::*; @@ -110,17 +111,18 @@ mod tests { ) .await; - let (sender_res, receiver_res) = tokio::join!( - sender.send(&mut sender_ctx, &data), - receiver.receive(&mut receiver_ctx, &choices) - ); - - sender_res.unwrap(); - let received = receiver_res.unwrap(); + let (output_sender, output_receiver) = tokio::try_join!( + sender.send(&mut sender_ctx, &data).map_err(OTError::from), + receiver + .receive(&mut receiver_ctx, &choices) + .map_err(OTError::from) + ) + .unwrap(); let expected = choose(data.iter().copied(), choices.iter_lsb0()).collect::>(); - assert_eq!(received, expected); + assert_eq!(output_sender.id, output_receiver.id); + assert_eq!(output_receiver.msgs, expected); } #[rstest] diff --git a/crates/mpz-ot/src/chou_orlandi/receiver.rs b/crates/mpz-ot/src/chou_orlandi/receiver.rs index 58e499df..91145515 100644 --- a/crates/mpz-ot/src/chou_orlandi/receiver.rs +++ b/crates/mpz-ot/src/chou_orlandi/receiver.rs @@ -4,6 +4,7 @@ use itybity::BitIterable; use mpz_cointoss as cointoss; use mpz_common::Context; use mpz_core::Block; +use mpz_ot_core::chou_orlandi::msgs::SenderPayload; use mpz_ot_core::chou_orlandi::{ receiver_state as state, Receiver as ReceiverCore, ReceiverConfig, }; @@ -13,7 +14,7 @@ use rand::{thread_rng, Rng}; use serio::{stream::IoStreamExt as _, SinkExt as _}; use utils_aio::non_blocking_backend::{Backend, NonBlockingBackend}; -use crate::{CommittedOTReceiver, OTError, OTReceiver, OTSetup}; +use crate::{CommittedOTReceiver, OTError, OTReceiver, OTReceiverOutput, OTSetup}; use super::ReceiverError; @@ -136,7 +137,11 @@ where Ctx: Context, T: BitIterable + Send + Sync + Clone + 'static, { - async fn receive(&mut self, ctx: &mut Ctx, choices: &[T]) -> Result, OTError> { + async fn receive( + &mut self, + ctx: &mut Ctx, + choices: &[T], + ) -> Result, OTError> { let mut receiver = std::mem::replace(&mut self.state, State::Error) .try_into_setup() .map_err(ReceiverError::from)?; @@ -150,19 +155,20 @@ where ctx.io_mut().send(receiver_payload).await?; - let sender_payload = ctx.io_mut().expect_next().await?; + let sender_payload: SenderPayload = ctx.io_mut().expect_next().await?; + let id = sender_payload.id; - let (receiver, data) = Backend::spawn(move || { + let (receiver, msgs) = Backend::spawn(move || { receiver .receive(sender_payload) - .map(|data| (receiver, data)) + .map(|msgs| (receiver, msgs)) }) .await .map_err(ReceiverError::from)?; self.state = State::Setup(receiver); - Ok(data) + Ok(OTReceiverOutput { id, msgs }) } } diff --git a/crates/mpz-ot/src/chou_orlandi/sender.rs b/crates/mpz-ot/src/chou_orlandi/sender.rs index 7ba6121d..610f891d 100644 --- a/crates/mpz-ot/src/chou_orlandi/sender.rs +++ b/crates/mpz-ot/src/chou_orlandi/sender.rs @@ -1,4 +1,6 @@ -use crate::{chou_orlandi::SenderError, OTError, OTSender, OTSetup, VerifiableOTSender}; +use crate::{ + chou_orlandi::SenderError, OTError, OTSender, OTSenderOutput, OTSetup, VerifiableOTSender, +}; use async_trait::async_trait; use mpz_cointoss as cointoss; @@ -99,7 +101,11 @@ impl OTSetup for Sender { #[async_trait] impl OTSender for Sender { - async fn send(&mut self, ctx: &mut Ctx, input: &[[Block; 2]]) -> Result<(), OTError> { + async fn send( + &mut self, + ctx: &mut Ctx, + input: &[[Block; 2]], + ) -> Result { let mut sender = std::mem::replace(&mut self.state, State::Error) .try_into_setup() .map_err(SenderError::from)?; @@ -115,11 +121,13 @@ impl OTSender for Sender { .await .map_err(SenderError::from)?; + let id = payload.id; + ctx.io_mut().send(payload).await?; self.state = State::Setup(sender); - Ok(()) + Ok(OTSenderOutput { id }) } } diff --git a/crates/mpz-ot/src/ideal/cot.rs b/crates/mpz-ot/src/ideal/cot.rs index 988066a1..a65809ed 100644 --- a/crates/mpz-ot/src/ideal/cot.rs +++ b/crates/mpz-ot/src/ideal/cot.rs @@ -1,41 +1,58 @@ //! Ideal functionality for correlated oblivious transfer. -use crate::{COTReceiver, COTSender, OTError, OTSetup}; use async_trait::async_trait; -use futures::{channel::mpsc, StreamExt}; -use mpz_common::Context; + +use mpz_common::{ + ideal::{ideal_f2p, Alice, Bob}, + Context, +}; use mpz_core::Block; +use mpz_ot_core::{ + ideal::cot::IdealCOT, COTReceiverOutput, COTSenderOutput, RCOTReceiverOutput, RCOTSenderOutput, +}; -/// Ideal OT sender. -#[derive(Debug)] -pub struct IdealCOTSender { - sender: mpsc::Sender>, - delta: Block, +use crate::{COTReceiver, COTSender, OTError, OTSetup, RandomCOTReceiver}; + +fn cot( + f: &mut IdealCOT, + sender_count: usize, + choices: Vec, +) -> (COTSenderOutput, COTReceiverOutput) { + assert_eq!(sender_count, choices.len()); + + f.correlated(choices) } -/// Ideal OT receiver. -#[derive(Debug)] -pub struct IdealCOTReceiver { - receiver: mpsc::Receiver>, +fn rcot( + f: &mut IdealCOT, + sender_count: usize, + receiver_count: usize, +) -> (RCOTSenderOutput, RCOTReceiverOutput) { + assert_eq!(sender_count, receiver_count); + + f.random_correlated(sender_count) } -/// Creates a pair of ideal COT sender and receiver. -pub fn ideal_cot_pair( - delta: Block, -) -> (IdealCOTSender, IdealCOTReceiver) { - let (sender, receiver) = mpsc::channel(10); +/// Returns an ideal COT sender and receiver. +pub fn ideal_cot() -> (IdealCOTSender, IdealCOTReceiver) { + let (alice, bob) = ideal_f2p(IdealCOT::default()); + (IdealCOTSender(alice), IdealCOTReceiver(bob)) +} - ( - IdealCOTSender { sender, delta }, - IdealCOTReceiver { receiver }, - ) +/// Returns an ideal random COT sender and receiver. +pub fn ideal_rcot() -> (IdealCOTSender, IdealCOTReceiver) { + let (alice, bob) = ideal_f2p(IdealCOT::default()); + (IdealCOTSender(alice), IdealCOTReceiver(bob)) } +/// Ideal OT sender. +#[derive(Debug, Clone)] +pub struct IdealCOTSender(Alice); + #[async_trait] -impl OTSetup for IdealCOTSender +impl OTSetup for IdealCOTSender where Ctx: Context, - T: Send + Sync, { async fn setup(&mut self, _ctx: &mut Ctx) -> Result<(), OTError> { Ok(()) @@ -43,25 +60,24 @@ where } #[async_trait] -impl COTSender for IdealCOTSender { - async fn send_correlated(&mut self, _ctx: &mut Ctx, msgs: &[Block]) -> Result<(), OTError> { - self.sender - .try_send( - msgs.iter() - .map(|msg| [*msg, *msg ^ self.delta]) - .collect::>(), - ) - .expect("IdealCOTSender should be able to send"); - - Ok(()) +impl COTSender for IdealCOTSender { + async fn send_correlated( + &mut self, + ctx: &mut Ctx, + count: usize, + ) -> Result, OTError> { + Ok(self.0.call(ctx, count, cot).await) } } +/// Ideal OT receiver. +#[derive(Debug, Clone)] +pub struct IdealCOTReceiver(Bob); + #[async_trait] -impl OTSetup for IdealCOTReceiver +impl OTSetup for IdealCOTReceiver where Ctx: Context, - T: Send + Sync, { async fn setup(&mut self, _ctx: &mut Ctx) -> Result<(), OTError> { Ok(()) @@ -69,70 +85,23 @@ where } #[async_trait] -impl COTReceiver for IdealCOTReceiver { +impl COTReceiver for IdealCOTReceiver { async fn receive_correlated( &mut self, - _ctx: &mut Ctx, + ctx: &mut Ctx, choices: &[bool], - ) -> Result, OTError> { - let payload = self - .receiver - .next() - .await - .expect("IdealCOTSender should send a value"); - - Ok(payload - .into_iter() - .zip(choices) - .map(|(v, c)| { - let [low, high] = v; - if *c { - high - } else { - low - } - }) - .collect()) + ) -> Result, OTError> { + Ok(self.0.call(ctx, choices.to_vec(), cot).await) } } -#[cfg(test)] -mod tests { - use itybity::IntoBits; - use mpz_common::executor::test_st_executor; - use rand::Rng; - use rand_chacha::ChaCha12Rng; - use rand_core::SeedableRng; - - use super::*; - - // Test that the sender and receiver can be used to send and receive values - #[tokio::test] - async fn test_ideal_cot_owned() { - let mut rng = ChaCha12Rng::seed_from_u64(0); - let (mut ctx_sender, mut ctx_receiver) = test_st_executor(8); - - let values = Block::random_vec(&mut rng, 8); - let choices = rng.gen::().into_lsb0_vec(); - let delta = Block::from([42u8; 16]); - let (mut sender, mut receiver) = ideal_cot_pair::(delta); - - sender - .send_correlated(&mut ctx_sender, &values) - .await - .unwrap(); - - let received = receiver - .receive_correlated(&mut ctx_receiver, &choices) - .await - .unwrap(); - - let expected = values - .into_iter() - .zip(choices) - .map(|(v, c)| if c { v ^ delta } else { v }) - .collect::>(); - - assert_eq!(received, expected); +#[async_trait] +impl RandomCOTReceiver for IdealCOTReceiver { + async fn receive_random_correlated( + &mut self, + ctx: &mut Ctx, + count: usize, + ) -> Result, OTError> { + Ok(self.0.call(ctx, count, rcot).await) } } diff --git a/crates/mpz-ot/src/ideal/mod.rs b/crates/mpz-ot/src/ideal/mod.rs index a06697a9..e8f57c57 100644 --- a/crates/mpz-ot/src/ideal/mod.rs +++ b/crates/mpz-ot/src/ideal/mod.rs @@ -2,5 +2,4 @@ pub mod cot; pub mod ot; -pub mod rcot; pub mod rot; diff --git a/crates/mpz-ot/src/ideal/ot.rs b/crates/mpz-ot/src/ideal/ot.rs index b5745242..60586c2f 100644 --- a/crates/mpz-ot/src/ideal/ot.rs +++ b/crates/mpz-ot/src/ideal/ot.rs @@ -1,56 +1,51 @@ -//! Ideal functionality for oblivious transfer. +//! Ideal functionality for correlated oblivious transfer. + +use std::marker::PhantomData; -use crate::{ - CommittedOTReceiver, CommittedOTSender, OTError, OTReceiver, OTSender, OTSetup, - VerifiableOTReceiver, VerifiableOTSender, -}; use async_trait::async_trait; -use futures::{ - channel::{mpsc, oneshot}, - StreamExt, + +use mpz_common::{ + ideal::{ideal_f2p, Alice, Bob}, + Context, }; -use mpz_common::Context; +use mpz_ot_core::ideal::ot::IdealOT; -/// Ideal OT sender. -#[derive(Debug)] -pub struct IdealOTSender { - sender: mpsc::Sender>, - msgs: Vec<[T; 2]>, - choices_receiver: Option>>, -} +use crate::{ + CommittedOTReceiver, OTError, OTReceiver, OTReceiverOutput, OTSender, OTSenderOutput, OTSetup, + VerifiableOTSender, +}; -/// Ideal OT receiver. -#[derive(Debug)] -pub struct IdealOTReceiver { - receiver: mpsc::Receiver>, - choices: Vec, - choices_sender: Option>>, +fn ot( + f: &mut IdealOT, + sender_msgs: Vec<[T; 2]>, + receiver_choices: Vec, +) -> (OTSenderOutput, OTReceiverOutput) { + assert_eq!(sender_msgs.len(), receiver_choices.len()); + + f.chosen(receiver_choices, sender_msgs) } -/// Creates a pair of ideal OT sender and receiver. -pub fn ideal_ot_pair() -> (IdealOTSender, IdealOTReceiver) { - let (sender, receiver) = mpsc::channel(10); - let (choices_sender, choices_receiver) = oneshot::channel(); +fn verify(f: &mut IdealOT, _: (), _: ()) -> (Vec, ()) { + (f.choices().to_vec(), ()) +} +/// Returns an ideal OT sender and receiver. +pub fn ideal_ot() -> (IdealOTSender, IdealOTReceiver) { + let (alice, bob) = ideal_f2p(IdealOT::default()); ( - IdealOTSender { - sender, - msgs: Vec::default(), - choices_receiver: Some(choices_receiver), - }, - IdealOTReceiver { - receiver, - choices: Vec::default(), - choices_sender: Some(choices_sender), - }, + IdealOTSender(alice, PhantomData), + IdealOTReceiver(bob, PhantomData), ) } +/// Ideal OT sender. +#[derive(Debug, Clone)] +pub struct IdealOTSender(Alice, PhantomData T>); + #[async_trait] impl OTSetup for IdealOTSender where Ctx: Context, - T: Send + Sync, { async fn setup(&mut self, _ctx: &mut Ctx) -> Result<(), OTError> { Ok(()) @@ -58,138 +53,55 @@ where } #[async_trait] -impl OTSender for IdealOTSender -where - Ctx: Context, - T: Send + Sync + Clone + 'static, +impl OTSender + for IdealOTSender<[T; 2]> { - async fn send(&mut self, _ctx: &mut Ctx, msgs: &[[T; 2]]) -> Result<(), OTError> { - self.msgs.extend(msgs.iter().cloned()); - - self.sender - .try_send(msgs.to_vec()) - .expect("DummySender should be able to send"); - - Ok(()) + async fn send(&mut self, ctx: &mut Ctx, msgs: &[[T; 2]]) -> Result { + Ok(self.0.call(ctx, msgs.to_vec(), ot).await) } } #[async_trait] -impl OTSetup for IdealOTReceiver -where - Ctx: Context, - T: Send + Sync, +impl VerifiableOTSender + for IdealOTSender<[T; 2]> { - async fn setup(&mut self, _ctx: &mut Ctx) -> Result<(), OTError> { - Ok(()) + async fn verify_choices(&mut self, ctx: &mut Ctx) -> Result, OTError> { + Ok(self.0.call(ctx, (), verify).await) } } -#[async_trait] -impl OTReceiver for IdealOTReceiver -where - Ctx: Context, - T: Send + Sync + 'static, -{ - async fn receive(&mut self, _ctx: &mut Ctx, choices: &[bool]) -> Result, OTError> { - self.choices.extend(choices.iter().copied()); - - let payload = self - .receiver - .next() - .await - .expect("DummySender should send a value"); - - Ok(payload - .into_iter() - .zip(choices) - .map(|(v, c)| { - let [low, high] = v; - if *c { - high - } else { - low - } - }) - .collect()) - } -} +/// Ideal OT receiver. +#[derive(Debug, Clone)] +pub struct IdealOTReceiver(Bob, PhantomData T>); #[async_trait] -impl VerifiableOTReceiver for IdealOTReceiver +impl OTSetup for IdealOTReceiver where Ctx: Context, - U: Send + Sync + 'static, - V: Send + Sync + 'static, { - async fn verify(&mut self, _ctx: &mut Ctx, _index: usize, _msgs: &[V]) -> Result<(), OTError> { + async fn setup(&mut self, _ctx: &mut Ctx) -> Result<(), OTError> { Ok(()) } } #[async_trait] -impl CommittedOTSender for IdealOTSender -where - Ctx: Context, - T: Send + Sync + Clone + 'static, +impl OTReceiver + for IdealOTReceiver { - async fn reveal(&mut self, _ctx: &mut Ctx) -> Result<(), OTError> { - Ok(()) + async fn receive( + &mut self, + ctx: &mut Ctx, + choices: &[bool], + ) -> Result, OTError> { + Ok(self.0.call(ctx, choices.to_vec(), ot).await) } } #[async_trait] -impl CommittedOTReceiver for IdealOTReceiver -where - Ctx: Context, - T: Send + Sync + 'static, +impl CommittedOTReceiver + for IdealOTReceiver { - async fn reveal_choices(&mut self, _ctx: &mut Ctx) -> Result<(), OTError> { - self.choices_sender - .take() - .expect("choices should not be revealed twice") - .send(self.choices.clone()) - .expect("DummySender should be able to send"); - - Ok(()) - } -} - -#[async_trait] -impl VerifiableOTSender for IdealOTSender -where - Ctx: Context, - T: Send + Sync + Clone + 'static, -{ - async fn verify_choices(&mut self, _ctx: &mut Ctx) -> Result, OTError> { - Ok(self - .choices_receiver - .take() - .expect("choices should not be verified twice") - .await - .expect("choices sender should not be dropped")) - } -} - -#[cfg(test)] -mod tests { - use mpz_common::executor::test_st_executor; - - use super::*; - - // Test that the sender and receiver can be used to send and receive values - #[tokio::test] - async fn test_ideal_ot_owned() { - let (mut ctx_sender, mut ctx_receiver) = test_st_executor(8); - - let values = vec![[0, 1], [2, 3]]; - let choices = vec![false, true]; - let (mut sender, mut receiver) = ideal_ot_pair::(); - - sender.send(&mut ctx_sender, &values).await.unwrap(); - - let received = receiver.receive(&mut ctx_receiver, &choices).await.unwrap(); - - assert_eq!(received, vec![0, 3]); + async fn reveal_choices(&mut self, ctx: &mut Ctx) -> Result<(), OTError> { + Ok(self.0.call(ctx, (), verify).await) } } diff --git a/crates/mpz-ot/src/ideal/rot.rs b/crates/mpz-ot/src/ideal/rot.rs index f1f02a2e..847edf16 100644 --- a/crates/mpz-ot/src/ideal/rot.rs +++ b/crates/mpz-ot/src/ideal/rot.rs @@ -1,51 +1,40 @@ //! Ideal functionality for random oblivious transfer. -use crate::{OTError, OTSetup, RandomOTReceiver, RandomOTSender}; use async_trait::async_trait; -use futures::{channel::mpsc, StreamExt}; -use mpz_common::Context; -use mpz_core::{prg::Prg, Block}; -use rand::Rng; -use rand_chacha::ChaCha12Rng; -use rand_core::{RngCore, SeedableRng}; -/// Ideal random OT sender. -#[derive(Debug)] -pub struct IdealRandomOTSender { - sender: mpsc::Sender>, - rng: ChaCha12Rng, -} +use mpz_common::{ + ideal::{ideal_f2p, Alice, Bob}, + Context, +}; +use mpz_core::Block; +use mpz_ot_core::{ideal::rot::IdealROT, ROTReceiverOutput, ROTSenderOutput}; -/// Ideal random OT receiver. -#[derive(Debug)] -pub struct IdealRandomOTReceiver { - receiver: mpsc::Receiver>, - rng: ChaCha12Rng, -} +use crate::{OTError, OTSetup, RandomOTReceiver, RandomOTSender}; + +fn rot( + f: &mut IdealROT, + sender_count: usize, + receiver_count: usize, +) -> (ROTSenderOutput<[Block; 2]>, ROTReceiverOutput) { + assert_eq!(sender_count, receiver_count); -/// Creates a pair of ideal random OT sender and receiver. -pub fn ideal_random_ot_pair( - seed: [u8; 32], -) -> (IdealRandomOTSender, IdealRandomOTReceiver) { - let (sender, receiver) = mpsc::channel(10); + f.random(sender_count) +} - ( - IdealRandomOTSender { - sender, - rng: ChaCha12Rng::from_seed(seed), - }, - IdealRandomOTReceiver { - receiver, - rng: ChaCha12Rng::from_seed(seed), - }, - ) +/// Returns an ideal ROT sender and receiver. +pub fn ideal_rot() -> (IdealROTSender, IdealROTReceiver) { + let (alice, bob) = ideal_f2p(IdealROT::default()); + (IdealROTSender(alice), IdealROTReceiver(bob)) } +/// Ideal ROT sender. +#[derive(Debug, Clone)] +pub struct IdealROTSender(Alice); + #[async_trait] -impl OTSetup for IdealRandomOTSender +impl OTSetup for IdealROTSender where Ctx: Context, - T: Send + Sync, { async fn setup(&mut self, _ctx: &mut Ctx) -> Result<(), OTError> { Ok(()) @@ -53,62 +42,24 @@ where } #[async_trait] -impl RandomOTSender for IdealRandomOTSender { +impl RandomOTSender for IdealROTSender { async fn send_random( &mut self, - _ctx: &mut Ctx, + ctx: &mut Ctx, count: usize, - ) -> Result, OTError> { - let messages = (0..count) - .map(|_| [Block::random(&mut self.rng), Block::random(&mut self.rng)]) - .collect::>(); - - self.sender - .try_send(messages.clone()) - .expect("IdealRandomOTSender should be able to send"); - - Ok(messages) + ) -> Result, OTError> { + Ok(self.0.call(ctx, count, rot).await) } } -#[async_trait] -impl RandomOTSender - for IdealRandomOTSender<[u8; N]> -{ - async fn send_random( - &mut self, - _ctx: &mut Ctx, - count: usize, - ) -> Result, OTError> { - let prng = |block| { - let mut prg = Prg::from_seed(block); - let mut out = [0_u8; N]; - prg.fill_bytes(&mut out); - out - }; - - let messages = (0..count) - .map(|_| { - [ - prng(Block::random(&mut self.rng)), - prng(Block::random(&mut self.rng)), - ] - }) - .collect::>(); - - self.sender - .try_send(messages.clone()) - .expect("IdealRandomOTSender should be able to send"); - - Ok(messages) - } -} +/// Ideal ROT receiver. +#[derive(Debug, Clone)] +pub struct IdealROTReceiver(Bob); #[async_trait] -impl OTSetup for IdealRandomOTReceiver +impl OTSetup for IdealROTReceiver where Ctx: Context, - T: Send + Sync, { async fn setup(&mut self, _ctx: &mut Ctx) -> Result<(), OTError> { Ok(()) @@ -116,123 +67,12 @@ where } #[async_trait] -impl RandomOTReceiver for IdealRandomOTReceiver { +impl RandomOTReceiver for IdealROTReceiver { async fn receive_random( &mut self, - _ctx: &mut Ctx, + ctx: &mut Ctx, count: usize, - ) -> Result<(Vec, Vec), OTError> { - let payload = self - .receiver - .next() - .await - .expect("IdealRandomOTSender should send a value"); - - assert_eq!(payload.len(), count); - - let choices = (0..count).map(|_| self.rng.gen()).collect::>(); - let payload = payload - .into_iter() - .zip(&choices) - .map(|(v, c)| { - let [low, high] = v; - if *c { - high - } else { - low - } - }) - .collect(); - - Ok((choices, payload)) - } -} - -#[async_trait] -impl RandomOTReceiver - for IdealRandomOTReceiver<[u8; N]> -{ - async fn receive_random( - &mut self, - _ctx: &mut Ctx, - count: usize, - ) -> Result<(Vec, Vec<[u8; N]>), OTError> { - let payload = self - .receiver - .next() - .await - .expect("IdealRandomOTSender should send a value"); - - assert_eq!(payload.len(), count); - - let choices = (0..count).map(|_| self.rng.gen()).collect::>(); - let payload = payload - .into_iter() - .zip(&choices) - .map(|(v, c)| { - let [low, high] = v; - if *c { - high - } else { - low - } - }) - .collect(); - - Ok((choices, payload)) - } -} - -#[cfg(test)] -mod tests { - use super::*; - use mpz_common::executor::test_st_executor; - - #[tokio::test] - async fn test_ideal_random_ot_owned_block() { - let seed = [0u8; 32]; - let (mut ctx_sender, mut ctx_receiver) = test_st_executor(8); - let (mut sender, mut receiver) = ideal_random_ot_pair::(seed); - - let values = RandomOTSender::send_random(&mut sender, &mut ctx_sender, 8) - .await - .unwrap(); - - let (choices, received) = - RandomOTReceiver::receive_random(&mut receiver, &mut ctx_receiver, 8) - .await - .unwrap(); - - let expected = values - .into_iter() - .zip(choices) - .map(|(v, c)| v[c as usize]) - .collect::>(); - - assert_eq!(received, expected); - } - - #[tokio::test] - async fn test_ideal_random_ot_owned_array() { - let seed = [0u8; 32]; - let (mut ctx_sender, mut ctx_receiver) = test_st_executor(8); - let (mut sender, mut receiver) = ideal_random_ot_pair::<[u8; 64]>(seed); - - let values = RandomOTSender::send_random(&mut sender, &mut ctx_sender, 8) - .await - .unwrap(); - - let (choices, received) = - RandomOTReceiver::receive_random(&mut receiver, &mut ctx_receiver, 8) - .await - .unwrap(); - - let expected = values - .into_iter() - .zip(choices) - .map(|(v, c)| v[c as usize]) - .collect::>(); - - assert_eq!(received, expected); + ) -> Result, OTError> { + Ok(self.0.call(ctx, count, rot).await) } } diff --git a/crates/mpz-ot/src/kos/mod.rs b/crates/mpz-ot/src/kos/mod.rs index 831e95cf..4c4c014c 100644 --- a/crates/mpz-ot/src/kos/mod.rs +++ b/crates/mpz-ot/src/kos/mod.rs @@ -44,7 +44,7 @@ mod tests { use rand_core::SeedableRng; use crate::{ - ideal::ot::{ideal_ot_pair, IdealOTReceiver, IdealOTSender}, + ideal::ot::{ideal_ot, IdealOTReceiver, IdealOTSender}, OTError, OTReceiver, OTSender, OTSetup, RandomOTReceiver, RandomOTSender, VerifiableOTReceiver, }; @@ -79,9 +79,9 @@ mod tests { count: usize, ) -> ( Sender>, - Receiver>, + Receiver>, ) { - let (base_sender, base_receiver) = ideal_ot_pair(); + let (base_sender, base_receiver) = ideal_ot(); let mut sender = Sender::new(sender_config, base_receiver); let mut receiver = Receiver::new(receiver_config, base_sender); @@ -109,17 +109,18 @@ mod tests { ) .await; - let (_, received): (_, Vec) = tokio::try_join!( - sender.send(&mut ctx_sender, &data).map_err(OTError::from), - receiver - .receive(&mut ctx_receiver, &choices) + let (output_sender, output_receiver) = tokio::try_join!( + OTSender::<_, [Block; 2]>::send(&mut sender, &mut ctx_sender, &data) + .map_err(OTError::from), + OTReceiver::<_, bool, Block>::receive(&mut receiver, &mut ctx_receiver, &choices) .map_err(OTError::from) ) .unwrap(); let expected = choose(data.iter().copied(), choices.iter_lsb0()).collect::>(); - assert_eq!(received, expected); + assert_eq!(output_sender.id, output_receiver.id); + assert_eq!(output_receiver.msgs, expected); } #[tokio::test] @@ -134,22 +135,25 @@ mod tests { ) .await; - let (sender_output, (choices, receiver_output)): ( - Vec<[Block; 2]>, - (Vec, Vec), - ) = tokio::try_join!( - RandomOTSender::send_random(&mut sender, &mut ctx_sender, 10), - RandomOTReceiver::receive_random(&mut receiver, &mut ctx_receiver, 10) + let (output_sender, output_receiver) = tokio::try_join!( + RandomOTSender::<_, [Block; 2]>::send_random(&mut sender, &mut ctx_sender, 10), + RandomOTReceiver::<_, bool, Block>::receive_random( + &mut receiver, + &mut ctx_receiver, + 10 + ) ) .unwrap(); - let expected = sender_output + let expected = output_sender + .msgs .into_iter() - .zip(choices) + .zip(output_receiver.choices) .map(|(output, choice)| output[choice as usize]) .collect::>(); - assert_eq!(receiver_output, expected); + assert_eq!(output_sender.id, output_receiver.id); + assert_eq!(output_receiver.msgs, expected); } #[rstest] @@ -170,17 +174,18 @@ mod tests { .map(|[a, b]| [a.to_bytes(), b.to_bytes()]) .collect(); - let (_, received): (_, Vec<[u8; 16]>) = tokio::try_join!( - sender.send(&mut ctx_sender, &data).map_err(OTError::from), - receiver - .receive(&mut ctx_receiver, &choices) + let (output_sender, output_receiver) = tokio::try_join!( + OTSender::<_, [[u8; 16]; 2]>::send(&mut sender, &mut ctx_sender, &data) + .map_err(OTError::from), + OTReceiver::<_, bool, [u8; 16]>::receive(&mut receiver, &mut ctx_receiver, &choices) .map_err(OTError::from) ) .unwrap(); let expected = choose(data.iter().copied(), choices.iter_lsb0()).collect::>(); - assert_eq!(received, expected); + assert_eq!(output_sender.id, output_receiver.id); + assert_eq!(output_receiver.msgs, expected); } #[rstest] @@ -196,22 +201,23 @@ mod tests { ) .await; - let (_, received): (_, Vec) = tokio::try_join!( - sender.send(&mut ctx_sender, &data).map_err(OTError::from), - receiver - .receive(&mut ctx_receiver, &choices) + let (output_sender, output_receiver) = tokio::try_join!( + OTSender::<_, [Block; 2]>::send(&mut sender, &mut ctx_sender, &data) + .map_err(OTError::from), + OTReceiver::<_, bool, Block>::receive(&mut receiver, &mut ctx_receiver, &choices) .map_err(OTError::from) ) .unwrap(); let expected = choose(data.iter().copied(), choices.iter_lsb0()).collect::>(); - assert_eq!(received, expected); + assert_eq!(output_sender.id, output_receiver.id); + assert_eq!(output_receiver.msgs, expected); tokio::try_join!( sender.reveal(&mut ctx_sender).map_err(OTError::from), receiver - .verify(&mut ctx_receiver, 0, &data) + .verify(&mut ctx_receiver, output_receiver.id, &data) .map_err(OTError::from) ) .unwrap(); @@ -233,16 +239,17 @@ mod tests { let mut receiver = SharedReceiver::new(receiver); let mut sender = SharedSender::new(sender); - let (_, received): (_, Vec) = tokio::try_join!( - sender.send(&mut ctx_sender, &data).map_err(OTError::from), - receiver - .receive(&mut ctx_receiver, &choices) + let (output_sender, output_receiver) = tokio::try_join!( + OTSender::<_, [Block; 2]>::send(&mut sender, &mut ctx_sender, &data) + .map_err(OTError::from), + OTReceiver::<_, bool, Block>::receive(&mut receiver, &mut ctx_receiver, &choices) .map_err(OTError::from) ) .unwrap(); let expected = choose(data.iter().copied(), choices.iter_lsb0()).collect::>(); - assert_eq!(received, expected); + assert_eq!(output_sender.id, output_receiver.id); + assert_eq!(output_receiver.msgs, expected); } } diff --git a/crates/mpz-ot/src/kos/receiver.rs b/crates/mpz-ot/src/kos/receiver.rs index ab3bf325..f9a8e355 100644 --- a/crates/mpz-ot/src/kos/receiver.rs +++ b/crates/mpz-ot/src/kos/receiver.rs @@ -3,9 +3,13 @@ use itybity::{FromBitIterator, IntoBitIterator}; use mpz_cointoss as cointoss; use mpz_common::{scoped_futures::ScopedFutureExt, Context}; use mpz_core::{prg::Prg, Block}; -use mpz_ot_core::kos::{ - msgs::StartExtend, pad_ot_count, receiver_state as state, Receiver as ReceiverCore, - ReceiverConfig, ReceiverKeys, CSP, +use mpz_ot_core::{ + kos::{ + msgs::{SenderPayload, StartExtend}, + pad_ot_count, receiver_state as state, Receiver as ReceiverCore, ReceiverConfig, + ReceiverKeys, CSP, + }, + OTReceiverOutput, ROTReceiverOutput, TransferId, }; use enum_try_as_inner::EnumTryAsInner; @@ -223,7 +227,11 @@ where Ctx: Context, BaseOT: Send, { - async fn receive(&mut self, ctx: &mut Ctx, choices: &[bool]) -> Result, OTError> { + async fn receive( + &mut self, + ctx: &mut Ctx, + choices: &[bool], + ) -> Result, OTError> { let receiver = self .state .try_as_extension_mut() @@ -240,7 +248,8 @@ where ctx.io_mut().send(derandomize).await?; // Receive payload - let payload = ctx.io_mut().expect_next().await?; + let payload: SenderPayload = ctx.io_mut().expect_next().await?; + let id = payload.id; let received = Backend::spawn(move || { receiver_keys @@ -249,7 +258,7 @@ where }) .await?; - Ok(received) + Ok(OTReceiverOutput { id, msgs: received }) } } @@ -263,18 +272,17 @@ where &mut self, _ctx: &mut Ctx, count: usize, - ) -> Result<(Vec, Vec), OTError> { + ) -> Result, OTError> { let receiver = self .state .try_as_extension_mut() .map_err(ReceiverError::from)?; - let (choices, random_outputs) = receiver - .keys(count) - .map_err(ReceiverError::from)? - .take_choices_and_keys(); + let keys = receiver.keys(count).map_err(ReceiverError::from)?; + let id = keys.id(); + let (choices, msgs) = keys.take_choices_and_keys(); - Ok((choices, random_outputs)) + Ok(ROTReceiverOutput { id, choices, msgs }) } } @@ -284,7 +292,11 @@ where Ctx: Context, BaseOT: Send, { - async fn receive(&mut self, ctx: &mut Ctx, choices: &[bool]) -> Result, OTError> { + async fn receive( + &mut self, + ctx: &mut Ctx, + choices: &[bool], + ) -> Result, OTError> { let receiver = self .state .try_as_extension_mut() @@ -301,7 +313,8 @@ where ctx.io_mut().send(derandomize).await?; // Receive payload - let payload = ctx.io_mut().expect_next().await?; + let payload: SenderPayload = ctx.io_mut().expect_next().await?; + let id = payload.id; let received = Backend::spawn(move || { receiver_keys @@ -310,7 +323,7 @@ where }) .await?; - Ok(received) + Ok(OTReceiverOutput { id, msgs: received }) } } @@ -324,29 +337,27 @@ where &mut self, _ctx: &mut Ctx, count: usize, - ) -> Result<(Vec, Vec<[u8; N]>), OTError> { + ) -> Result, OTError> { let receiver = self .state .try_as_extension_mut() .map_err(ReceiverError::from)?; - let (choices, random_outputs) = receiver - .keys(count) - .map_err(ReceiverError::from)? - .take_choices_and_keys(); - - Ok(( - choices, - random_outputs - .into_iter() - .map(|block| { - let mut prg = Prg::from_seed(block); - let mut out = [0_u8; N]; - prg.fill_bytes(&mut out); - out - }) - .collect(), - )) + let keys = receiver.keys(count).map_err(ReceiverError::from)?; + let id = keys.id(); + + let (choices, random_outputs) = keys.take_choices_and_keys(); + let msgs = random_outputs + .into_iter() + .map(|block| { + let mut prg = Prg::from_seed(block); + let mut out = [0_u8; N]; + prg.fill_bytes(&mut out); + out + }) + .collect(); + + Ok(ROTReceiverOutput { id, choices, msgs }) } } @@ -359,7 +370,7 @@ where async fn verify( &mut self, ctx: &mut Ctx, - id: usize, + id: TransferId, msgs: &[[Block; 2]], ) -> Result<(), OTError> { // Verify delta if we haven't yet. @@ -369,9 +380,7 @@ where let receiver = self.state.try_as_verify().map_err(ReceiverError::from)?; - let record = receiver - .remove_record(id as u32) - .map_err(ReceiverError::from)?; + let record = receiver.remove_record(id).map_err(ReceiverError::from)?; let msgs = msgs.to_vec(); Backend::spawn(move || record.verify(&msgs)) diff --git a/crates/mpz-ot/src/kos/sender.rs b/crates/mpz-ot/src/kos/sender.rs index f5929c4b..ba70a8f2 100644 --- a/crates/mpz-ot/src/kos/sender.rs +++ b/crates/mpz-ot/src/kos/sender.rs @@ -4,10 +4,13 @@ use itybity::IntoBits; use mpz_cointoss as cointoss; use mpz_common::{scoped_futures::ScopedFutureExt, Context}; use mpz_core::{prg::Prg, Block}; -use mpz_ot_core::kos::{ - extension_matrix_size, - msgs::{Extend, StartExtend}, - pad_ot_count, sender_state as state, Sender as SenderCore, SenderConfig, SenderKeys, CSP, +use mpz_ot_core::{ + kos::{ + extension_matrix_size, + msgs::{Extend, StartExtend}, + pad_ot_count, sender_state as state, Sender as SenderCore, SenderConfig, SenderKeys, CSP, + }, + OTSenderOutput, ROTSenderOutput, }; use rand::{thread_rng, Rng}; use rand_core::{RngCore, SeedableRng}; @@ -99,9 +102,12 @@ impl Sender { let ext_sender = std::mem::replace(&mut self.state, State::Error).try_into_initialized()?; let choices = delta.into_lsb0_vec(); - let seeds = self.base.receive(ctx, &choices).await?; + let base_output = self.base.receive(ctx, &choices).await?; - let seeds: [Block; CSP] = seeds.try_into().expect("seeds should be CSP length"); + let seeds: [Block; CSP] = base_output + .msgs + .try_into() + .expect("seeds should be CSP length"); let ext_sender = ext_sender.setup(delta, seeds); @@ -262,7 +268,11 @@ where Ctx: Context, BaseOT: Send, { - async fn send(&mut self, ctx: &mut Ctx, msgs: &[[Block; 2]]) -> Result<(), OTError> { + async fn send( + &mut self, + ctx: &mut Ctx, + msgs: &[[Block; 2]], + ) -> Result { let sender = self .state .try_as_extension_mut() @@ -277,13 +287,14 @@ where let payload = sender_keys .encrypt_blocks(msgs) .map_err(SenderError::from)?; + let id = payload.id; ctx.io_mut() .send(payload) .await .map_err(SenderError::from)?; - Ok(()) + Ok(OTSenderOutput { id }) } } @@ -297,14 +308,19 @@ where &mut self, _ctx: &mut Ctx, count: usize, - ) -> Result, OTError> { + ) -> Result, OTError> { let sender = self .state .try_as_extension_mut() .map_err(SenderError::from)?; let random_outputs = sender.keys(count).map_err(SenderError::from)?; - Ok(random_outputs.take_keys()) + let id = random_outputs.id(); + + Ok(ROTSenderOutput { + id, + msgs: random_outputs.take_keys(), + }) } } @@ -314,7 +330,11 @@ where Ctx: Context, BaseOT: Send, { - async fn send(&mut self, ctx: &mut Ctx, msgs: &[[[u8; N]; 2]]) -> Result<(), OTError> { + async fn send( + &mut self, + ctx: &mut Ctx, + msgs: &[[[u8; N]; 2]], + ) -> Result { let sender = self .state .try_as_extension_mut() @@ -327,13 +347,14 @@ where .derandomize(derandomize) .map_err(SenderError::from)?; let payload = sender_keys.encrypt_bytes(msgs).map_err(SenderError::from)?; + let id = payload.id; ctx.io_mut() .send(payload) .await .map_err(SenderError::from)?; - Ok(()) + Ok(OTSenderOutput { id }) } } @@ -347,13 +368,14 @@ where &mut self, _ctx: &mut Ctx, count: usize, - ) -> Result, OTError> { + ) -> Result, OTError> { let sender = self .state .try_as_extension_mut() .map_err(SenderError::from)?; let random_outputs = sender.keys(count).map_err(SenderError::from)?; + let id = random_outputs.id(); let prng = |block| { let mut prg = Prg::from_seed(block); @@ -362,11 +384,14 @@ where out }; - Ok(random_outputs - .take_keys() - .into_iter() - .map(|[a, b]| [prng(a), prng(b)]) - .collect()) + Ok(ROTSenderOutput { + id, + msgs: random_outputs + .take_keys() + .into_iter() + .map(|[a, b]| [prng(a), prng(b)]) + .collect(), + }) } } diff --git a/crates/mpz-ot/src/kos/shared_receiver.rs b/crates/mpz-ot/src/kos/shared_receiver.rs index 9d3cb35a..a72b42ad 100644 --- a/crates/mpz-ot/src/kos/shared_receiver.rs +++ b/crates/mpz-ot/src/kos/shared_receiver.rs @@ -4,6 +4,7 @@ use async_trait::async_trait; use itybity::IntoBitIterator; use mpz_common::{sync::Mutex, Context}; use mpz_core::Block; +use mpz_ot_core::{kos::msgs::SenderPayload, OTReceiverOutput}; use serio::{stream::IoStreamExt, SinkExt}; use utils_aio::non_blocking_backend::{Backend, NonBlockingBackend}; @@ -34,7 +35,11 @@ where Ctx: Context, BaseOT: Send, { - async fn receive(&mut self, ctx: &mut Ctx, choices: &[bool]) -> Result, OTError> { + async fn receive( + &mut self, + ctx: &mut Ctx, + choices: &[bool], + ) -> Result, OTError> { let mut keys = self.inner.lock(ctx).await?.take_keys(choices.len())?; let choices = choices.into_lsb0_vec(); @@ -44,12 +49,13 @@ where ctx.io_mut().send(derandomize).await?; // Receive payload - let payload = ctx.io_mut().expect_next().await?; + let payload: SenderPayload = ctx.io_mut().expect_next().await?; + let id = payload.id; - let received = + let msgs = Backend::spawn(move || keys.decrypt_blocks(payload).map_err(ReceiverError::from)) .await?; - Ok(received) + Ok(OTReceiverOutput { id, msgs }) } } diff --git a/crates/mpz-ot/src/kos/shared_sender.rs b/crates/mpz-ot/src/kos/shared_sender.rs index bc2c6fd7..f1441224 100644 --- a/crates/mpz-ot/src/kos/shared_sender.rs +++ b/crates/mpz-ot/src/kos/shared_sender.rs @@ -4,6 +4,7 @@ use async_trait::async_trait; use mpz_common::{sync::Mutex, Context}; use mpz_core::Block; +use mpz_ot_core::OTSenderOutput; use serio::{stream::IoStreamExt as _, SinkExt as _}; use crate::{ @@ -33,19 +34,24 @@ where Ctx: Context, BaseOT: OTReceiver + Send + 'static, { - async fn send(&mut self, ctx: &mut Ctx, msgs: &[[Block; 2]]) -> Result<(), OTError> { + async fn send( + &mut self, + ctx: &mut Ctx, + msgs: &[[Block; 2]], + ) -> Result { let mut keys = self.inner.lock(ctx).await?.take_keys(msgs.len())?; let derandomize = ctx.io_mut().expect_next().await?; keys.derandomize(derandomize).map_err(SenderError::from)?; let payload = keys.encrypt_blocks(msgs).map_err(SenderError::from)?; + let id = payload.id; ctx.io_mut() .send(payload) .await .map_err(SenderError::from)?; - Ok(()) + Ok(OTSenderOutput { id }) } } diff --git a/crates/mpz-ot/src/lib.rs b/crates/mpz-ot/src/lib.rs index 712c3761..4ddafe21 100644 --- a/crates/mpz-ot/src/lib.rs +++ b/crates/mpz-ot/src/lib.rs @@ -10,13 +10,18 @@ )] pub mod chou_orlandi; -#[cfg(feature = "ideal")] +#[cfg(any(test, feature = "ideal"))] pub mod ideal; pub mod kos; use async_trait::async_trait; use mpz_common::Context; +pub use mpz_ot_core::{ + COTReceiverOutput, COTSenderOutput, OTReceiverOutput, OTSenderOutput, RCOTReceiverOutput, + ROTReceiverOutput, ROTSenderOutput, TransferId, +}; + /// An oblivious transfer error. #[derive(Debug, thiserror::Error)] #[allow(missing_docs)] @@ -47,89 +52,64 @@ where /// An oblivious transfer sender. #[async_trait] -pub trait OTSender -where - Ctx: Context, - T: Send + Sync, -{ +pub trait OTSender { /// Obliviously transfers the messages to the receiver. /// /// # Arguments /// /// * `ctx` - The thread context. /// * `msgs` - The messages to obliviously transfer. - async fn send(&mut self, ctx: &mut Ctx, msgs: &[T]) -> Result<(), OTError>; + async fn send(&mut self, ctx: &mut Ctx, msgs: &[T]) -> Result; } /// A correlated oblivious transfer sender. #[async_trait] -pub trait COTSender -where - Ctx: Context, - T: Send + Sync, -{ +pub trait COTSender { /// Obliviously transfers the correlated messages to the receiver. /// + /// Returns the `0`-bit messages that were obliviously transferred. + /// /// # Arguments /// /// * `ctx` - The thread context. - /// * `msgs` - The `0`-bit messages to use during the oblivious transfer. - async fn send_correlated(&mut self, ctx: &mut Ctx, msgs: &[T]) -> Result<(), OTError>; + /// * `count` - The number of correlated messages to obliviously transfer. + async fn send_correlated( + &mut self, + ctx: &mut Ctx, + count: usize, + ) -> Result, OTError>; } /// A random OT sender. #[async_trait] -pub trait RandomOTSender -where - Ctx: Context, - T: Send + Sync, -{ +pub trait RandomOTSender { /// Outputs pairs of random messages. /// /// # Arguments /// /// * `ctx` - The thread context. /// * `count` - The number of pairs of random messages to output. - async fn send_random(&mut self, ctx: &mut Ctx, count: usize) -> Result, OTError>; -} - -/// A random correlated oblivious transfer sender. -#[async_trait] -pub trait RandomCOTSender -where - Ctx: Context, - T: Send + Sync, -{ - /// Obliviously transfers the correlated messages to the receiver. - /// - /// Returns the `0`-bit messages that were obliviously transferred. - /// - /// # Arguments - /// - /// * `ctx` - The thread context. - /// * `count` - The number of correlated messages to obliviously transfer. - async fn send_random_correlated( + async fn send_random( &mut self, ctx: &mut Ctx, count: usize, - ) -> Result, OTError>; + ) -> Result, OTError>; } /// An oblivious transfer receiver. #[async_trait] -pub trait OTReceiver -where - Ctx: Context, - T: Send + Sync, - U: Send + Sync, -{ +pub trait OTReceiver { /// Obliviously receives data from the sender. /// /// # Arguments /// /// * `ctx` - The thread context. /// * `choices` - The choices made by the receiver. - async fn receive(&mut self, ctx: &mut Ctx, choices: &[T]) -> Result, OTError>; + async fn receive( + &mut self, + ctx: &mut Ctx, + choices: &[T], + ) -> Result, OTError>; } /// A correlated oblivious transfer receiver. @@ -146,8 +126,11 @@ where /// /// * `ctx` - The thread context. /// * `choices` - The choices made by the receiver. - async fn receive_correlated(&mut self, ctx: &mut Ctx, choices: &[T]) - -> Result, OTError>; + async fn receive_correlated( + &mut self, + ctx: &mut Ctx, + choices: &[T], + ) -> Result, OTError>; } /// A random OT receiver. @@ -168,7 +151,7 @@ where &mut self, ctx: &mut Ctx, count: usize, - ) -> Result<(Vec, Vec), OTError>; + ) -> Result, OTError>; } /// A random correlated oblivious transfer receiver. @@ -191,7 +174,7 @@ where &mut self, ctx: &mut Ctx, count: usize, - ) -> Result<(Vec, Vec), OTError>; + ) -> Result, OTError>; } /// An oblivious transfer sender that is committed to its messages and can reveal them @@ -216,11 +199,7 @@ where /// An oblivious transfer sender that can verify the receiver's choices. #[async_trait] -pub trait VerifiableOTSender: OTSender -where - Ctx: Context, - U: Send + Sync, -{ +pub trait VerifiableOTSender: OTSender { /// Receives the purported choices made by the receiver and verifies them. /// /// # Arguments @@ -232,12 +211,7 @@ where /// An oblivious transfer receiver that is committed to its choices and can reveal them /// to the sender to verify them. #[async_trait] -pub trait CommittedOTReceiver: OTReceiver -where - Ctx: Context, - T: Send + Sync, - U: Send + Sync, -{ +pub trait CommittedOTReceiver: OTReceiver { /// Reveals the choices made by the receiver. /// /// # Warning @@ -266,5 +240,5 @@ where /// * `ctx` - The thread context. /// * `id` - The transfer id of the messages to verify. /// * `msgs` - The purported messages sent by the sender. - async fn verify(&mut self, ctx: &mut Ctx, id: usize, msgs: &[V]) -> Result<(), OTError>; + async fn verify(&mut self, ctx: &mut Ctx, id: TransferId, msgs: &[V]) -> Result<(), OTError>; } From a34385776915ba645917045492c06dd8f06b954e Mon Sep 17 00:00:00 2001 From: "sinu.eth" <65924192+sinui0@users.noreply.github.com> Date: Mon, 13 May 2024 06:09:29 -0800 Subject: [PATCH 12/39] feat(mpz-common): add try_/join convenience macros (#126) --- crates/mpz-common/src/context.rs | 67 +++++++++++++++++++++++++++++++ crates/mpz-ot/src/kos/receiver.rs | 29 +++++-------- crates/mpz-ot/src/kos/sender.rs | 36 +++++++---------- 3 files changed, 91 insertions(+), 41 deletions(-) diff --git a/crates/mpz-common/src/context.rs b/crates/mpz-common/src/context.rs index 67d74b11..e5f0e1bf 100644 --- a/crates/mpz-common/src/context.rs +++ b/crates/mpz-common/src/context.rs @@ -44,3 +44,70 @@ pub trait Context: Send { RB: Send + 'a, E: Send + 'a; } + +/// A convenience macro for forking a context and joining two tasks concurrently. +/// +/// This macro calls `Context::join` under the hood. +#[macro_export] +macro_rules! join { + ($ctx:ident, $task_0:expr, $task_1:expr) => { + async { + use $crate::{scoped_futures::ScopedFutureExt, Context}; + $ctx.join( + |$ctx| async { $task_0.await }.scope_boxed(), + |$ctx| async { $task_1.await }.scope_boxed(), + ) + .await + } + .await + }; +} + +/// A convenience macro for forking a context and joining two tasks concurrently, returning an error +/// if one of the tasks fails. +/// +/// This macro calls `Context::try_join` under the hood. +#[macro_export] +macro_rules! try_join { + ($ctx:ident, $task_0:expr, $task_1:expr) => { + async { + use $crate::{scoped_futures::ScopedFutureExt, Context}; + $ctx.try_join( + |$ctx| async { $task_0.await }.scope_boxed(), + |$ctx| async { $task_1.await }.scope_boxed(), + ) + .await + } + .await + }; +} + +#[cfg(test)] +mod tests { + use crate::executor::test_st_executor; + + #[test] + fn test_join_macro() { + let (mut ctx, _) = test_st_executor(1); + + futures::executor::block_on(async { + join!(ctx, async { println!("{:?}", ctx.id()) }, async { + println!("{:?}", ctx.id()) + }) + }); + } + + #[test] + fn test_try_join_macro() { + let (mut ctx, _) = test_st_executor(1); + + futures::executor::block_on(async { + try_join!( + ctx, + async { Ok::<_, ()>(println!("{:?}", ctx.id())) }, + async { Ok::<_, ()>(println!("{:?}", ctx.id())) } + ) + .unwrap(); + }); + } +} diff --git a/crates/mpz-ot/src/kos/receiver.rs b/crates/mpz-ot/src/kos/receiver.rs index f9a8e355..39bab96d 100644 --- a/crates/mpz-ot/src/kos/receiver.rs +++ b/crates/mpz-ot/src/kos/receiver.rs @@ -1,7 +1,8 @@ use async_trait::async_trait; +use futures::TryFutureExt as _; use itybity::{FromBitIterator, IntoBitIterator}; use mpz_cointoss as cointoss; -use mpz_common::{scoped_futures::ScopedFutureExt, Context}; +use mpz_common::{try_join, Context}; use mpz_core::{prg::Prg, Block}; use mpz_ot_core::{ kos::{ @@ -183,25 +184,13 @@ where // If the sender is committed, we run a coin toss if ext_receiver.config().sender_commit() { let cointoss_seed = thread_rng().gen(); - let base = &mut self.base; - - let (cointoss_receiver, _) = ctx - .try_join( - |ctx| { - async move { - cointoss::Receiver::new(vec![cointoss_seed]) - .receive(ctx) - .await - .map_err(ReceiverError::from) - } - .scope_boxed() - }, - |ctx| { - async move { base.setup(ctx).await.map_err(ReceiverError::from) } - .scope_boxed() - }, - ) - .await?; + let (cointoss_receiver, _) = try_join!( + ctx, + cointoss::Receiver::new(vec![cointoss_seed]) + .receive(ctx) + .map_err(ReceiverError::from), + self.base.setup(ctx).map_err(ReceiverError::from) + )?; self.cointoss_receiver = Some(cointoss_receiver); } else { diff --git a/crates/mpz-ot/src/kos/sender.rs b/crates/mpz-ot/src/kos/sender.rs index ba70a8f2..ac7d5f5a 100644 --- a/crates/mpz-ot/src/kos/sender.rs +++ b/crates/mpz-ot/src/kos/sender.rs @@ -1,8 +1,9 @@ use async_trait::async_trait; use enum_try_as_inner::EnumTryAsInner; +use futures::TryFutureExt; use itybity::IntoBits; use mpz_cointoss as cointoss; -use mpz_common::{scoped_futures::ScopedFutureExt, Context}; +use mpz_common::{try_join, Context}; use mpz_core::{prg::Prg, Block}; use mpz_ot_core::{ kos::{ @@ -223,27 +224,20 @@ where // If the sender is committed, we sample delta using a coin toss. let delta = if sender.config().sender_commit() { let cointoss_seed = thread_rng().gen(); - let base = &mut self.base; + // Execute coin-toss protocol and base OT setup concurrently. - let ((seeds, cointoss_sender), _) = ctx - .try_join( - |ctx| { - async move { - cointoss::Sender::new(vec![cointoss_seed]) - .commit(ctx) - .await? - .receive(ctx) - .await - .map_err(SenderError::from) - } - .scope_boxed() - }, - |ctx| { - async move { base.setup(ctx).await.map_err(SenderError::from) } - .scope_boxed() - }, - ) - .await?; + let ((seeds, cointoss_sender), _) = try_join!( + ctx, + async { + cointoss::Sender::new(vec![cointoss_seed]) + .commit(ctx) + .await? + .receive(ctx) + .await + .map_err(SenderError::from) + }, + self.base.setup(ctx).map_err(SenderError::from) + )?; // Store the sender to finalize the cointoss protocol later. self.cointoss_sender = Some(cointoss_sender); From 9c40d847a9760a62a576df32e7856013b6d12df0 Mon Sep 17 00:00:00 2001 From: "sinu.eth" <65924192+sinui0@users.noreply.github.com> Date: Mon, 13 May 2024 06:44:33 -0800 Subject: [PATCH 13/39] fix(mpz-ot): Ideal RCOT (#131) * delete obsolete module * export test-utils and add ideal COT tests --- crates/mpz-ot-core/Cargo.toml | 3 +- crates/mpz-ot-core/src/lib.rs | 4 +- crates/mpz-ot-core/src/test.rs | 6 +- crates/mpz-ot/Cargo.toml | 1 + crates/mpz-ot/src/ideal/cot.rs | 86 ++++++++++++++++- crates/mpz-ot/src/ideal/rcot.rs | 158 -------------------------------- crates/mpz-ot/src/lib.rs | 20 +++- 7 files changed, 113 insertions(+), 165 deletions(-) delete mode 100644 crates/mpz-ot/src/ideal/rcot.rs diff --git a/crates/mpz-ot-core/Cargo.toml b/crates/mpz-ot-core/Cargo.toml index b88dd648..8c109327 100644 --- a/crates/mpz-ot-core/Cargo.toml +++ b/crates/mpz-ot-core/Cargo.toml @@ -10,8 +10,9 @@ workspace = true name = "mpz_ot_core" [features] -default = ["rayon"] +default = ["rayon", "test-utils"] rayon = ["dep:rayon", "itybity/rayon", "blake3/rayon"] +test-utils = [] [dependencies] mpz-core.workspace = true diff --git a/crates/mpz-ot-core/src/lib.rs b/crates/mpz-ot-core/src/lib.rs index 1c932212..87314c5a 100644 --- a/crates/mpz-ot-core/src/lib.rs +++ b/crates/mpz-ot-core/src/lib.rs @@ -26,8 +26,8 @@ pub mod ferret; pub mod ideal; pub mod kos; pub mod msgs; -#[cfg(test)] -pub(crate) mod test; +#[cfg(any(test, feature = "test-utils"))] +pub mod test; /// An oblivious transfer identifier. /// diff --git a/crates/mpz-ot-core/src/test.rs b/crates/mpz-ot-core/src/test.rs index 010c6e71..975215ec 100644 --- a/crates/mpz-ot-core/src/test.rs +++ b/crates/mpz-ot-core/src/test.rs @@ -1,7 +1,9 @@ +//! OT test utilities. + use mpz_core::Block; /// Asserts the correctness of correlated oblivious transfer. -pub(crate) fn assert_cot(delta: Block, choices: &[bool], msgs: &[Block], received: &[Block]) { +pub fn assert_cot(delta: Block, choices: &[bool], msgs: &[Block], received: &[Block]) { assert!(choices.into_iter().zip(msgs.into_iter().zip(received)).all( |(&choice, (&msg, &received))| { if choice { @@ -14,7 +16,7 @@ pub(crate) fn assert_cot(delta: Block, choices: &[bool], msgs: &[Block], receive } /// Asserts the correctness of random oblivious transfer. -pub(crate) fn assert_rot(choices: &[bool], msgs: &[[T; 2]], received: &[T]) { +pub fn assert_rot(choices: &[bool], msgs: &[[T; 2]], received: &[T]) { assert!(choices.into_iter().zip(msgs.into_iter().zip(received)).all( |(&choice, (&msg, &received))| { if choice { diff --git a/crates/mpz-ot/Cargo.toml b/crates/mpz-ot/Cargo.toml index 96b45c73..cee9db73 100644 --- a/crates/mpz-ot/Cargo.toml +++ b/crates/mpz-ot/Cargo.toml @@ -39,6 +39,7 @@ cfg-if.workspace = true [dev-dependencies] mpz-common = { workspace = true, features = ["test-utils", "ideal"] } +mpz-ot-core = { workspace = true, features = ["test-utils"] } rstest = { workspace = true } criterion = { workspace = true, features = ["async_tokio"] } tokio = { workspace = true, features = [ diff --git a/crates/mpz-ot/src/ideal/cot.rs b/crates/mpz-ot/src/ideal/cot.rs index a65809ed..ee739584 100644 --- a/crates/mpz-ot/src/ideal/cot.rs +++ b/crates/mpz-ot/src/ideal/cot.rs @@ -11,7 +11,7 @@ use mpz_ot_core::{ ideal::cot::IdealCOT, COTReceiverOutput, COTSenderOutput, RCOTReceiverOutput, RCOTSenderOutput, }; -use crate::{COTReceiver, COTSender, OTError, OTSetup, RandomCOTReceiver}; +use crate::{COTReceiver, COTSender, OTError, OTSetup, RandomCOTReceiver, RandomCOTSender}; fn cot( f: &mut IdealCOT, @@ -70,6 +70,17 @@ impl COTSender for IdealCOTSender { } } +#[async_trait] +impl RandomCOTSender for IdealCOTSender { + async fn send_random_correlated( + &mut self, + ctx: &mut Ctx, + count: usize, + ) -> Result, OTError> { + Ok(self.0.call(ctx, count, rcot).await) + } +} + /// Ideal OT receiver. #[derive(Debug, Clone)] pub struct IdealCOTReceiver(Bob); @@ -105,3 +116,76 @@ impl RandomCOTReceiver for IdealCOTReceiver { Ok(self.0.call(ctx, count, rcot).await) } } + +#[cfg(test)] +mod tests { + use super::*; + use mpz_common::executor::test_st_executor; + use mpz_ot_core::test::assert_cot; + use rand::{Rng, SeedableRng}; + use rand_chacha::ChaCha12Rng; + + #[tokio::test] + async fn test_ideal_cot() { + let mut rng = ChaCha12Rng::seed_from_u64(0); + let (mut ctx_a, mut ctx_b) = test_st_executor(8); + let (mut alice, mut bob) = ideal_cot(); + + let delta = alice.0.get_mut().delta(); + + let count = 10; + let choices = (0..count).map(|_| rng.gen()).collect::>(); + + let ( + COTSenderOutput { + id: id_a, + msgs: sender_msgs, + }, + COTReceiverOutput { + id: id_b, + msgs: receiver_msgs, + }, + ) = tokio::try_join!( + alice.send_correlated(&mut ctx_a, count), + bob.receive_correlated(&mut ctx_b, &choices) + ) + .unwrap(); + + assert_eq!(id_a, id_b); + assert_eq!(count, sender_msgs.len()); + assert_eq!(count, receiver_msgs.len()); + assert_cot(delta, &choices, &sender_msgs, &receiver_msgs); + } + + #[tokio::test] + async fn test_ideal_rcot() { + let (mut ctx_a, mut ctx_b) = test_st_executor(8); + let (mut alice, mut bob) = ideal_rcot(); + + let delta = alice.0.get_mut().delta(); + + let count = 10; + + let ( + RCOTSenderOutput { + id: id_a, + msgs: sender_msgs, + }, + RCOTReceiverOutput { + id: id_b, + choices, + msgs: receiver_msgs, + }, + ) = tokio::try_join!( + alice.send_random_correlated(&mut ctx_a, count), + bob.receive_random_correlated(&mut ctx_b, count) + ) + .unwrap(); + + assert_eq!(id_a, id_b); + assert_eq!(count, sender_msgs.len()); + assert_eq!(count, receiver_msgs.len()); + assert_eq!(count, choices.len()); + assert_cot(delta, &choices, &sender_msgs, &receiver_msgs); + } +} diff --git a/crates/mpz-ot/src/ideal/rcot.rs b/crates/mpz-ot/src/ideal/rcot.rs deleted file mode 100644 index deb524d3..00000000 --- a/crates/mpz-ot/src/ideal/rcot.rs +++ /dev/null @@ -1,158 +0,0 @@ -//! Ideal functionality for random correlated oblivious transfer. - -use crate::{OTError, OTSetup, RandomCOTReceiver, RandomCOTSender}; -use async_trait::async_trait; -use futures::{channel::mpsc, StreamExt}; -use mpz_common::Context; -use mpz_core::Block; -use rand::Rng; -use rand_chacha::ChaCha12Rng; -use rand_core::SeedableRng; - -/// Ideal random OT sender. -#[derive(Debug)] -pub struct IdealRandomCOTSender { - sender: mpsc::Sender>, - delta: Block, - rng: ChaCha12Rng, -} - -/// Ideal random OT receiver. -#[derive(Debug)] -pub struct IdealRandomCOTReceiver { - receiver: mpsc::Receiver>, - rng: ChaCha12Rng, -} - -/// Creates a pair of ideal random COT sender and receiver. -pub fn ideal_random_cot_pair( - seed: [u8; 32], - delta: Block, -) -> (IdealRandomCOTSender, IdealRandomCOTReceiver) { - let (sender, receiver) = mpsc::channel(10); - - ( - IdealRandomCOTSender { - sender, - delta, - rng: ChaCha12Rng::from_seed(seed), - }, - IdealRandomCOTReceiver { - receiver, - rng: ChaCha12Rng::from_seed(seed), - }, - ) -} - -#[async_trait] -impl OTSetup for IdealRandomCOTSender -where - Ctx: Context, - T: Send + Sync, -{ - async fn setup(&mut self, _ctx: &mut Ctx) -> Result<(), OTError> { - Ok(()) - } -} - -#[async_trait] -impl RandomCOTSender for IdealRandomCOTSender { - async fn send_random_correlated( - &mut self, - _ctx: &mut Ctx, - count: usize, - ) -> Result, OTError> { - let low = (0..count) - .map(|_| Block::random(&mut self.rng)) - .collect::>(); - - self.sender - .try_send( - low.iter() - .map(|msg| [*msg, *msg ^ self.delta]) - .collect::>(), - ) - .expect("IdealRandomCOTSender should be able to send"); - - Ok(low) - } -} - -#[async_trait] -impl OTSetup for IdealRandomCOTReceiver -where - Ctx: Context, - T: Send + Sync, -{ - async fn setup(&mut self, _ctx: &mut Ctx) -> Result<(), OTError> { - Ok(()) - } -} - -#[async_trait] -impl RandomCOTReceiver for IdealRandomCOTReceiver { - async fn receive_random_correlated( - &mut self, - _ctx: &mut Ctx, - count: usize, - ) -> Result<(Vec, Vec), OTError> { - let payload = self - .receiver - .next() - .await - .expect("IdealRandomCOTSender should send a value"); - - assert_eq!(payload.len(), count); - - let choices = (0..count).map(|_| self.rng.gen()).collect::>(); - let payload = payload - .into_iter() - .zip(&choices) - .map(|(v, c)| { - let [low, high] = v; - if *c { - high - } else { - low - } - }) - .collect(); - - Ok((choices, payload)) - } -} - -#[cfg(test)] -mod tests { - use mpz_common::executor::test_st_executor; - - use super::*; - - // Test that the sender and receiver can be used to send and receive values - #[tokio::test] - async fn test_ideal_random_cot_owned() { - let seed = [0u8; 32]; - let (mut ctx_sender, mut ctx_receiver) = test_st_executor(8); - - let delta = Block::from([42u8; 16]); - let (mut sender, mut receiver) = ideal_random_cot_pair::(seed, delta); - - let values = sender - .send_random_correlated(&mut ctx_sender, 8) - .await - .unwrap(); - - let (choices, received) = receiver - .receive_random_correlated(&mut ctx_receiver, 8) - .await - .unwrap(); - - let expected = values - .into_iter() - .zip(choices) - .map(|(v, c)| if c { v ^ delta } else { v }) - .collect::>(); - - assert_eq!(received, expected); - } -} diff --git a/crates/mpz-ot/src/lib.rs b/crates/mpz-ot/src/lib.rs index 4ddafe21..1a21fa2b 100644 --- a/crates/mpz-ot/src/lib.rs +++ b/crates/mpz-ot/src/lib.rs @@ -19,7 +19,7 @@ use mpz_common::Context; pub use mpz_ot_core::{ COTReceiverOutput, COTSenderOutput, OTReceiverOutput, OTSenderOutput, RCOTReceiverOutput, - ROTReceiverOutput, ROTSenderOutput, TransferId, + RCOTSenderOutput, ROTReceiverOutput, ROTSenderOutput, TransferId, }; /// An oblivious transfer error. @@ -96,6 +96,24 @@ pub trait RandomOTSender { ) -> Result, OTError>; } +/// A random correlated oblivious transfer sender. +#[async_trait] +pub trait RandomCOTSender { + /// Obliviously transfers the correlated messages to the receiver. + /// + /// Returns the `0`-bit messages that were obliviously transferred. + /// + /// # Arguments + /// + /// * `ctx` - The thread context. + /// * `count` - The number of correlated messages to obliviously transfer. + async fn send_random_correlated( + &mut self, + ctx: &mut Ctx, + count: usize, + ) -> Result, OTError>; +} + /// An oblivious transfer receiver. #[async_trait] pub trait OTReceiver { From f9fa8dd65b587ddacb12f1f69b54d03b6f656ac6 Mon Sep 17 00:00:00 2001 From: dan Date: Wed, 15 May 2024 08:06:13 +0000 Subject: [PATCH 14/39] docs: fix typos (#130) --- crates/mpz-ot-core/src/lib.rs | 4 ++-- crates/mpz-ot/src/ideal/cot.rs | 4 ++-- crates/mpz-ot/src/ideal/ot.rs | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/crates/mpz-ot-core/src/lib.rs b/crates/mpz-ot-core/src/lib.rs index 87314c5a..8dd77287 100644 --- a/crates/mpz-ot-core/src/lib.rs +++ b/crates/mpz-ot-core/src/lib.rs @@ -75,7 +75,7 @@ pub struct COTReceiverOutput { pub struct RCOTSenderOutput { /// The transfer id. pub id: TransferId, - /// The msgs. + /// The `0-bit` messages. pub msgs: Vec, } @@ -126,7 +126,7 @@ pub struct OTReceiverOutput { pub msgs: Vec, } -/// The output that sender receivers from the SPCOT functionality. +/// The output that sender receives from the SPCOT functionality. #[derive(Debug)] pub struct SPCOTSenderOutput { /// The transfer id. diff --git a/crates/mpz-ot/src/ideal/cot.rs b/crates/mpz-ot/src/ideal/cot.rs index ee739584..47d739b8 100644 --- a/crates/mpz-ot/src/ideal/cot.rs +++ b/crates/mpz-ot/src/ideal/cot.rs @@ -45,7 +45,7 @@ pub fn ideal_rcot() -> (IdealCOTSender, IdealCOTReceiver) { (IdealCOTSender(alice), IdealCOTReceiver(bob)) } -/// Ideal OT sender. +/// Ideal COT sender. #[derive(Debug, Clone)] pub struct IdealCOTSender(Alice); @@ -81,7 +81,7 @@ impl RandomCOTSender for IdealCOTSender { } } -/// Ideal OT receiver. +/// Ideal COT receiver. #[derive(Debug, Clone)] pub struct IdealCOTReceiver(Bob); diff --git a/crates/mpz-ot/src/ideal/ot.rs b/crates/mpz-ot/src/ideal/ot.rs index 60586c2f..4504c19a 100644 --- a/crates/mpz-ot/src/ideal/ot.rs +++ b/crates/mpz-ot/src/ideal/ot.rs @@ -1,4 +1,4 @@ -//! Ideal functionality for correlated oblivious transfer. +//! Ideal functionality for chosen-message oblivious transfer. use std::marker::PhantomData; From 10f43567daef0384656b17af107488d2cd997948 Mon Sep 17 00:00:00 2001 From: "sinu.eth" <65924192+sinui0@users.noreply.github.com> Date: Wed, 15 May 2024 07:33:09 -0800 Subject: [PATCH 15/39] feat(mpz-common): dummy executor (#132) --- crates/mpz-common/src/executor/dummy.rs | 148 ++++++++++++++++++++++++ crates/mpz-common/src/executor/mod.rs | 2 + 2 files changed, 150 insertions(+) create mode 100644 crates/mpz-common/src/executor/dummy.rs diff --git a/crates/mpz-common/src/executor/dummy.rs b/crates/mpz-common/src/executor/dummy.rs new file mode 100644 index 00000000..96ea5f4d --- /dev/null +++ b/crates/mpz-common/src/executor/dummy.rs @@ -0,0 +1,148 @@ +use async_trait::async_trait; + +use scoped_futures::ScopedBoxFuture; +use serio::{Sink, Stream}; + +use crate::{context::Context, ThreadId}; + +/// A dummy executor. +#[derive(Debug, Default)] +pub struct DummyExecutor { + id: ThreadId, + io: DummyIo, +} + +/// A dummy I/O. +#[derive(Debug, Default)] +pub struct DummyIo; + +impl Sink for DummyIo { + type Error = std::io::Error; + + fn poll_ready( + self: std::pin::Pin<&mut Self>, + _cx: &mut std::task::Context<'_>, + ) -> std::task::Poll> { + std::task::Poll::Ready(Ok(())) + } + + fn start_send( + self: std::pin::Pin<&mut Self>, + _item: Item, + ) -> Result<(), Self::Error> { + Ok(()) + } + + fn poll_flush( + self: std::pin::Pin<&mut Self>, + _cx: &mut std::task::Context<'_>, + ) -> std::task::Poll> { + std::task::Poll::Ready(Ok(())) + } + + fn poll_close( + self: std::pin::Pin<&mut Self>, + _cx: &mut std::task::Context<'_>, + ) -> std::task::Poll> { + std::task::Poll::Ready(Ok(())) + } +} + +impl Stream for DummyIo { + type Error = std::io::Error; + + fn poll_next( + self: std::pin::Pin<&mut Self>, + _cx: &mut std::task::Context<'_>, + ) -> std::task::Poll>> { + std::task::Poll::Ready(None) + } +} + +#[async_trait] +impl Context for DummyExecutor { + type Io = DummyIo; + + fn id(&self) -> &ThreadId { + &self.id + } + + fn io_mut(&mut self) -> &mut Self::Io { + &mut self.io + } + + async fn join<'a, A, B, RA, RB>(&'a mut self, a: A, b: B) -> (RA, RB) + where + A: for<'b> FnOnce(&'b mut Self) -> ScopedBoxFuture<'a, 'b, RA> + Send + 'a, + B: for<'b> FnOnce(&'b mut Self) -> ScopedBoxFuture<'a, 'b, RB> + Send + 'a, + RA: Send + 'a, + RB: Send + 'a, + { + let a = a(self).await; + let b = b(self).await; + (a, b) + } + + async fn try_join<'a, A, B, RA, RB, E>(&'a mut self, a: A, b: B) -> Result<(RA, RB), E> + where + A: for<'b> FnOnce(&'b mut Self) -> ScopedBoxFuture<'a, 'b, Result> + Send + 'a, + B: for<'b> FnOnce(&'b mut Self) -> ScopedBoxFuture<'a, 'b, Result> + Send + 'a, + RA: Send + 'a, + RB: Send + 'a, + E: Send + 'a, + { + let a = a(self).await?; + let b = b(self).await?; + Ok((a, b)) + } +} + +#[cfg(test)] +mod tests { + use futures::executor::block_on; + use scoped_futures::ScopedFutureExt; + + use super::*; + + #[derive(Debug, Default)] + struct LifetimeTest { + a: ThreadId, + b: ThreadId, + } + + impl LifetimeTest { + // This test is to ensure that the compiler is satisfied with the lifetimes + // of the async closures passed to `join`. + async fn foo(&mut self, ctx: &mut Ctx) { + let a = &mut self.a; + let b = &mut self.b; + ctx.join( + |ctx| { + async move { + *a = ctx.id().clone(); + } + .scope_boxed() + }, + |ctx| { + async move { + *b = ctx.id().clone(); + } + .scope_boxed() + }, + ) + .await; + + // Make sure we can mutate the fields after borrowing them in the async closures. + self.a = ThreadId::default(); + self.b = ThreadId::default(); + } + } + + #[test] + fn test_dummy_executor_join() { + let mut ctx = DummyExecutor::default(); + let mut test = LifetimeTest::default(); + + block_on(test.foo(&mut ctx)); + } +} diff --git a/crates/mpz-common/src/executor/mod.rs b/crates/mpz-common/src/executor/mod.rs index d5e66b37..7e6054cd 100644 --- a/crates/mpz-common/src/executor/mod.rs +++ b/crates/mpz-common/src/executor/mod.rs @@ -1,7 +1,9 @@ //! Executors. +mod dummy; mod st; +pub use dummy::{DummyExecutor, DummyIo}; pub use st::STExecutor; #[cfg(any(test, feature = "test-utils"))] From 6fe419c71c27820e73f01e9d4fa6eecb54c2bc1a Mon Sep 17 00:00:00 2001 From: "sinu.eth" <65924192+sinui0@users.noreply.github.com> Date: Wed, 15 May 2024 13:19:49 -0800 Subject: [PATCH 16/39] feat(mpz-common): simple counter (#133) * feat(mpz-common): simple counter * add derives --- crates/mpz-common/src/id.rs | 25 +++++++++++++++++++++++++ crates/mpz-common/src/lib.rs | 2 +- 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/crates/mpz-common/src/id.rs b/crates/mpz-common/src/id.rs index 97b8ff31..f7a470c6 100644 --- a/crates/mpz-common/src/id.rs +++ b/crates/mpz-common/src/id.rs @@ -1,3 +1,4 @@ +use core::fmt; use std::sync::Arc; /// A logical thread identifier. @@ -50,3 +51,27 @@ impl AsRef<[u8]> for ThreadId { self.as_bytes() } } + +/// A simple counter. +#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub struct Counter(u32); + +impl Counter { + /// Increments the counter in place, returning the previous value. + pub fn next(&mut self) -> Self { + let prev = self.0; + self.0 += 1; + Self(prev) + } + + /// Returns the next value without incrementing the counter. + pub fn peek(&self) -> Self { + Self(self.0 + 1) + } +} + +impl fmt::Display for Counter { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{}", self.0) + } +} diff --git a/crates/mpz-common/src/lib.rs b/crates/mpz-common/src/lib.rs index 53fc6458..e71a0ab9 100644 --- a/crates/mpz-common/src/lib.rs +++ b/crates/mpz-common/src/lib.rs @@ -23,7 +23,7 @@ pub mod ideal; pub mod sync; pub use context::Context; -pub use id::ThreadId; +pub use id::{Counter, ThreadId}; // Re-export scoped-futures for use with the callback-like API in `Context`. pub use scoped_futures; From cf36cf72816f130322ae306807663021c773770b Mon Sep 17 00:00:00 2001 From: "sinu.eth" <65924192+sinui0@users.noreply.github.com> Date: Tue, 28 May 2024 10:47:53 -0700 Subject: [PATCH 17/39] refactor(mpz-garble-core): batched garbling (#140) * refactor(mpz-garble-core): batched garbling * Apply suggestions from code review Co-authored-by: th4s Co-authored-by: dan * qualify comment * remove unused msg module * comments --------- Co-authored-by: th4s Co-authored-by: dan --- crates/mpz-garble-core/Cargo.toml | 1 + crates/mpz-garble-core/benches/garble.rs | 78 ++++- crates/mpz-garble-core/src/circuit.rs | 26 +- crates/mpz-garble-core/src/encoding/mod.rs | 11 +- crates/mpz-garble-core/src/evaluator.rs | 305 +++++++++++------ crates/mpz-garble-core/src/generator.rs | 368 +++++++++++++++------ crates/mpz-garble-core/src/lib.rs | 166 +++++++--- crates/mpz-garble-core/src/msg.rs | 29 -- 8 files changed, 678 insertions(+), 306 deletions(-) delete mode 100644 crates/mpz-garble-core/src/msg.rs diff --git a/crates/mpz-garble-core/Cargo.toml b/crates/mpz-garble-core/Cargo.toml index bda49e72..4518f611 100644 --- a/crates/mpz-garble-core/Cargo.toml +++ b/crates/mpz-garble-core/Cargo.toml @@ -24,6 +24,7 @@ rand_core.workspace = true rand_chacha.workspace = true regex = { workspace = true, optional = true } once_cell.workspace = true +opaque-debug.workspace = true serde = { workspace = true, features = ["derive"] } serde_arrays.workspace = true diff --git a/crates/mpz-garble-core/benches/garble.rs b/crates/mpz-garble-core/benches/garble.rs index c720bf01..143b0adb 100644 --- a/crates/mpz-garble-core/benches/garble.rs +++ b/crates/mpz-garble-core/benches/garble.rs @@ -1,39 +1,83 @@ use criterion::{black_box, criterion_group, criterion_main, Criterion}; use mpz_circuits::circuits::AES128; -use mpz_garble_core::{ChaChaEncoder, Encoder, Generator}; +use mpz_garble_core::{ChaChaEncoder, Encoder, Evaluator, Generator}; fn criterion_benchmark(c: &mut Criterion) { - let mut group = c.benchmark_group("garble_circuits"); + let mut gb_group = c.benchmark_group("garble"); let encoder = ChaChaEncoder::new([0u8; 32]); - let inputs = AES128 + let full_inputs = AES128 .inputs() .iter() .map(|value| encoder.encode_by_type(0, &value.value_type())) .collect::>(); - group.bench_function("aes128", |b| { + + let active_inputs = vec![ + full_inputs[0].clone().select([0u8; 16]).unwrap(), + full_inputs[1].clone().select([0u8; 16]).unwrap(), + ]; + + gb_group.bench_function("aes128", |b| { + let mut gen = Generator::default(); b.iter(|| { - let mut gen = Generator::new(AES128.clone(), encoder.delta(), &inputs).unwrap(); + let mut gen_iter = gen + .generate(&AES128, encoder.delta(), full_inputs.clone()) + .unwrap(); - let mut enc_gates = Vec::with_capacity(AES128.and_count()); - for gate in gen.by_ref() { - enc_gates.push(gate); - } + let _: Vec<_> = gen_iter.by_ref().collect(); + + black_box(gen_iter.finish().unwrap()) + }) + }); + + gb_group.bench_function("aes128_batched", |b| { + let mut gen = Generator::default(); + b.iter(|| { + let mut gen_iter = gen + .generate_batched(&AES128, encoder.delta(), full_inputs.clone()) + .unwrap(); + + let _: Vec<_> = gen_iter.by_ref().collect(); + + black_box(gen_iter.finish().unwrap()) + }) + }); + + gb_group.bench_function("aes128_with_hash", |b| { + let mut gen = Generator::default(); + b.iter(|| { + let mut gen_iter = gen + .generate(&AES128, encoder.delta(), full_inputs.clone()) + .unwrap(); + + gen_iter.enable_hasher(); - black_box(gen.outputs().unwrap()) + let _: Vec<_> = gen_iter.by_ref().collect(); + + black_box(gen_iter.finish().unwrap()) }) }); - group.bench_function("aes128_with_hash", |b| { + + drop(gb_group); + + let mut ev_group = c.benchmark_group("evaluate"); + + ev_group.bench_function("aes128", |b| { + let mut gen = Generator::default(); + let mut gen_iter = gen + .generate(&AES128, encoder.delta(), full_inputs.clone()) + .unwrap(); + let gates: Vec<_> = gen_iter.by_ref().collect(); + + let mut ev = Evaluator::default(); b.iter(|| { - let mut gen = - Generator::new_with_hasher(AES128.clone(), encoder.delta(), &inputs).unwrap(); + let mut ev_consumer = ev.evaluate(&AES128, active_inputs.clone()).unwrap(); - let mut enc_gates = Vec::with_capacity(AES128.and_count()); - for gate in gen.by_ref() { - enc_gates.push(gate); + for gate in &gates { + ev_consumer.next(*gate); } - black_box(gen.outputs().unwrap()) + black_box(ev_consumer.finish().unwrap()); }) }); } diff --git a/crates/mpz-garble-core/src/circuit.rs b/crates/mpz-garble-core/src/circuit.rs index 14dffd8b..da8fe499 100644 --- a/crates/mpz-garble-core/src/circuit.rs +++ b/crates/mpz-garble-core/src/circuit.rs @@ -3,7 +3,7 @@ use std::ops::Index; use mpz_core::Block; use serde::{Deserialize, Serialize}; -use crate::EncodingCommitment; +use crate::{EncodingCommitment, DEFAULT_BATCH_SIZE}; /// Encrypted gate truth table /// @@ -11,7 +11,7 @@ use crate::EncodingCommitment; /// privacy-free garbling mode where it will be reduced to 1. /// /// We do not yet support privacy-free garbling. -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +#[derive(Debug, Default, Clone, Copy, PartialEq, Serialize, Deserialize)] pub struct EncryptedGate(#[serde(with = "serde_arrays")] pub(crate) [Block; 2]); impl EncryptedGate { @@ -35,6 +35,28 @@ impl Index for EncryptedGate { } } +/// A batch of encrypted gates. +/// +/// # Parameters +/// +/// - `N`: The size of a batch. +#[derive(Debug, Serialize, Deserialize)] +pub struct EncryptedGateBatch( + #[serde(with = "serde_arrays")] [EncryptedGate; N], +); + +impl EncryptedGateBatch { + /// Creates a new batch of encrypted gates. + pub fn new(batch: [EncryptedGate; N]) -> Self { + Self(batch) + } + + /// Returns the inner array. + pub fn into_array(self) -> [EncryptedGate; N] { + self.0 + } +} + /// A garbled circuit #[derive(Debug, Clone, Serialize, Deserialize)] pub struct GarbledCircuit { diff --git a/crates/mpz-garble-core/src/encoding/mod.rs b/crates/mpz-garble-core/src/encoding/mod.rs index 4c46148a..772888de 100644 --- a/crates/mpz-garble-core/src/encoding/mod.rs +++ b/crates/mpz-garble-core/src/encoding/mod.rs @@ -272,7 +272,7 @@ impl Index for Labels { } /// Encoded bit label. -#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)] +#[derive(Debug, Default, Clone, Copy, PartialEq, Serialize, Deserialize)] pub struct Label(Block); impl Label { @@ -350,6 +350,15 @@ impl BitXor for &Label { } } +impl BitXor<&Delta> for Label { + type Output = Label; + + #[inline] + fn bitxor(self, rhs: &Delta) -> Self::Output { + Label(self.0 ^ rhs.0) + } +} + impl AsRef for Label { fn as_ref(&self) -> &Block { &self.0 diff --git a/crates/mpz-garble-core/src/evaluator.rs b/crates/mpz-garble-core/src/evaluator.rs index 5f28b0b9..9ea29035 100644 --- a/crates/mpz-garble-core/src/evaluator.rs +++ b/crates/mpz-garble-core/src/evaluator.rs @@ -1,12 +1,16 @@ -use std::sync::Arc; +use core::fmt; use blake3::Hasher; use crate::{ circuit::EncryptedGate, encoding::{state, EncodedValue, Label}, + EncryptedGateBatch, DEFAULT_BATCH_SIZE, +}; +use mpz_circuits::{ + types::{BinaryRepr, TypeError}, + Circuit, CircuitError, Gate, }; -use mpz_circuits::{types::TypeError, Circuit, CircuitError, Gate}; use mpz_core::{ aes::{FixedKeyAes, FIXED_KEY_AES}, hash::Hash, @@ -54,57 +58,42 @@ pub(crate) fn and_gate( Label::new(w_g ^ w_e) } -/// Core evaluator type for evaluating a garbled circuit. +/// Output of the evaluator. +#[derive(Debug)] +pub struct EvaluatorOutput { + /// Encoded outputs of the circuit. + pub outputs: Vec>, + /// Hash of the encrypted gates. + pub hash: Option, +} + +/// Garbled circuit evaluator. +#[derive(Debug)] pub struct Evaluator { - /// Cipher to use to encrypt the gates - cipher: &'static FixedKeyAes, - /// Circuit to evaluate - circ: Arc, - /// Active label state - active_labels: Vec>, - /// Current position in the circuit - pos: usize, - /// Current gate id - gid: usize, - /// Whether the evaluator is finished - complete: bool, - /// Hasher to use to hash the encrypted gates - hasher: Option, + /// Buffer for the active labels. + buffer: Vec