Skip to content

Commit

Permalink
offline-phase: lowgear: triplets: Add MAC checks for triplet gen
Browse files Browse the repository at this point in the history
  • Loading branch information
joeykraut committed Apr 12, 2024
1 parent 7173505 commit ee1b503
Show file tree
Hide file tree
Showing 7 changed files with 142 additions and 42 deletions.
2 changes: 1 addition & 1 deletion mp-spdz-rs/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ pub mod benchmark_helpers {
let mut rng = thread_rng();
let mut pt = Plaintext::new(params);

for i in 0..pt.num_slots() as usize {
for i in 0..pt.num_slots() {
pt.set_element(i, Scalar::random(&mut rng));
}

Expand Down
3 changes: 3 additions & 0 deletions offline-phase/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ use std::{error::Error, fmt::Display};
pub enum LowGearError {
/// An invalid commitment was provided in a commit/reveal phase
InvalidCommitment,
/// An error with the mac on a value
InvalidMac,
/// Error exchanging keys
KeyExchange(String),
/// The lowgear setup params requested before setup
Expand All @@ -22,6 +24,7 @@ impl Display for LowGearError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
LowGearError::InvalidCommitment => write!(f, "Received invalid commitment"),
LowGearError::InvalidMac => write!(f, "Received invalid MAC"),
LowGearError::KeyExchange(e) => write!(f, "Key exchange error: {e}"),
LowGearError::NotSetup => write!(f, "LowGear not setup"),
LowGearError::SacrificeError => write!(f, "Error during sacrifice phase"),
Expand Down
79 changes: 79 additions & 0 deletions offline-phase/src/lowgear/commit_reveal.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
//! Defines a commit/reveal subprotocol for the LowGear offline phase
use ark_ec::CurveGroup;
use ark_mpc::{algebra::Scalar, network::MpcNetwork};
use sha3::{Digest, Sha3_256};

use crate::error::LowGearError;

use super::LowGear;

impl<C: CurveGroup, N: MpcNetwork<C> + Unpin + Send> LowGear<C, N> {
/// Open a single value without committing first
///
/// Adds the counterparty's value to the input to recover the underlying
/// value
pub async fn open_single(&mut self, my_value: Scalar<C>) -> Result<Scalar<C>, LowGearError> {
Ok(self.open_batch(&[my_value]).await?.pop().expect("Expected a single value"))
}

/// Open a batch of values without committing first
///
/// Adds the counterparty's values to the input to recover the underlying
/// values
pub async fn open_batch(
&mut self,
values: &[Scalar<C>],
) -> Result<Vec<Scalar<C>>, LowGearError> {
// Send the values
self.send_network_payload(values.to_vec()).await?;
let their_values: Vec<Scalar<C>> = self.receive_network_payload().await?;
let res = their_values.iter().zip(values.iter()).map(|(a, b)| a + b).collect();

Ok(res)
}

/// Commit and reveal a single value
pub async fn commit_reveal_single(
&mut self,
value: Scalar<C>,
) -> Result<Scalar<C>, LowGearError> {
Ok(self.commit_reveal(&[value]).await?.pop().expect("Expected a single value"))
}

/// Commit and reveal a set of values
///
/// Returns the counterparty's revealed values
pub async fn commit_reveal(
&mut self,
values: &[Scalar<C>],
) -> Result<Vec<Scalar<C>>, LowGearError> {
// Hash the values
let my_comm = Self::commit_scalars(values);
self.send_network_payload(my_comm).await?;
let their_comm: Scalar<C> = self.receive_network_payload().await?;

// Reveal the values
self.send_network_payload(values.to_vec()).await?;
let their_values: Vec<Scalar<C>> = self.receive_network_payload().await?;

// Check the counterparty's commitment
let expected_comm = Self::commit_scalars(&their_values);
if expected_comm != their_comm {
return Err(LowGearError::InvalidCommitment);
}

Ok(their_values)
}

/// Hash commit to a set of random values
pub(crate) fn commit_scalars(values: &[Scalar<C>]) -> Scalar<C> {
let mut hasher = Sha3_256::new();
for value in values.iter() {
hasher.update(value.to_bytes_be());
}
let hash_output = hasher.finalize();

Scalar::<C>::from_be_bytes_mod_order(&hash_output)
}
}
49 changes: 49 additions & 0 deletions offline-phase/src/lowgear/mac_check.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
//! Subprotocol definitions for checking MACs on opened values
use ark_ec::CurveGroup;
use ark_mpc::{algebra::Scalar, network::MpcNetwork};

use crate::{beaver_source::ValueMacBatch, error::LowGearError};

use super::LowGear;

impl<C: CurveGroup, N: MpcNetwork<C> + Unpin + Send> LowGear<C, N> {
/// Open a batch of values and check their MACs
///
/// Returns the opened values
pub async fn open_and_check_macs(
&mut self,
x: ValueMacBatch<C>,
) -> Result<Vec<Scalar<C>>, LowGearError> {
// Open and reconstruct
let recovered_values = self.open_batch(&x.values()).await?;

// Take a linear combination of the values and their macs
let random_values = self.get_shared_randomness_vec(recovered_values.len()).await?;
let combined_value = Self::linear_combination(&recovered_values, &random_values);
let combined_mac = Self::linear_combination(&x.macs(), &random_values);

// Check the MAC before returning
self.check_mac(combined_value, combined_mac).await?;
Ok(recovered_values)
}

/// Check the MAC of a given opening
async fn check_mac(&mut self, x: Scalar<C>, mac: Scalar<C>) -> Result<(), LowGearError> {
// Compute the mac check expression, then commit/open it
let mac_check = mac - self.mac_share * x;
let their_mac_check = self.commit_reveal_single(mac_check).await?;

if their_mac_check + mac_check != Scalar::zero() {
return Err(LowGearError::InvalidMac);
}

Ok(())
}

/// A helper to compute the linear combination of a batch of values
fn linear_combination(values: &[Scalar<C>], coeffs: &[Scalar<C>]) -> Scalar<C> {
assert_eq!(values.len(), coeffs.len());
values.iter().zip(coeffs.iter()).map(|(v, c)| v * c).sum()
}
}
3 changes: 2 additions & 1 deletion offline-phase/src/lowgear/mod.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
//! Defines the lowgear protocol for generating triples, inverse pairs, mac
//! keys, authenticating inputs, etc
pub mod commit_reveal;
pub mod mac_check;
pub mod setup;
pub mod shared_random;
pub mod triplets;

use ark_ec::CurveGroup;
use ark_mpc::{
algebra::Scalar,
beaver::PartyIDBeaverSource,
network::{MpcNetwork, NetworkOutbound, NetworkPayload, PartyId},
};
use futures::{SinkExt, StreamExt};
Expand Down
26 changes: 1 addition & 25 deletions offline-phase/src/lowgear/shared_random.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ use ark_ec::CurveGroup;
use ark_mpc::{algebra::Scalar, network::MpcNetwork};
use itertools::Itertools;
use rand::rngs::OsRng;
use sha3::{Digest, Sha3_256};

use crate::error::LowGearError;

Expand All @@ -30,19 +29,7 @@ impl<C: CurveGroup, N: MpcNetwork<C> + Unpin + Send> LowGear<C, N> {
// Generate local random values
let mut rng = OsRng;
let my_shares = (0..n).map(|_| Scalar::random(&mut rng)).collect_vec();

let my_comm = Self::commit_randomness(&my_shares);
self.send_network_payload(my_comm).await?;
let their_comm: Scalar<C> = self.receive_network_payload().await?;

self.send_network_payload(my_shares.clone()).await?;
let their_shares: Vec<Scalar<C>> = self.receive_network_payload().await?;

// Verify commitments
let expected_comm = Self::commit_randomness(&their_shares);
if expected_comm != their_comm {
return Err(LowGearError::InvalidCommitment);
}
let their_shares = self.commit_reveal(&my_shares).await?;

let final_shares = my_shares
.iter()
Expand All @@ -51,17 +38,6 @@ impl<C: CurveGroup, N: MpcNetwork<C> + Unpin + Send> LowGear<C, N> {
.collect_vec();
Ok(final_shares)
}

/// Hash commit to a set of random values
fn commit_randomness(values: &[Scalar<C>]) -> Scalar<C> {
let mut hasher = Sha3_256::new();
for value in values.iter() {
hasher.update(value.to_bytes_be());
}
let hash_output = hasher.finalize();

Scalar::<C>::from_be_bytes_mod_order(&hash_output)
}
}

#[cfg(test)]
Expand Down
22 changes: 7 additions & 15 deletions offline-phase/src/lowgear/triplets.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
use ark_ec::CurveGroup;
use ark_mpc::{algebra::Scalar, network::MpcNetwork};
use itertools::{izip, Itertools};
use itertools::izip;
use mp_spdz_rs::fhe::{
ciphertext::{CiphertextPoK, CiphertextVector},
plaintext::{Plaintext, PlaintextVector},
Expand Down Expand Up @@ -126,27 +126,19 @@ impl<C: CurveGroup, N: MpcNetwork<C> + Unpin> LowGear<C, N> {
let r = self.get_shared_randomness().await?;

// Open r * b - b'
let rho = &(b * r) - b_prime;
self.send_network_payload(rho.values()).await?;
let other_rho: Vec<Scalar<C>> = self.receive_network_payload().await?;

// TODO: mac check here
let my_rho = &(b * r) - b_prime;
let rho = self.open_and_check_macs(my_rho).await?;

// Compute the expected rhs of the sacrifice identity
let recovered_rho =
other_rho.iter().zip(rho.iter()).map(|(a, b)| a + b.value()).collect_vec();
let rho_a = a * recovered_rho.as_slice();
let rho_a = a * rho.as_slice();
let c_diff = &(c * r) - c_prime;
let tau = &c_diff - &rho_a;
let my_tau = &c_diff - &rho_a;

// Open tau and check that all values are zero
self.send_network_payload(tau.values()).await?;
let other_tau: Vec<Scalar<C>> = self.receive_network_payload().await?;
let mut recovered_tau = other_tau.iter().zip(tau.iter()).map(|(a, b)| a + b.value());
let tau = self.open_and_check_macs(my_tau).await?;

// TODO: Mac check
let zero = Scalar::zero();
if !recovered_tau.all(|s| s == zero) {
if !tau.into_iter().all(|s| s == zero) {
return Err(LowGearError::SacrificeError);
}

Expand Down

0 comments on commit ee1b503

Please sign in to comment.