Skip to content

Commit

Permalink
offline-phase: lowgear: shared-random: Generate shared random values
Browse files Browse the repository at this point in the history
These shared random values are used to construct shared bits and inverse
tuples
  • Loading branch information
joeykraut committed Apr 13, 2024
1 parent ee1b503 commit 0c0387d
Show file tree
Hide file tree
Showing 7 changed files with 116 additions and 7 deletions.
6 changes: 3 additions & 3 deletions mp-spdz-rs/src/fhe/params.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,13 +57,13 @@ impl<C: CurveGroup> BGVParams<C> {
}

/// Get the number of plaintext slots the given parameters support
pub fn plaintext_slots(&self) -> u32 {
self.as_ref().n_plaintext_slots()
pub fn plaintext_slots(&self) -> usize {
self.as_ref().n_plaintext_slots() as usize
}

/// Get the number of ciphertexts that may be proven together
pub fn ciphertext_pok_batch_size(&self) -> usize {
(self.plaintext_slots() as usize) * (DEFAULT_DROWN_SEC as usize)
self.plaintext_slots() * (DEFAULT_DROWN_SEC as usize)
}
}

Expand Down
39 changes: 39 additions & 0 deletions mp-spdz-rs/src/fhe/plaintext.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,16 @@ impl<C: CurveGroup> Plaintext<C> {
self.inner.num_slots() as usize
}

/// Get a vector of scalars from the plaintext slots
pub fn to_scalars(&self) -> Vec<Scalar<C>> {
let mut scalars = Vec::with_capacity(self.num_slots());
for i in 0..self.num_slots() {
scalars.push(self.get_element(i));
}

scalars
}

/// Set each slot with the given value
pub fn set_all<T: Into<Scalar<C>>>(&mut self, value: T) {
let val_bigint = scalar_to_ffi_bigint(value.into());
Expand Down Expand Up @@ -155,6 +165,35 @@ impl<C: CurveGroup> PlaintextVector<C> {
Self { inner, _phantom: PhantomData }
}

/// Create a plaintext vector from a vector of scalars, packing them into
/// slots
pub fn from_scalars(scalars: &[Scalar<C>], params: &BGVParams<C>) -> Self {
let n_plaintexts = scalars.len() / params.plaintext_slots() + 1;
let mut pt = Self::new(n_plaintexts, params);

for chunk in scalars.chunks(params.plaintext_slots()) {
let mut plaintext = Plaintext::new(params);
for (i, scalar) in chunk.iter().enumerate() {
plaintext.set_element(i, *scalar);
}

pt.push(&plaintext);
}

pt
}

/// Create a vector of scalars from the plaintext vector
pub fn to_scalars(&self) -> Vec<Scalar<C>> {
let mut scalars = Vec::with_capacity(self.total_slots());
for i in 0..self.len() {
let plaintext = self.get(i);
scalars.extend(plaintext.to_scalars());
}

scalars
}

/// Create a new empty `PlaintextVector`
pub fn empty() -> Self {
Self { inner: ffi::new_empty_plaintext_vector(), _phantom: PhantomData }
Expand Down
23 changes: 23 additions & 0 deletions offline-phase/src/lowgear/inverse_tuples.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
//! Defines the subprotocol for generating tuples (a, a^{-1}) for a random value
//! a
use ark_ec::CurveGroup;
use ark_mpc::network::MpcNetwork;

use crate::error::LowGearError;

use super::LowGear;

impl<C: CurveGroup, N: MpcNetwork<C> + Unpin + Send> LowGear<C, N> {
/// Generate a set of inverse tuples
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");
let random_values = self.get_authenticated_randomness_vec(2 * n).await?;

// Split into halves that we will multiply using the Beaver trick
let (random_values1, random_values2) = random_values.split_at(n);

Ok(())
}
}
5 changes: 5 additions & 0 deletions offline-phase/src/lowgear/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@
//! keys, authenticating inputs, etc
pub mod commit_reveal;
pub mod inverse_tuples;
pub mod mac_check;
pub mod multiplication;
pub mod setup;
pub mod shared_random;
pub mod triplets;
Expand Down Expand Up @@ -43,6 +45,8 @@ pub struct LowGear<C: CurveGroup, N: MpcNetwork<C>> {
pub other_mac_enc: Option<Ciphertext<C>>,
/// The Beaver triples generated during the offline phase
pub triples: Vec<(ValueMac<C>, ValueMac<C>, ValueMac<C>)>,
/// The inverse tuples generated during the offline phase
pub inverse_tuples: Vec<(ValueMac<C>, ValueMac<C>)>,
/// A reference to the underlying network connection
pub network: N,
}
Expand All @@ -63,6 +67,7 @@ impl<C: CurveGroup, N: MpcNetwork<C> + Unpin> LowGear<C, N> {
other_pk: None,
other_mac_enc: None,
triples: Default::default(),
inverse_tuples: Default::default(),
network,
}
}
Expand Down
1 change: 1 addition & 0 deletions offline-phase/src/lowgear/multiplication.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
//! Multiplication sub-protocol using the Beaver trick
45 changes: 43 additions & 2 deletions offline-phase/src/lowgear/shared_random.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,10 @@
use ark_ec::CurveGroup;
use ark_mpc::{algebra::Scalar, network::MpcNetwork};
use itertools::Itertools;
use mp_spdz_rs::fhe::plaintext::PlaintextVector;
use rand::rngs::OsRng;

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

