Skip to content

Commit

Permalink
add MPCOT for regular distribution
Browse files Browse the repository at this point in the history
  • Loading branch information
xiangxiecrypto committed Nov 22, 2023
1 parent 5bdb07c commit 7b126f0
Show file tree
Hide file tree
Showing 4 changed files with 406 additions and 4 deletions.
78 changes: 77 additions & 1 deletion ot/mpz-ot-core/src/ferret/mpcot/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,10 @@ pub mod sender_regular;

#[cfg(test)]
mod tests {
use super::{receiver::Receiver as MpcotReceiver, sender::Sender as MpcotSender};
use super::{
receiver::Receiver as MpcotReceiver, receiver_regular::Receiver as RegularReceiver,
sender::Sender as MpcotSender, sender_regular::Sender as RegularSender,
};
use crate::ideal::ideal_spcot::{IdealSpcot, SpcotMsgForReceiver, SpcotMsgForSender};
use mpz_core::prg::Prg;

Expand Down Expand Up @@ -88,4 +91,77 @@ mod tests {

assert_eq!(output_sender, output_receiver);
}

#[test]
fn mpcot_regular_test() {
let mut prg = Prg::new();
let delta = prg.random_block();
let mut ideal_spcot = IdealSpcot::init_with_delta(delta);

let sender = RegularSender::new();
let receiver = RegularReceiver::new();

let mut sender = sender.setup(delta);
let mut receiver = receiver.setup();

// extend once.
let alphas = [0, 3, 4, 7, 9];
let t = alphas.len();
let n = 10;

// sender generates the messages to invoke ideal spcot.
let sender_queries = sender.extend_pre(t as u32, n).unwrap();
let mut queries = receiver.extend_pre(&alphas, n).unwrap();

assert!(sender_queries
.iter()
.zip(queries.iter())
.all(|(x, (y, _))| *x == *y));

queries.iter_mut().for_each(|(x, _)| *x = 1 << (*x));

let (sender_spcot_msg, receiver_spcot_msg) = ideal_spcot.extend(&queries);

let SpcotMsgForSender { v: st } = sender_spcot_msg;
let SpcotMsgForReceiver { w: rt } = receiver_spcot_msg;

let mut output_sender = sender.extend(&st, n).unwrap();
let output_receiver = receiver.extend(&rt, n).unwrap();

for i in alphas {
output_sender[i as usize] ^= delta;
}

assert_eq!(output_sender, output_receiver);

// extend twice.
let alphas = [0, 3, 7, 9, 14, 15];
let t = alphas.len();
let n = 16;

// sender generates the messages to invoke ideal spcot.
let sender_queries = sender.extend_pre(t as u32, n).unwrap();
let mut queries = receiver.extend_pre(&alphas, n).unwrap();

assert!(sender_queries
.iter()
.zip(queries.iter())
.all(|(x, (y, _))| *x == *y));

queries.iter_mut().for_each(|(x, _)| *x = 1 << (*x));

let (sender_spcot_msg, receiver_spcot_msg) = ideal_spcot.extend(&queries);

let SpcotMsgForSender { v: st } = sender_spcot_msg;
let SpcotMsgForReceiver { w: rt } = receiver_spcot_msg;

let mut output_sender = sender.extend(&st, n).unwrap();
let output_receiver = receiver.extend(&rt, n).unwrap();

for i in alphas {
output_sender[i as usize] ^= delta;
}

assert_eq!(output_sender, output_receiver);
}
}
170 changes: 169 additions & 1 deletion ot/mpz-ot-core/src/ferret/mpcot/receiver_regular.rs
Original file line number Diff line number Diff line change
@@ -1 +1,169 @@
//! MPCOT receiver for regular indices.
//! MPCOT receiver for regular indices. Regular indices means the indices are evenly distributed.
use mpz_core::Block;

use crate::ferret::mpcot::error::ReceiverError;

/// MPCOT receiver.
#[derive(Debug, Default)]
pub struct Receiver<T: state::State = state::Initialized> {
state: T,
}

