From 2e977c3404c37100faff8fd878710ddc3de09b87 Mon Sep 17 00:00:00 2001 From: sinu <65924192+sinui0@users.noreply.github.com> Date: Mon, 15 Jan 2024 18:00:12 -0800 Subject: [PATCH] add ideal COT impls --- ot/mpz-ot/src/ideal/mod.rs | 9 +- ot/mpz-ot/src/ideal/owned/cot.rs | 159 ++++++++++++++++++++++++++++++ ot/mpz-ot/src/ideal/owned/mod.rs | 2 + ot/mpz-ot/src/ideal/shared/cot.rs | 137 +++++++++++++++++++++++++ ot/mpz-ot/src/ideal/shared/mod.rs | 2 + ot/mpz-ot/src/lib.rs | 9 +- 6 files changed, 313 insertions(+), 5 deletions(-) create mode 100644 ot/mpz-ot/src/ideal/owned/cot.rs create mode 100644 ot/mpz-ot/src/ideal/shared/cot.rs diff --git a/ot/mpz-ot/src/ideal/mod.rs b/ot/mpz-ot/src/ideal/mod.rs index c2252022..ec2cbedf 100644 --- a/ot/mpz-ot/src/ideal/mod.rs +++ b/ot/mpz-ot/src/ideal/mod.rs @@ -3,5 +3,10 @@ mod owned; mod shared; -pub use owned::{ideal_ot_pair, IdealOTReceiver, IdealOTSender}; -pub use shared::{ideal_ot_shared_pair, IdealSharedOTReceiver, IdealSharedOTSender}; +pub use owned::{ + ideal_cot_pair, ideal_ot_pair, IdealCOTReceiver, IdealCOTSender, IdealOTReceiver, IdealOTSender, +}; +pub use shared::{ + ideal_cot_shared_pair, ideal_ot_shared_pair, IdealSharedCOTReceiver, IdealSharedCOTSender, + IdealSharedOTReceiver, IdealSharedOTSender, +}; diff --git a/ot/mpz-ot/src/ideal/owned/cot.rs b/ot/mpz-ot/src/ideal/owned/cot.rs new file mode 100644 index 00000000..b4634132 --- /dev/null +++ b/ot/mpz-ot/src/ideal/owned/cot.rs @@ -0,0 +1,159 @@ +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}; + +/// Ideal OT sender. +#[derive(Debug)] +pub struct IdealCOTSender { + sender: mpsc::Sender>, + delta: Block, +} + +/// Ideal OT receiver. +#[derive(Debug)] +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, +) -> (IdealCOTSender, IdealCOTReceiver) { + let (sender, receiver) = mpsc::channel(10); + + ( + IdealCOTSender { sender, delta }, + IdealCOTReceiver { receiver }, + ) +} + +#[async_trait] +impl OTSetup for IdealCOTSender +where + T: Send + Sync, +{ + async fn setup + Send + Unpin, St: IoStream<()> + Send + Unpin>( + &mut self, + _sink: &mut Si, + _stream: &mut St, + ) -> 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> { + self.sender + .try_send( + msgs.iter() + .map(|msg| [*msg, *msg ^ self.delta]) + .collect::>(), + ) + .expect("IdealCOTSender should be able to send"); + + Ok(()) + } +} + +#[async_trait] +impl OTSetup for IdealCOTReceiver +where + T: Send + Sync, +{ + async fn setup + Send + Unpin, St: IoStream<()> + Send + Unpin>( + &mut self, + _sink: &mut Si, + _stream: &mut St, + ) -> Result<(), OTError> { + Ok(()) + } +} + +#[async_trait] +impl COTReceiver for IdealCOTReceiver { + async fn receive_correlated + Send + Unpin, St: IoStream<()> + Send + Unpin>( + &mut self, + _sink: &mut Si, + _stream: &mut St, + choices: &[bool], + ) -> Result, OTError> { + let payload = self + .receiver + .next() + .await + .expect("IdealCOTSender should send a value"); + + Ok(payload + .into_iter() + .zip(choices) + .map(|(v, c)| { + let [low, high] = v; + if *c { + high + } else { + low + } + }) + .collect()) + } +} + +#[cfg(test)] +mod tests { + use itybity::IntoBits; + use rand::Rng; + use rand_chacha::ChaCha12Rng; + use rand_core::SeedableRng; + use utils_aio::duplex::MemoryDuplex; + + use super::*; + + // Test that the sender and receiver can be used to send and receive values + #[tokio::test] + async fn test_ideal_cot_owned() { + let mut rng = ChaCha12Rng::seed_from_u64(0); + let (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 values = Block::random_vec(&mut rng, 8); + let choices = rng.gen::().into_lsb0_vec(); + let delta = Block::from([42u8; 16]); + let (mut sender, mut receiver) = ideal_cot_pair::(delta); + + sender + .send_correlated(&mut send_sink, &mut send_stream, &values) + .await + .unwrap(); + + let received = receiver + .receive_correlated(&mut recv_sink, &mut recv_stream, &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/owned/mod.rs b/ot/mpz-ot/src/ideal/owned/mod.rs index 1f5cd253..4959e368 100644 --- a/ot/mpz-ot/src/ideal/owned/mod.rs +++ b/ot/mpz-ot/src/ideal/owned/mod.rs @@ -1,3 +1,5 @@ +mod cot; mod ot; +pub use cot::{ideal_cot_pair, IdealCOTReceiver, IdealCOTSender}; pub use ot::{ideal_ot_pair, IdealOTReceiver, IdealOTSender}; diff --git a/ot/mpz-ot/src/ideal/shared/cot.rs b/ot/mpz-ot/src/ideal/shared/cot.rs new file mode 100644 index 00000000..3266c2b8 --- /dev/null +++ b/ot/mpz-ot/src/ideal/shared/cot.rs @@ -0,0 +1,137 @@ +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_ot() { + 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 index 0a91386c..4f85b977 100644 --- a/ot/mpz-ot/src/ideal/shared/mod.rs +++ b/ot/mpz-ot/src/ideal/shared/mod.rs @@ -1,3 +1,5 @@ +mod cot; mod ot; +pub use cot::{ideal_cot_shared_pair, IdealSharedCOTReceiver, IdealSharedCOTSender}; pub use ot::{ideal_ot_shared_pair, IdealSharedOTReceiver, IdealSharedOTSender}; diff --git a/ot/mpz-ot/src/lib.rs b/ot/mpz-ot/src/lib.rs index 8842d367..94be2dc6 100644 --- a/ot/mpz-ot/src/lib.rs +++ b/ot/mpz-ot/src/lib.rs @@ -128,7 +128,10 @@ where /// * `sink` - The IO sink to the sender. /// * `stream` - The IO stream from the sender. /// * `choices` - The choices made by the receiver. - async fn receive + Send + Unpin, St: IoStream + Send + Unpin>( + async fn receive_correlated< + Si: IoSink + Send + Unpin, + St: IoStream + Send + Unpin, + >( &mut self, sink: &mut Si, stream: &mut St, @@ -260,7 +263,7 @@ pub trait COTSenderShared { /// /// * `id` - The unique identifier for this transfer. /// * `msgs` - The `0`-bit messages to obliviously transfer. - async fn send(&self, id: &str, msgs: &[T]) -> Result<(), OTError>; + async fn send_correlated(&self, id: &str, msgs: &[T]) -> Result<(), OTError>; } /// An oblivious transfer receiver that can be used via a shared reference. @@ -284,7 +287,7 @@ pub trait COTReceiverShared { /// /// * `id` - The unique identifier for this transfer. /// * `choices` - The choices made by the receiver. - async fn receive(&self, id: &str, choices: &[T]) -> Result, OTError>; + async fn receive_correlated(&self, id: &str, choices: &[T]) -> Result, OTError>; } /// An oblivious transfer sender that is committed to its messages and can reveal them