Skip to content

Commit

Permalink
offline-phase: lowgear: inverse_tuples: Generate inverse tuples
Browse files Browse the repository at this point in the history
  • Loading branch information
joeykraut committed Apr 13, 2024
1 parent 1239c59 commit c042a78
Show file tree
Hide file tree
Showing 4 changed files with 141 additions and 50 deletions.
6 changes: 6 additions & 0 deletions offline-phase/src/beaver_source.rs
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,12 @@ impl<C: CurveGroup> ValueMacBatch<C> {
self.inner.iter_mut()
}

/// Split the batch in two at the given index
pub fn split_at(&self, i: usize) -> (Self, Self) {
let (lhs, rhs) = self.inner.split_at(i);
(Self { inner: lhs.to_vec() }, Self { inner: rhs.to_vec() })
}

/// Create a new ValueMacBatch from a batch of values and macs
pub fn from_parts(values: &[Scalar<C>], macs: &[Scalar<C>]) -> Self {
assert_eq!(values.len(), macs.len());
Expand Down
45 changes: 44 additions & 1 deletion offline-phase/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ pub(crate) mod test_helpers {
PARTY0, PARTY1,
};
use futures::Future;
use itertools::Itertools;
use mp_spdz_rs::fhe::{
ciphertext::Ciphertext,
keys::{BGVKeypair, BGVPublicKey},
Expand All @@ -35,7 +36,7 @@ pub(crate) mod test_helpers {
};
use rand::thread_rng;

use crate::lowgear::LowGear;
use crate::{beaver_source::ValueMacBatch, lowgear::LowGear};

/// The curve used for testing in this crate
pub type TestCurve = ark_bn254::G1Projective;
Expand Down Expand Up @@ -78,6 +79,48 @@ pub(crate) mod test_helpers {
key.encrypt(&pt)
}

/// Generate random mock triples for the Beaver trick
#[allow(clippy::type_complexity)]
pub fn generate_triples(
n: usize,
) -> (Vec<Scalar<TestCurve>>, Vec<Scalar<TestCurve>>, Vec<Scalar<TestCurve>>) {
let mut rng = thread_rng();
let a = (0..n).map(|_| Scalar::<TestCurve>::random(&mut rng)).collect_vec();
let b = (0..n).map(|_| Scalar::<TestCurve>::random(&mut rng)).collect_vec();
let c = (0..n).map(|_| Scalar::<TestCurve>::random(&mut rng)).collect_vec();

(a, b, c)
}

/// Generate authenticated secret shares of a given set of values
pub fn generate_authenticated_secret_shares(
values: &[Scalar<TestCurve>],
mac_key: Scalar<TestCurve>,
) -> (ValueMacBatch<TestCurve>, ValueMacBatch<TestCurve>) {
let (shares1, shares2) = generate_secret_shares(values);
let macs = values.iter().map(|value| *value * mac_key).collect_vec();
let (macs1, macs2) = generate_secret_shares(&macs);

(ValueMacBatch::from_parts(&shares1, &macs1), ValueMacBatch::from_parts(&shares2, &macs2))
}

/// Generate secret shares of a set of values
pub fn generate_secret_shares(
values: &[Scalar<TestCurve>],
) -> (Vec<Scalar<TestCurve>>, Vec<Scalar<TestCurve>>) {
let mut rng = thread_rng();
let mut shares1 = Vec::with_capacity(values.len());
let mut shares2 = Vec::with_capacity(values.len());
for value in values {
let share1 = Scalar::<TestCurve>::random(&mut rng);
let share2 = value - share1;
shares1.push(share1);
shares2.push(share2);
}

(shares1, shares2)
}

/// Run a two-party method with a `LowGear` instance setup and in scope
pub async fn mock_lowgear<F, S, T>(f: F) -> (T, T)
where
Expand Down
92 changes: 88 additions & 4 deletions offline-phase/src/lowgear/inverse_tuples.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,105 @@
use ark_ec::CurveGroup;
use ark_mpc::network::MpcNetwork;
use itertools::Itertools;

use crate::error::LowGearError;

use super::LowGear;

impl<C: CurveGroup, N: MpcNetwork<C> + Unpin + Send> LowGear<C, N> {
/// Generate a set of inverse tuples
///
/// 1. Multiply the left and right hand side randomness. We consider one of
/// these random values to be a multiplicative blinder of the other.
/// 2. Open the product and check its MAC
/// 3. Invert the publicly available value and multiply with the shared
/// product to get the inverse of the blinded randomness
pub async fn generate_inverse_tuples(&mut self, n: usize) -> Result<(), LowGearError> {
// We use one triplet per tuple, so we need at least n triples
assert!(self.triples.len() >= n, "not enough triplets for {n} inverse tuples");
// We need `n` triplets to sacrifice for `n` inverse tuples
assert!(self.triples.len() >= n, "Not enough triplets to generate {n} inverse tuples");
let random_values = self.get_authenticated_randomness_vec(2 * n).await?;
let (lhs, rhs) = random_values.split_at(n);

// Split into halves that we will multiply using the Beaver trick
let (random_values1, random_values2) = random_values.into_inner().split_at(n);
// Multiply left and right hand side value
let product = self.beaver_mul(&lhs, &rhs).await?;
let product_open = self.open_and_check_macs(&product).await?;

// Invert the publicly available value and multiply with the shared
// product to get the inverse of the blinded randomness
let inverses = product_open.into_iter().map(|x| x.inverse()).collect_vec();
let shared_inverses = &rhs * inverses.as_slice(); // this leaves `1 / lhs`

// Structure into inverse tuples
let tuples = lhs.into_iter().zip(shared_inverses.into_inner().into_iter()).collect_vec();
self.inverse_tuples = tuples;

Ok(())
}
}

#[cfg(test)]
mod test {
use ark_mpc::{algebra::Scalar, test_helpers::TestCurve, PARTY0};
use itertools::{izip, Itertools};
use rand::thread_rng;

use crate::{
beaver_source::{ValueMac, ValueMacBatch},
test_helpers::{
encrypt_all, generate_authenticated_secret_shares, generate_triples,
mock_lowgear_with_keys,
},
};

/// Tests generating inverse tuples
#[tokio::test]
async fn test_generate_inverse_tuples() {
let mut rng = thread_rng();
const N: usize = 100; // The number of tuples to generate

// Generate a mac key and shares
let mac_key = Scalar::random(&mut rng);
let mac_key1 = Scalar::random(&mut rng);
let mac_key2 = mac_key - mac_key1;

// Setup a set of mock triples
let (a, b, c) = generate_triples(N);
let (a1, a2) = generate_authenticated_secret_shares(&a, mac_key);
let (b1, b2) = generate_authenticated_secret_shares(&b, mac_key);
let (c1, c2) = generate_authenticated_secret_shares(&c, mac_key);

mock_lowgear_with_keys(|mut lowgear| {
// Setup the mac keys
let is_party0 = lowgear.party_id() == PARTY0;
let other_pk = lowgear.other_pk.as_ref().unwrap();

let my_mac_key = if is_party0 { mac_key1 } else { mac_key2 };
let their_mac_key = if is_party0 { mac_key2 } else { mac_key1 };
lowgear.mac_share = my_mac_key;
lowgear.other_mac_enc = Some(encrypt_all(their_mac_key, other_pk, &lowgear.params));

// Setup the triplets
let (my_a, my_b, my_c) = if is_party0 { (&a1, &b1, &c1) } else { (&a2, &b2, &c2) };
lowgear.triples =
izip!(my_a.clone().into_iter(), my_b.clone().into_iter(), my_c.clone().into_iter())
.collect_vec();

async move {
lowgear.generate_inverse_tuples(N).await.unwrap();

// Check the inverse triples
let (a, a_inv): (Vec<ValueMac<TestCurve>>, Vec<ValueMac<TestCurve>>) =
lowgear.inverse_tuples.clone().into_iter().unzip();
let a_inv_open =
lowgear.open_and_check_macs(&ValueMacBatch::new(a_inv)).await.unwrap();
let a_open = lowgear.open_and_check_macs(&ValueMacBatch::new(a)).await.unwrap();

for (a, a_inv) in izip!(a_open, a_inv_open) {
assert_eq!(a * a_inv, Scalar::one());
}
}
})
.await;
}
}
48 changes: 3 additions & 45 deletions offline-phase/src/lowgear/multiplication.rs
Original file line number Diff line number Diff line change
Expand Up @@ -78,53 +78,11 @@ mod tests {
use itertools::{izip, Itertools};
use rand::thread_rng;

use crate::{
beaver_source::ValueMacBatch,
test_helpers::{encrypt_all, mock_lowgear_with_keys, TestCurve},
use crate::test_helpers::{
encrypt_all, generate_authenticated_secret_shares, generate_triples,
mock_lowgear_with_keys, TestCurve,
};

/// Generate random mock triples for the Beaver trick
#[allow(clippy::type_complexity)]
fn generate_triples(
n: usize,
) -> (Vec<Scalar<TestCurve>>, Vec<Scalar<TestCurve>>, Vec<Scalar<TestCurve>>) {
let mut rng = thread_rng();
let a = (0..n).map(|_| Scalar::<TestCurve>::random(&mut rng)).collect_vec();
let b = (0..n).map(|_| Scalar::<TestCurve>::random(&mut rng)).collect_vec();
let c = (0..n).map(|_| Scalar::<TestCurve>::random(&mut rng)).collect_vec();

(a, b, c)
}

/// Generate authenticated secret shares of a given set of values
fn generate_authenticated_secret_shares(
values: &[Scalar<TestCurve>],
mac_key: Scalar<TestCurve>,
) -> (ValueMacBatch<TestCurve>, ValueMacBatch<TestCurve>) {
let (shares1, shares2) = generate_secret_shares(values);
let macs = values.iter().map(|value| *value * mac_key).collect_vec();
let (macs1, macs2) = generate_secret_shares(&macs);

(ValueMacBatch::from_parts(&shares1, &macs1), ValueMacBatch::from_parts(&shares2, &macs2))
}

/// Generate secret shares of a set of values
fn generate_secret_shares(
values: &[Scalar<TestCurve>],
) -> (Vec<Scalar<TestCurve>>, Vec<Scalar<TestCurve>>) {
let mut rng = thread_rng();
let mut shares1 = Vec::with_capacity(values.len());
let mut shares2 = Vec::with_capacity(values.len());
for value in values {
let share1 = Scalar::<TestCurve>::random(&mut rng);
let share2 = value - share1;
shares1.push(share1);
shares2.push(share2);
}

(shares1, shares2)
}

#[tokio::test]
async fn test_beaver_mul() {
const N: usize = 100;
Expand Down

0 comments on commit c042a78

Please sign in to comment.