use crate::{
block::Block,
channel::{Channel, recv_from, recv_vec_from, send_to},
mpc::faand::Error,
ot_core::{
CorrelatedReceiver, CorrelatedSender, FixedKeyInitializer, Malicious,
Receiver as OtReceiver, SemiHonest, Sender as OtSender,
alsz::{
Receiver as AlszReceiver, Sender as AlszSender, boolvec_to_u8vec, u8vec_to_boolvec,
},
},
};
use rand::{CryptoRng, Rng, RngCore};
use rand_chacha::ChaCha20Rng;
const SSP: usize = 40;
pub(crate) struct Sender<OT: OtReceiver<Msg = Block> + Malicious> {
pub(super) ot: AlszSender<OT>,
}
pub(crate) struct Receiver<OT: OtSender<Msg = Block> + Malicious> {
ot: AlszReceiver<OT>,
}
impl<OT: OtReceiver<Msg = Block> + Malicious> Sender<OT> {
pub(super) async fn send_setup<C: Channel>(
&mut self,
channel: &C,
m: usize,
p_to: usize,
shared_rand: &mut ChaCha20Rng,
) -> Result<Vec<u8>, Error> {
let m = m.next_multiple_of(8);
let ncols = m + 128 + SSP;
let qs = self.ot.send_setup(channel, ncols, p_to).await?;
let mut check = (Block::default(), Block::default());
let mut chi = Block::default();
for j in 0..ncols {
let q = &qs[j * 16..(j + 1) * 16];
let q: [u8; 16] = q.try_into().unwrap();
let q = Block::from(q);
shared_rand.fill_bytes(chi.as_mut());
let (lo, hi) = q.clmul(&chi);
check = xor_two_blocks(&check, &(lo, hi));
}
let (x, t0, t1) = recv_from::<(Block, Block, Block)>(channel, p_to, "KOS_OT_x_t0_t1")
.await?
.pop()
.ok_or(Error::EmptyMsg)?;
let (lo, hi) = x.clmul(&self.ot.s_);
let check = xor_two_blocks(&check, &(lo, hi));
if check != (t0, t1) {
return Err(Error::KOSConsistencyCheckFailed);
}
Ok(qs)
}
}
impl<OT: OtReceiver<Msg = Block> + Malicious> FixedKeyInitializer for Sender<OT> {
async fn init_fixed_key<C: Channel, RNG: CryptoRng + Rng>(
channel: &C,
s_: [u8; 16],
rng: &mut RNG,
p_to: usize,
shared_rand: &mut ChaCha20Rng,
) -> Result<Self, Error> {
let ot = AlszSender::<OT>::init_fixed_key(channel, s_, rng, p_to, shared_rand).await?;
Ok(Self { ot })
}
}
impl<OT: OtReceiver<Msg = Block> + Malicious> OtSender for Sender<OT> {
type Msg = Block;
async fn init<C: Channel, RNG: CryptoRng + Rng>(
channel: &C,
rng: &mut RNG,
p_to: usize,
shared_rand: &mut ChaCha20Rng,
) -> Result<Self, Error> {
let ot = AlszSender::<OT>::init(channel, rng, p_to, shared_rand).await?;
Ok(Self { ot })
}
async fn send<C: Channel, RNG: CryptoRng + Rng>(
&mut self,
channel: &C,
inputs: &[(Block, Block)],
_: &mut RNG,
p_to: usize,
shared_rand: &mut ChaCha20Rng,
) -> Result<(), Error> {
let m = inputs.len();
let qs = self.send_setup(channel, m, p_to, shared_rand).await?;
let mut y0y1_vec: Vec<(Block, Block)> = vec![];
for (j, input) in inputs.iter().enumerate() {
let q = &qs[j * 16..(j + 1) * 16];
let q: [u8; 16] = q.try_into().unwrap();
let q = Block::from(q);
let y0 = self.ot.hash.tccr_hash_block(Block::from(j as u128), q) ^ input.0;
let q = q ^ self.ot.s_;
let y1 = self.ot.hash.tccr_hash_block(Block::from(j as u128), q) ^ input.1;
y0y1_vec.push((y0, y1));
}
send_to(channel, p_to, "KOS_OT_send", &y0y1_vec).await?;
Ok(())
}
}
impl<OT: OtReceiver<Msg = Block> + Malicious> CorrelatedSender for Sender<OT> {
async fn send_correlated<C: Channel, RNG: CryptoRng + Rng>(
&mut self,
channel: &C,
deltas: &[Self::Msg],
_: &mut RNG,
p_to: usize,
shared_rand: &mut ChaCha20Rng,
) -> Result<Vec<(Self::Msg, Self::Msg)>, Error> {
let m = deltas.len();
let qs = self.send_setup(channel, m, p_to, shared_rand).await?;
let mut out = Vec::with_capacity(m);
let mut ys = Vec::with_capacity(m);
for (j, delta) in deltas.iter().enumerate() {
let q = &qs[j * 16..(j + 1) * 16];
let q: [u8; 16] = q.try_into().unwrap();
let q = Block::from(q);
let x0 = self.ot.hash.tccr_hash_block(Block::from(j as u128), q);
let x1 = x0 ^ *delta;
let q = q ^ self.ot.s_;
let y = self.ot.hash.tccr_hash_block(Block::from(j as u128), q) ^ x1;
ys.push(y);
out.push((x0, x1));
}
send_to(channel, p_to, "KOS_OT_corr", &ys).await?;
Ok(out)
}
}
impl<OT: OtSender<Msg = Block> + Malicious> Receiver<OT> {
pub(super) async fn recv_setup<C: Channel, RNG: CryptoRng + Rng>(
&mut self,
channel: &C,
inputs: &[bool],
_: &mut RNG,
p_to: usize,
shared_rand: &mut ChaCha20Rng,
) -> Result<Vec<u8>, Error> {
let m = inputs.len();
let m = m.next_multiple_of(8);
let m_ = m + 128 + SSP;
let mut r = boolvec_to_u8vec(inputs);
r.extend((0..(m_ - m) / 8).map(|_| rand::random::<u8>()));
let ts = self.ot.recv_setup(channel, &r, m_, p_to).await?;
let mut x = Block::default();
let mut t = (Block::default(), Block::default());
let r_ = u8vec_to_boolvec(&r);
let mut chi = Block::default();
for (j, xj) in r_.into_iter().enumerate() {
let tj = &ts[j * 16..(j + 1) * 16];
let tj: [u8; 16] = tj.try_into().unwrap();
let tj = Block::from(tj);
shared_rand.fill_bytes(chi.as_mut());
x ^= if xj { chi } else { Block::default() };
let (lo, hi) = tj.clmul(&chi);
t = xor_two_blocks(&t, &(lo, hi));
}
send_to(channel, p_to, "KOS_OT_x_t0_t1", &[(x, t.0, t.1)]).await?;
Ok(ts)
}
}
impl<OT: OtSender<Msg = Block> + Malicious> OtReceiver for Receiver<OT> {
type Msg = Block;
async fn init<C: Channel, RNG: CryptoRng + Rng>(
channel: &C,
rng: &mut RNG,
p_to: usize,
shared_rand: &mut ChaCha20Rng,
) -> Result<Self, Error> {
let ot = AlszReceiver::<OT>::init(channel, rng, p_to, shared_rand).await?;
Ok(Self { ot })
}
async fn recv<C: Channel, RNG: CryptoRng + Rng>(
&mut self,
channel: &C,
inputs: &[bool],
rng: &mut RNG,
p_to: usize,
shared_rand: &mut ChaCha20Rng,
) -> Result<Vec<Block>, Error> {
let ts = self
.recv_setup(channel, inputs, rng, p_to, shared_rand)
.await?;
let mut out = Vec::with_capacity(inputs.len());
let y0y1_vec =
recv_vec_from::<(Block, Block)>(channel, p_to, "KOS_OT_send", inputs.len()).await?;
for (j, b) in inputs.iter().enumerate() {
let t = &ts[j * 16..(j + 1) * 16];
let t: [u8; 16] = t.try_into().unwrap();
let (y0, y1) = y0y1_vec[j];
let y = if *b { y1 } else { y0 };
let y = y ^ self
.ot
.hash
.tccr_hash_block(Block::from(j as u128), Block::from(t));
out.push(y);
}
Ok(out)
}
}
impl<OT: OtSender<Msg = Block> + Malicious> CorrelatedReceiver for Receiver<OT> {
async fn recv_correlated<C: Channel, RNG: CryptoRng + Rng>(
&mut self,
channel: &C,
inputs: &[bool],
rng: &mut RNG,
p_to: usize,
shared_rand: &mut ChaCha20Rng,
) -> Result<Vec<Self::Msg>, Error> {
let ts = self
.recv_setup(channel, inputs, rng, p_to, shared_rand)
.await?;
let mut out = Vec::with_capacity(inputs.len());
let ys = recv_vec_from::<Block>(channel, p_to, "KOS_OT_corr", inputs.len()).await?;
for (j, b) in inputs.iter().enumerate() {
let t = &ts[j * 16..(j + 1) * 16];
let t: [u8; 16] = t.try_into().unwrap();
let y = ys[j];
let y = if *b { y } else { Block::default() };
let h = self
.ot
.hash
.tccr_hash_block(Block::from(j as u128), Block::from(t));
out.push(y ^ h);
}
Ok(out)
}
}
impl<OT: OtReceiver<Msg = Block> + Malicious> SemiHonest for Sender<OT> {}
impl<OT: OtSender<Msg = Block> + Malicious> SemiHonest for Receiver<OT> {}
impl<OT: OtReceiver<Msg = Block> + Malicious> Malicious for Sender<OT> {}
impl<OT: OtSender<Msg = Block> + Malicious> Malicious for Receiver<OT> {}
#[inline(always)]
pub(crate) fn xor_two_blocks(x: &(Block, Block), y: &(Block, Block)) -> (Block, Block) {
(x.0 ^ y.0, x.1 ^ y.1)
}