Skip to content

Commit

Permalink
Add shared version for ROT
Browse files Browse the repository at this point in the history
  • Loading branch information
th4s committed Jan 19, 2024
1 parent 9b9cd42 commit 89c02f4
Show file tree
Hide file tree
Showing 4 changed files with 254 additions and 4 deletions.
5 changes: 3 additions & 2 deletions ot/mpz-ot/src/ideal/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ pub use owned::{
};
pub use shared::{
ideal_cot_shared_pair, ideal_ot_shared_pair, ideal_random_cot_shared_pair,
IdealSharedCOTReceiver, IdealSharedCOTSender, IdealSharedOTReceiver, IdealSharedOTSender,
IdealSharedRandomCOTReceiver, IdealSharedRandomCOTSender,
ideal_random_ot_shared_pair, IdealSharedCOTReceiver, IdealSharedCOTSender,
IdealSharedOTReceiver, IdealSharedOTSender, IdealSharedRandomCOTReceiver,
IdealSharedRandomCOTSender, IdealSharedRandomOTReceiver, IdealSharedRandomOTSender,
};
5 changes: 5 additions & 0 deletions ot/mpz-ot/src/ideal/shared/mod.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
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,
};
242 changes: 242 additions & 0 deletions ot/mpz-ot/src/ideal/shared/rot.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,242 @@
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<Mutex<HashMap<String, Box<dyn Any + Send + 'static>>>>;
type ReceiverBuffer = Arc<Mutex<HashMap<String, oneshot::Sender<Box<dyn Any + Send + 'static>>>>>;

/// 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<Mutex<HashMap<String, Box<dyn Any + Send>>>> =
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<Mutex<ChaCha12Rng>>,
sender_buffer: SenderBuffer,
receiver_buffer: ReceiverBuffer,
}

#[async_trait]
impl RandomOTSenderShared<[Block; 2]> for IdealSharedRandomOTSender {
async fn send_random(&self, id: &str, count: usize) -> Result<Vec<[Block; 2]>, 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::<Vec<_>>();

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<const N: usize> RandomOTSenderShared<[[u8; N]; 2]> for IdealSharedRandomOTSender {
async fn send_random(&self, id: &str, count: usize) -> Result<Vec<[[u8; N]; 2]>, 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::<Vec<_>>();

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<Mutex<ChaCha12Rng>>,
sender_buffer: SenderBuffer,
receiver_buffer: ReceiverBuffer,
}

#[async_trait]
impl RandomOTReceiverShared<bool, Block> for IdealSharedRandomOTReceiver {
async fn receive_random(
&self,
id: &str,
count: usize,
) -> Result<(Vec<bool>, Vec<Block>), OTError> {
let choices = (0..count)
.map(|_| (*self.rng.lock().unwrap()).gen())
.collect::<Vec<bool>>();

if let Some(value) = self.sender_buffer.lock().unwrap().remove(id) {
let values = *value
.downcast::<Vec<[Block; 2]>>()
.expect("value type should be consistent");

let value = values
.into_iter()
.zip(&choices)
.map(|([low, high], c)| if *c { high } else { low })
.collect::<Vec<_>>();

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::<Vec<[Block; 2]>>()
.expect("value type should be consistent");

let values = values
.into_iter()
.zip(&choices)
.map(|([low, high], c)| if *c { high } else { low })
.collect::<Vec<_>>();

Ok((choices, values))
}
}

#[async_trait]
impl<const N: usize> RandomOTReceiverShared<bool, [u8; N]> for IdealSharedRandomOTReceiver {
async fn receive_random(
&self,
id: &str,
count: usize,
) -> Result<(Vec<bool>, Vec<[u8; N]>), OTError> {
let choices = (0..count)
.map(|_| (*self.rng.lock().unwrap()).gen())
.collect::<Vec<bool>>();

if let Some(value) = self.sender_buffer.lock().unwrap().remove(id) {
let values = *value
.downcast::<Vec<[[u8; N]; 2]>>()
.expect("value type should be consistent");

let value = values
.into_iter()
.zip(&choices)
.map(|([low, high], c)| if *c { high } else { low })
.collect::<Vec<_>>();

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::<Vec<[[u8; N]; 2]>>()
.expect("value type should be consistent");

let values = values
.into_iter()
.zip(&choices)
.map(|([low, high], c)| if *c { high } else { low })
.collect::<Vec<_>>();

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<bool>, Vec<Block>) =
receiver.receive_random("", 8).await.unwrap();

let expected: Vec<Block> = values
.into_iter()
.zip(choices)
.map(|(v, c): ([Block; 2], bool)| v[c as usize])
.collect::<Vec<_>>();

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<bool>, 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::<Vec<_>>();

assert_eq!(received, expected);
}
}

6 changes: 4 additions & 2 deletions ot/mpz-ot/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -364,7 +364,8 @@ pub trait RandomOTSenderShared<T> {
/// # Arguments
///
/// * `id` - The unique identifier for this transfer.
async fn send(&self, id: &str) -> Result<Vec<T>, OTError>;
/// * `count` - The number of pairs of random messages to output.
async fn send_random(&self, id: &str, count: usize) -> Result<Vec<T>, OTError>;
}

/// A correlated oblivious transfer sender that can be used via a shared reference.
Expand Down Expand Up @@ -413,7 +414,8 @@ pub trait RandomOTReceiverShared<T, U> {
/// # Arguments
///
/// * `id` - The unique identifier for this transfer.
async fn receive(&self, id: &str) -> Result<(Vec<T>, Vec<U>), OTError>;
/// * `count` - The number of random messages to receive.
async fn receive_random(&self, id: &str, count: usize) -> Result<(Vec<T>, Vec<U>), OTError>;
}

/// A correlated oblivious transfer receiver that can be used via a shared reference.
Expand Down

0 comments on commit 89c02f4

Please sign in to comment.