From 01e30eefe96a4130ea4ace915b36df3b609762cc Mon Sep 17 00:00:00 2001 From: themighty1 Date: Fri, 29 Apr 2022 06:31:29 +0300 Subject: [PATCH] comments --- mpc-core/src/block.rs | 10 ++++++++++ mpc-core/src/ot/base/mod.rs | 3 +++ mpc-core/src/ot/base/receiver.rs | 7 +++++++ mpc-core/src/ot/base/sender.rs | 5 +++++ mpc-core/src/ot/extension/mod.rs | 9 +++++++++ mpc-core/src/ot/extension/receiver.rs | 15 +++++++++++++++ mpc-core/src/ot/extension/sender.rs | 14 ++++++++++++++ 7 files changed, 63 insertions(+) diff --git a/mpc-core/src/block.rs b/mpc-core/src/block.rs index 7568b42bc..91545613a 100644 --- a/mpc-core/src/block.rs +++ b/mpc-core/src/block.rs @@ -32,6 +32,16 @@ impl Block { } #[inline] + // OT extension Sender must break correlation between his 2 masks before + // using them in 1-out-of-2 Oblivious Transfer. Every pair of masks has + // a constant correlation: their XOR equals a delta (delta is choice bits + // in base OT). + // If masks were used as-is in OT, Receiver could infer bits of delta and break + // the OT security. + // For performance reasons, we don't use a hash but a construction which has + // tweakable correlation robustness (tcr). The GKWY20 paper shows (in + // Section 7.4) how to achieve tcr using a fixed-key cipher C instead of a + // hash, i.e. instead of Hash(x, i) we must do C(C(x) xor i) xor C(x). pub fn hash_tweak + BlockEncrypt>( &self, c: &mut C, diff --git a/mpc-core/src/ot/base/mod.rs b/mpc-core/src/ot/base/mod.rs index 555795407..07408df02 100644 --- a/mpc-core/src/ot/base/mod.rs +++ b/mpc-core/src/ot/base/mod.rs @@ -1,3 +1,6 @@ +//! this crate implements the CO15 Oblivious Transfer protocol from +//! [ref1] https://eprint.iacr.org/2015/267.pdf (see Figure 1) + pub mod errors; pub mod receiver; pub mod sender; diff --git a/mpc-core/src/ot/base/receiver.rs b/mpc-core/src/ot/base/receiver.rs index fafea267f..8075a6ecc 100644 --- a/mpc-core/src/ot/base/receiver.rs +++ b/mpc-core/src/ot/base/receiver.rs @@ -66,6 +66,7 @@ impl ReceiveCore for ReceiverCore { if choice.len() != self.count { return Err(ReceiverCoreError::InvalidChoiceLength); } + // point_table is A in [ref1] let point_table = RistrettoBasepointTable::create(&sender_setup.public_key); let zero = &Scalar::zero() * &point_table; let one = &Scalar::one() * &point_table; @@ -73,10 +74,14 @@ impl ReceiveCore for ReceiverCore { .iter() .enumerate() .map(|(i, b)| { + // x is b in [ref1] let x = Scalar::random(&mut self.rng); let c = if *b { one } else { zero }; + // k is B in [ref1] let k = c + &x * &RISTRETTO_BASEPOINT_TABLE; + // h is k_r in [ref1] == hash(A^b) let h = Block::hash_point(&(&x * &point_table), i as u32); + // we send the k values to the Sender and keep the h values (k, h) }) .unzip(); @@ -101,7 +106,9 @@ impl ReceiveCore for ReceiverCore { .zip(hashes) .zip(payload.encrypted_values.iter()) .map(|((c, h), v)| { + // select an encrypted value based on the choice bit let b = if *c { v[1] } else { v[0] }; + // decrypt it with the corresponding key (the key is a hash) *h ^ b }) .collect(); diff --git a/mpc-core/src/ot/base/sender.rs b/mpc-core/src/ot/base/sender.rs index 74c907650..76315f42d 100644 --- a/mpc-core/src/ot/base/sender.rs +++ b/mpc-core/src/ot/base/sender.rs @@ -18,7 +18,9 @@ pub enum State { pub struct SenderCore { rng: R, count: usize, + // private_key is random "a" in [ref1] private_key: Option, + // public_key is A == g^a in [ref1] public_key: Option, state: State, } @@ -84,12 +86,15 @@ impl SendCore for SenderCore { } let private_key = self.private_key.unwrap(); let ninputs = inputs.len(); + // ys is A^a in [ref1] let ys = private_key * self.public_key.unwrap(); let mut encrypted_values: Vec<[Block; 2]> = Vec::with_capacity(ninputs); for (i, (input, receiver_key)) in inputs.iter().zip(receiver_setup.keys).enumerate() { + // yr is B^a in [ref1] let yr = private_key * receiver_key; let k0 = Block::hash_point(&yr, i as u32); + // yr - ys == (B/A)^a in [ref1] let k1 = Block::hash_point(&(yr - ys), i as u32); encrypted_values.push([k0 ^ input[0], k1 ^ input[1]]); } diff --git a/mpc-core/src/ot/extension/mod.rs b/mpc-core/src/ot/extension/mod.rs index 247968e12..a9c89dba3 100644 --- a/mpc-core/src/ot/extension/mod.rs +++ b/mpc-core/src/ot/extension/mod.rs @@ -1,3 +1,5 @@ +//! This crate implements the KOS15 Oblivious Transfer extension protocol. + pub mod errors; pub mod receiver; pub mod sender; @@ -20,6 +22,7 @@ const K: usize = 40; pub trait ExtSendCore { fn state(&self) -> sender::State; + // fn base_setup( &mut self, base_sender_setup: BaseSenderSetup, @@ -42,6 +45,8 @@ pub trait ExtRandomSendCore: ExtSendCore { ExtSendCore::state(self) } + // Sender in OT extension acts as Receiver in base OT and receives a setup + // message from base OT Sender and responds with its own setup message. fn base_setup( &mut self, base_sender_setup: BaseSenderSetup, @@ -74,6 +79,8 @@ pub trait ExtRandomSendCore: ExtSendCore { pub trait ExtReceiveCore { fn state(&self) -> &receiver::State; + // Receiver in OT extension acts as Sender in base OT and sends the first + // base OT setup message. fn base_setup(&mut self) -> Result; fn base_send( @@ -96,6 +103,8 @@ pub trait ExtRandomReceiveCore: ExtReceiveCore { ExtReceiveCore::state(self) } + // Receiver in OT extension acts as Sender in base OT and sends the first + // base OT setup message. fn base_setup(&mut self) -> Result { ExtReceiveCore::base_setup(self) } diff --git a/mpc-core/src/ot/extension/receiver.rs b/mpc-core/src/ot/extension/receiver.rs index b504c652b..3847bcbe2 100644 --- a/mpc-core/src/ot/extension/receiver.rs +++ b/mpc-core/src/ot/extension/receiver.rs @@ -35,6 +35,8 @@ pub struct ExtReceiverCore>, rngs: Option>, table: Option>>, @@ -174,12 +176,19 @@ where .as_mut() .ok_or(ExtReceiverCoreError::BaseOTNotSetup)?; + // The amount of choice bits must be equal to the amount of OT instances + // needed plus extra 256 instances which will be sacrificed as part of the + // KOS protocol. let r = utils::boolvec_to_u8vec(choice); let m = choice.len(); let ncols = if m % 8 != 0 { m + (8 - m % 8) } else { m }; let mut ts: Vec> = vec![vec![0u8; ncols / 8]; BASE_COUNT]; let mut gs: Vec> = vec![vec![0u8; ncols / 8]; BASE_COUNT]; + // Note that for each row j of the matrix gs which will be sent to Sender, + // Sender knows either rng[0] or rng[1] depending on his choice bit during + // base OT. If he knows rng[1] then he will XOR it with gs[j] and get a + // row ( ts[j] ^ r ). But if he knows rng[0] then his row will be ts[j]. for j in 0..BASE_COUNT { rngs[j][0].fill_bytes(&mut ts[j]); rngs[j][1].fill_bytes(&mut gs[j]); @@ -190,6 +199,12 @@ where .map(|((g, t), r)| *g ^ *t ^ *r) .collect(); } + + // After Sender transposes his matrix, he will have a table S such that + // for each row j: + // self.table[j] = S[j], if our choice bit was 0 or + // self.table[j] = S[j] ^ delta, if our choice bit was 1 + // (note that delta is known only to Sender) self.table = Some(utils::transpose(&ts)); self.state = State::Setup(ChoiceState { choice: Vec::from(choice), diff --git a/mpc-core/src/ot/extension/sender.rs b/mpc-core/src/ot/extension/sender.rs index 77916fd9f..6fe8285cb 100644 --- a/mpc-core/src/ot/extension/sender.rs +++ b/mpc-core/src/ot/extension/sender.rs @@ -30,9 +30,17 @@ pub struct ExtSenderCore> { state: State, count: usize, sent: usize, + // choice bits for the base OT protocol base_choice: Vec, + // seeds are the result of running base OT setup. They are used to seed the + // RNGs. seeds: Option>, rngs: Option>, + // table's rows are such that for each row j: + // table[j] = R[j], if Receiver's choice bit was 0 or + // table[j] = R[j] ^ base_choice, if Receiver's choice bit was 1 + // (where R is the table which Receiver has. Note that base_choice is known + // only to us). table: Option>>, } @@ -41,6 +49,9 @@ pub struct ExtSenderPayload { pub encrypted_values: Vec<[Block; 2]>, } +// Having 2 messages that Receiver chooses from, we encrypt each message with +// a unique mask (i.e. XOR the message them with the mask). Receiver who knows +// only 1 mask will be able to decrypt only 1 message out of 2. fn encrypt_values + BlockEncrypt>( cipher: &mut C, inputs: &[[Block; 2]], @@ -51,6 +62,9 @@ fn encrypt_values + BlockEncrypt>( let mut encrypted_values: Vec<[Block; 2]> = Vec::with_capacity(table.len()); let base_choice: [u8; 16] = utils::boolvec_to_u8vec(base_choice).try_into().unwrap(); let delta = Block::from(base_choice); + // If Receiver used *random* choice bits during OT extension setup, he will now + // instruct us to de-randomize, so that the value corresponding to his *actual* + // choice bit would be masked by that mask which Receiver knows. let flip = flip.unwrap_or(vec![false; inputs.len()]); for (j, (input, flip)) in inputs.iter().zip(flip).enumerate() { let q: [u8; 16] = table[j].clone().try_into().unwrap();