use super::LowGear;

Expand Down Expand Up @@ -38,14 +39,39 @@ impl<C: CurveGroup, N: MpcNetwork<C> + Unpin + Send> LowGear<C, N> {
.collect_vec();
Ok(final_shares)
}

/// Generate secret shared, authenticated random values
pub async fn get_authenticated_randomness_vec(
&mut self,
n: usize,
) -> Result<Vec<ValueMac<C>>, LowGearError> {
// Each party generates shares locally with the represented value implicitly
// defined as the sum of the shares
let mut rng = OsRng;
let my_shares = (0..n).map(|_| Scalar::<C>::random(&mut rng)).collect_vec();

let pt_vec = PlaintextVector::from_scalars(&my_shares, &self.params);
let mut macs = self.authenticate_vec(&pt_vec).await?.to_scalars();

// Recombine into ValueMac pairs
macs.truncate(n);
let res =
my_shares.into_iter().zip(macs.into_iter()).map(|(v, m)| ValueMac::new(v, m)).collect();

Ok(res)
}
}

#[cfg(test)]
mod tests {
use crate::test_helpers::mock_lowgear;
use crate::{
beaver_source::ValueMacBatch,
test_helpers::{mock_lowgear, mock_lowgear_with_keys},
};

use super::*;

/// Tests creating a shared vector of public randomness values
#[tokio::test]
async fn test_get_shared_randomness_vec() {
mock_lowgear(|mut lowgear| async move {
Expand All @@ -62,4 +88,19 @@ mod tests {
})
.await;
}

/// Tests creating a shared vector of authenticated random values
#[tokio::test]
async fn test_get_authenticated_randomness_vec() {
const N: usize = 100;

mock_lowgear_with_keys(|mut lowgear| async move {
let shares = lowgear.get_authenticated_randomness_vec(N).await.unwrap();
assert_eq!(shares.len(), N);

// Check the macs on the shares
lowgear.open_and_check_macs(ValueMacBatch::new(shares)).await.unwrap();
})
.await;
}
}
4 changes: 2 additions & 2 deletions offline-phase/src/lowgear/triplets.rs
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ impl<C: CurveGroup, N: MpcNetwork<C> + Unpin> LowGear<C, N> {
}

/// Authenticate a plaintext vector with the counterparty
async fn authenticate_vec(
pub async fn authenticate_vec(
&mut self,
a: &PlaintextVector<C>,
) -> Result<PlaintextVector<C>, LowGearError> {
Expand Down Expand Up @@ -416,7 +416,7 @@ mod test {
// The number of plaintext vectors to test
mock_lowgear_with_keys(|mut lowgear| async move {
// Generate values for the triplets
let n_slots = lowgear.params.plaintext_slots() as usize;
let n_slots = lowgear.params.plaintext_slots();
let my_a = random_scalars(n_slots);
let my_b = random_scalars(n_slots);
let my_c = random_scalars(n_slots);
Expand Down

0 comments on commit 0c0387d

Please sign in to comment.