Skip to content

Commit

Permalink
gadgets: Add prefix-product implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
joeykraut committed Oct 21, 2023
1 parent 06ff8aa commit 8e69e28
Show file tree
Hide file tree
Showing 2 changed files with 103 additions and 0 deletions.
102 changes: 102 additions & 0 deletions src/gadgets.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
//! MPC circuits implemented directly in the library as gadgets for more complex MPC operations
use std::iter;

use ark_ec::CurveGroup;
use itertools::Itertools;

use crate::{algebra::AuthenticatedScalarResult, MpcFabric};

/// A prefix product gadget, computes the prefix products of a vector of values, where
/// for `n` values, the `i`th prefix product is defined as:
/// x0 * x1 * ... * xi
///
/// The method used here is that described in (Section 4.2):
/// https://dl.acm.org/doi/pdf/10.1145/72981.72995
/// I.e. we blind each value in the product with a telescoping product, open the blinded values,
/// construct prefix products, then unblind them as shared values
pub fn prefix_product<C: CurveGroup>(
values: &[AuthenticatedScalarResult<C>],
fabric: &MpcFabric<C>,
) -> Vec<AuthenticatedScalarResult<C>> {
let n = values.len();
let (b_values, b_inv_values) = fabric.random_inverse_pairs(n + 1);

// Blind each value in a telescoping manner, i.e. left multiply by b_inv[i-1]
// and right multiply by b[i]
let partial_blind = AuthenticatedScalarResult::batch_mul(&b_inv_values[..n], values);
let blinded = AuthenticatedScalarResult::batch_mul(&partial_blind, &b_values[1..]);

// Open the blinded values
let blinded_open = AuthenticatedScalarResult::open_authenticated_batch(&blinded)
.into_iter()
.map(|v| v.value)
.collect_vec();

// Construct the prefix products
// Each prefix is b[0] * blinded_open[0] * ... * blinded_open[i] * b_inv[i]

// Each prefix is multiplied by b[0] on the left
let b0_repeat = iter::repeat(b_values[0].clone()).take(n).collect_vec();

// Construct a vector of the prefix products of the blinded values, the left hand multiple of
// each term cancels the right hand blinder of the previous one in a telescoping fashion
let mut prefix = blinded_open[0].clone();
let mut prefixes = vec![prefix.clone()];
for blinded_term in blinded_open[1..].iter() {
prefix = prefix * blinded_term;
prefixes.push(prefix.clone());
}

// Construct the right hand terms, this is the value b_inv[i] for the ith prefix, which cancels
// the right hand blinder of the last term in the prefix product
let right_hand_terms = &b_inv_values[1..];

// Cancel each prefix term's blinders with b[0] on the lhs and b_inv[i] on the rhs
let partial_unblind = AuthenticatedScalarResult::batch_mul_public(&b0_repeat, &prefixes);
AuthenticatedScalarResult::batch_mul(&partial_unblind, right_hand_terms)
}

#[cfg(test)]
mod test {
use futures::future;
use itertools::Itertools;
use rand::thread_rng;

use crate::{
algebra::{AuthenticatedScalarResult, Scalar},
gadgets::prefix_product,
test_helpers::execute_mock_mpc,
PARTY0,
};

/// Test the prefix product implementation
#[tokio::test]
async fn test_prefix_prod() {
const N: usize = 10;
let mut rng = thread_rng();
let values = (0..N).map(|_| Scalar::random(&mut rng)).collect_vec();

let mut expected_res = vec![values[0]];
let mut product = values[0];
for val in values[1..].iter() {
product *= *val;
expected_res.push(product);
}

let (res, _) = execute_mock_mpc(|fabric| {
let values = values.clone();
async move {
let allocated_values = fabric.batch_share_scalar(values, PARTY0 /* sender */);
let res = prefix_product(&allocated_values, &fabric);
let res_open = AuthenticatedScalarResult::open_authenticated_batch(&res);

future::join_all(res_open).await
}
})
.await;

let res = res.into_iter().collect::<Result<Vec<_>, _>>().unwrap();
assert_eq!(res, expected_res)
}
}
1 change: 1 addition & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ pub(crate) mod buffer;
pub mod commitment;
pub mod error;
mod fabric;
pub mod gadgets;
#[cfg(feature = "benchmarks")]
pub use fabric::*;
#[cfg(not(feature = "benchmarks"))]
Expand Down

0 comments on commit 8e69e28

Please sign in to comment.