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 96d15c8e..4799af0d 100644 --- a/ot/mpz-ot/Cargo.toml +++ b/ot/mpz-ot/Cargo.toml @@ -7,21 +7,20 @@ edition = "2021" 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 @@ -32,9 +31,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>; }