Skip to content

Commit

Permalink
Merge pull request #985 from andyleiserson/vec25519
Browse files Browse the repository at this point in the history
Vectorized Fp25519 share conversion
  • Loading branch information
andyleiserson authored Apr 4, 2024
2 parents 2029a0f + 5799798 commit daf74b8
Show file tree
Hide file tree
Showing 23 changed files with 1,371 additions and 406 deletions.
5 changes: 3 additions & 2 deletions ipa-core/src/ff/boolean_array.rs
Original file line number Diff line number Diff line change
Expand Up @@ -215,8 +215,9 @@ macro_rules! impl_serializable_trait {
};

($name: ident, $bits: tt, $store: ty, infallible) => {
const _SAFEGUARD: () = assert!(
$bits % 8 == 0,
$crate::const_assert_eq!(
$bits % 8,
0,
"Infallible deserialization is defined for lengths that are multiples of 8 only"
);

Expand Down
5 changes: 5 additions & 0 deletions ipa-core/src/ff/curve_points.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ use typenum::U32;
use crate::{
ff::{ec_prime_field::Fp25519, Serializable},
impl_shared_value_common,
protocol::ipa_prf::PRF_CHUNK,
secret_sharing::{Block, SharedValue, StdArray, Vectorizable},
};

Expand Down Expand Up @@ -42,6 +43,10 @@ impl Vectorizable<1> for RP25519 {
type Array = StdArray<Self, 1>;
}

impl Vectorizable<PRF_CHUNK> for RP25519 {
type Array = StdArray<Self, PRF_CHUNK>;
}

#[derive(thiserror::Error, Debug)]
#[error("{0:?} is not the canonical encoding of a Ristretto point.")]
pub struct NonCanonicalEncoding(CompressedRistretto);
Expand Down
57 changes: 54 additions & 3 deletions ipa-core/src/ff/ec_prime_field.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,16 @@ use generic_array::GenericArray;
use typenum::{U2, U32};

use crate::{
ff::{boolean_array::BA256, Field, Serializable},
ff::{boolean_array::BA256, Expand, Field, Serializable},
impl_shared_value_common,
protocol::prss::FromRandom,
secret_sharing::{Block, FieldVectorizable, SharedValue, StdArray, Vectorizable},
protocol::{
ipa_prf::PRF_CHUNK,
prss::{FromPrss, FromRandom, PrssIndex, SharedRandomness},
},
secret_sharing::{
replicated::{semi_honest::AdditiveShare, ReplicatedSecretSharing},
Block, FieldVectorizable, SharedValue, StdArray, Vectorizable,
},
};

impl Block for Scalar {
Expand Down Expand Up @@ -125,6 +131,20 @@ impl std::ops::MulAssign for Fp25519 {
}
}

impl<const N: usize> Expand for AdditiveShare<Fp25519, N>
where
Fp25519: Vectorizable<N>,
{
type Input = AdditiveShare<Fp25519>;

fn expand(v: &Self::Input) -> Self {
AdditiveShare::new_arr(
<Fp25519 as Vectorizable<N>>::Array::expand(&v.left()),
<Fp25519 as Vectorizable<N>>::Array::expand(&v.right()),
)
}
}

impl From<Scalar> for Fp25519 {
fn from(s: Scalar) -> Self {
Fp25519(s)
Expand Down Expand Up @@ -185,6 +205,14 @@ impl FieldVectorizable<1> for Fp25519 {
type ArrayAlias = StdArray<Self, 1>;
}

impl Vectorizable<PRF_CHUNK> for Fp25519 {
type Array = StdArray<Self, PRF_CHUNK>;
}

impl FieldVectorizable<PRF_CHUNK> for Fp25519 {
type ArrayAlias = StdArray<Self, PRF_CHUNK>;
}

impl Field for Fp25519 {
const NAME: &'static str = "Fp25519";

Expand All @@ -203,6 +231,29 @@ impl FromRandom for Fp25519 {
}
}

macro_rules! impl_share_from_random {
($width:expr) => {
impl FromPrss for AdditiveShare<Fp25519, $width> {
fn from_prss_with<P: SharedRandomness + ?Sized, I: Into<PrssIndex>>(
prss: &P,
index: I,
_params: (),
) -> AdditiveShare<Fp25519, $width> {
let (l_arr, r_arr) = StdArray::from_tuple_iter(
prss.generate_chunks_iter::<_, U2>(index)
.map(|(l_rand, r_rand)| {
(Fp25519::from_random(l_rand), Fp25519::from_random(r_rand))
})
.take($width),
);
AdditiveShare::new_arr(l_arr, r_arr)
}
}
};
}

impl_share_from_random!(PRF_CHUNK);

#[cfg(all(test, unit_test))]
mod test {
use curve25519_dalek::scalar::Scalar;
Expand Down
20 changes: 20 additions & 0 deletions ipa-core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,26 @@ pub(crate) mod test_executor {
}
}

#[macro_export]
macro_rules! const_assert {
($x:expr $(,)?) => {
const _: () = assert!($x, stringify!($x));
};
($x:expr, $msg:expr $(,)?) => {
const _: () = assert!($x, $msg);
};
}

#[macro_export]
macro_rules! const_assert_eq {
($x:expr, $y:expr $(,)?) => {
$crate::const_assert!($x == $y);
};
($x:expr, $y:expr, $msg:expr $(,)?) => {
$crate::const_assert!($x == $y, $msg);
};
}

macro_rules! mutually_incompatible {
($feature1:literal,$feature2:literal) => {
#[cfg(all(feature = $feature1, feature = $feature2))]
Expand Down
2 changes: 1 addition & 1 deletion ipa-core/src/protocol/basics/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ pub use check_zero::check_zero;
pub use if_else::{if_else, select};
pub use mul::{BooleanArrayMul, MultiplyZeroPositions, SecureMul, ZeroPositions};
pub use reshare::Reshare;
pub use reveal::{reveal, Reveal};
pub use reveal::{partial_reveal, reveal, Reveal};
pub use share_known_value::ShareKnownValue;
pub use sum_of_product::SumOfProducts;

Expand Down
18 changes: 16 additions & 2 deletions ipa-core/src/protocol/basics/reveal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -176,8 +176,9 @@ impl<'a, F: ExtendableField> Reveal<UpgradedMaliciousContext<'a, F>, 1> for Mali
}
}

// Workaround for https://github.com/rust-lang/rust/issues/100013. Calling this wrapper function
// instead of `Reveal::reveal` seems to hide the `impl Future` GAT.
// Workaround for https://github.com/rust-lang/rust/issues/100013. Calling these wrapper functions
// instead of the trait methods seems to hide the `impl Future` GAT.

pub fn reveal<'fut, C, S>(
ctx: C,
record_id: RecordId,
Expand All @@ -190,6 +191,19 @@ where
S::reveal(v, ctx, record_id)
}

pub fn partial_reveal<'fut, C, S, const N: usize>(
ctx: C,
record_id: RecordId,
excluded: Role,
v: &'fut S,
) -> impl Future<Output = Result<Option<S::Output>, Error>> + Send + 'fut
where
C: Context + 'fut,
S: Reveal<C, N>,
{
S::partial_reveal(v, ctx, record_id, excluded)
}

#[cfg(all(test, unit_test))]
mod tests {
use std::iter::zip;
Expand Down
34 changes: 28 additions & 6 deletions ipa-core/src/protocol/context/prss.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
//! Metric-aware PRSS decorators
use generic_array::{ArrayLength, GenericArray};
use generic_array::ArrayLength;
use rand_core::{Error, RngCore};

use crate::{
Expand Down Expand Up @@ -35,16 +35,38 @@ impl<'a> InstrumentedIndexedSharedRandomness<'a> {
}

impl SharedRandomness for InstrumentedIndexedSharedRandomness<'_> {
fn generate_arrays<I: Into<PrssIndex>, N: ArrayLength>(
type ChunksIter<'a, Z: ArrayLength> = InstrumentedChunksIter<
'a,
<IndexedSharedRandomness as SharedRandomness>::ChunksIter<'a, Z>,
>
where Self: 'a;

fn generate_chunks_iter<I: Into<PrssIndex>, Z: ArrayLength>(
&self,
index: I,
) -> (GenericArray<u128, N>, GenericArray<u128, N>) {
let step = self.step.as_ref().to_string();
) -> Self::ChunksIter<'_, Z> {
InstrumentedChunksIter {
instrumented: self,
inner: self.inner.generate_chunks_iter(index),
}
}
}

pub struct InstrumentedChunksIter<'a, I: Iterator> {
instrumented: &'a InstrumentedIndexedSharedRandomness<'a>,
inner: I,
}

impl<'a, I: Iterator> Iterator for InstrumentedChunksIter<'a, I> {
type Item = <I as Iterator>::Item;

fn next(&mut self) -> Option<Self::Item> {
let step = self.instrumented.step.as_ref().to_string();
// TODO: what we really want here is a gauge indicating the maximum index used to generate
// PRSS. Gauge infrastructure is not supported yet, `Metrics` struct needs to be able to
// handle gauges
metrics::increment_counter!(INDEXED_PRSS_GENERATED, STEP => step, ROLE => self.role.as_static_str());
self.inner.generate_arrays(index)
metrics::increment_counter!(INDEXED_PRSS_GENERATED, STEP => step, ROLE => self.instrumented.role.as_static_str());
self.inner.next()
}
}

Expand Down
Loading

0 comments on commit daf74b8

Please sign in to comment.