impl Receiver {
/// Creates a new Receiver.
pub fn new() -> Self {
Receiver {
state: state::Initialized::default(),
}
}

/// Completes the setup phase of the protocol.
pub fn setup(self) -> Receiver<state::Extension> {
Receiver {
state: state::Extension {
counter: 0,
queries_length: Vec::default(),
queries_depth: Vec::default(),
},
}
}
}

impl Receiver<state::Extension> {
/// Performs the prepare procedure in MPCOT extension.
/// Outputs the indices for SPCOT.
///
/// # Arguments.
///
/// * `alphas` - The queried indices.
/// * `n` - The total number of indices.
pub fn extend_pre(
&mut self,
alphas: &[u32],
n: u32,
) -> Result<Vec<(usize, u32)>, ReceiverError> {
let t = alphas.len() as u32;
if t > n {
return Err(ReceiverError::InvalidInput(
"the length of alpha should not exceed n".to_string(),
));
}

// The range of each interval.
let k = (n + t - 1) / t;

self.state.queries_length = if n % t == 0 {
vec![k as usize; t as usize]
} else {
let mut tmp = vec![k as usize; (t - 1) as usize];
tmp.push((n % k) as usize);
if tmp.iter().sum::<usize>() != n as usize {
return Err(ReceiverError::InvalidInput(
"the input parameters (t,n) are not regular".to_string(),
));
} else {
tmp
}
};

for len in self.state.queries_length.iter() {
if let Some(power) = len.checked_next_power_of_two() {
self.state.queries_depth.push(power.ilog2() as usize);
} else {
return Err(ReceiverError::InvalidInput(
"The next power of 2 of each length exceeds the MAX number".to_string(),
));
}
}

if !alphas
.iter()
.enumerate()
.all(|(i, &alpha)| (i as u32) * k <= alpha && alpha < ((i + 1) as u32) * k)
{
return Err(ReceiverError::InvalidInput(
"the input position is not regular".to_string(),
));
}

let res: Vec<(usize, u32)> = self
.state
.queries_depth
.iter()
.zip(alphas.iter())
.map(|(&d, &alpha)| (d, alpha % k))
.collect();

Ok(res)
}

/// Performs MPCOT extension.
///
/// # Arguments.
///
/// * `rt` - The vector received from SPCOT protocol on multiple queries.
/// * `n` - The total number of indices.
pub fn extend(&mut self, rt: &[Vec<Block>], n: u32) -> Result<Vec<Block>, ReceiverError> {
if rt
.iter()
.zip(self.state.queries_depth.iter())
.any(|(blks, m)| blks.len() != 1 << m)
{
return Err(ReceiverError::InvalidInput(
"the length of rt[i] should be 2^self.state.queries_depth[i]".to_string(),
));
}

let mut res: Vec<Block> = Vec::with_capacity(n as usize);

for (blks, pos) in rt.iter().zip(self.state.queries_length.iter()) {
res.extend(&blks[..*pos]);
}

self.state.counter += 1;
self.state.queries_depth.clear();
self.state.queries_length.clear();

Ok(res)
}
}
/// The receiver's state.
pub mod state {

mod sealed {
pub trait Sealed {}

impl Sealed for super::Initialized {}
impl Sealed for super::Extension {}
}

/// The receiver's state.
pub trait State: sealed::Sealed {}

/// The receiver's initial state.
#[derive(Default)]
pub struct Initialized {}

impl State for Initialized {}

opaque_debug::implement!(Initialized);

/// The receiver's state after the setup phase.
///
/// In this state the receiver performs MPCOT extension (potentially multiple times).
pub struct Extension {
/// Current MPCOT counter
pub(super) counter: usize,

/// Current queries length.
pub(super) queries_length: Vec<usize>,

/// The depth of queries.
pub(super) queries_depth: Vec<usize>,
}

impl State for Extension {}

opaque_debug::implement!(Extension);
}
2 changes: 1 addition & 1 deletion ot/mpz-ot-core/src/ferret/mpcot/sender.rs
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ impl Sender<state::Extension> {
.any(|(s, b)| s.len() != *b)
{
return Err(SenderError::InvalidInput(
"the length of st[i] should be self.state.buckets_length".to_string(),
"the length of st[i] should be self.state.buckets_length[i]".to_string(),
));
}

Expand Down
Loading

0 comments on commit 7b126f0

Please sign in to comment.