From cd46b4488d53de3dfabf8eb8e4d8d30515ed5eb6 Mon Sep 17 00:00:00 2001 From: Daniel Masny Date: Mon, 2 Oct 2023 09:44:30 -0700 Subject: [PATCH 01/76] added 25519 prime field --- Cargo.toml | 1 + src/ff/ec_prime_field.rs | 194 +++++++++++++++++++++++++++++++++++++++ src/ff/mod.rs | 1 + 3 files changed, 196 insertions(+) create mode 100644 src/ff/ec_prime_field.rs diff --git a/Cargo.toml b/Cargo.toml index e264d503f..11e15fdc7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -55,6 +55,7 @@ clap = { version = "4.3.2", optional = true, features = ["derive"] } comfy-table = { version = "7.0", optional = true } config = "0.13.2" criterion = { version = "0.5.1", optional = true, default-features = false, features = ["async_tokio", "plotters", "html_reports"] } +curve25519-dalek = "4.1.1" dashmap = "5.4" dhat = "0.3.2" embed-doc-image = "0.1.4" diff --git a/src/ff/ec_prime_field.rs b/src/ff/ec_prime_field.rs new file mode 100644 index 000000000..c87dbfa94 --- /dev/null +++ b/src/ff/ec_prime_field.rs @@ -0,0 +1,194 @@ +use generic_array::GenericArray; +use curve25519_dalek::scalar::Scalar; +use rand_core::RngCore; +use typenum::U32; + +use crate::{ + ff::Serializable, + secret_sharing::{Block, SharedValue}, +}; + +impl Block for Scalar { + type Size = U32; +} + +#[derive(Clone, Copy, PartialEq, Debug)] +pub struct Fp25519(::Storage); + +//how to add const ONE: Self = Self(Scalar::ONE); within the struct, do I need to do it via a trait? + + +impl SharedValue for Fp25519 { + type Storage = Scalar; + const BITS: u32 = 256; + const ZERO: Self = Self(Scalar::ZERO); +} + +impl Serializable for Fp25519 { + type Size = <::Storage as Block>::Size; + + fn serialize(&self, buf: &mut GenericArray) { + let raw = &self.0.as_bytes()[..buf.len()] ; + buf.copy_from_slice(raw); + } + + fn deserialize(buf: &GenericArray) -> Self { + let mut buf_to = [0u8; 32]; + buf_to[..buf.len()].copy_from_slice(buf); + + Fp25519(Scalar::from_bytes_mod_order(buf_to)) + } +} + + +impl rand::distributions::Distribution for rand::distributions::Standard { + fn sample(&self, rng: &mut R) -> Fp25519 { + //Fp25519(Scalar::random(rng: &mut R)) + let mut scalar_bytes = [0u8; 64]; + rng.fill_bytes(&mut scalar_bytes); + Fp25519(Scalar::from_bytes_mod_order_wide(&scalar_bytes)) + } +} + + +impl std::ops::Add for Fp25519 { +type Output = Self; + +fn add(self, rhs: Self) -> Self::Output { + Self(self.0+rhs.0) +} +} + +impl std::ops::AddAssign for Fp25519 { +#[allow(clippy::assign_op_pattern)] +fn add_assign(&mut self, rhs: Self) { + *self = *self + rhs; +} +} + +impl std::ops::Neg for Fp25519 { +type Output = Self; + +fn neg(self) -> Self::Output { + Self(self.0.neg()) +} +} + +impl std::ops::Sub for Fp25519 { +type Output = Self; + +fn sub(self, rhs: Self) -> Self::Output { + Self(self.0- rhs.0) +} +} + +impl std::ops::SubAssign for Fp25519 { +#[allow(clippy::assign_op_pattern)] +fn sub_assign(&mut self, rhs: Self) { + *self = *self - rhs; +} +} + +impl std::ops::Mul for Fp25519 { +type Output = Self; + +fn mul(self, rhs: Self) -> Self::Output { + Self(self.0 * rhs.0) +} +} + +impl std::ops::MulAssign for Fp25519 { +#[allow(clippy::assign_op_pattern)] +fn mul_assign(&mut self, rhs: Self) { + *self = *self * rhs; +} +} + +//must not use with ZERO +impl Fp25519 { + pub fn invert(&self) -> Fp25519 { + Fp25519(self.0.invert()) + } +} + +#[cfg(all(test, unit_test))] +mod test { + use generic_array::GenericArray; + use crate::ff::ec_prime_field::Fp25519; + use crate::ff::Serializable; + use typenum::U32; + use curve25519_dalek::scalar::Scalar; + use rand::{thread_rng, Rng}; + use crate::secret_sharing::SharedValue; + + #[test] + fn serde_25519() { + let input:[u8;32] = [ + 0x01, 0xff,0x00, 0xff,0x00, 0xff,0x00, 0xff, + 0x00, 0xff,0x00, 0xff,0x00, 0xff,0x00, 0xff, + 0x00, 0xff,0x00, 0xff,0x00, 0xff,0x00, 0xff, + 0x00, 0xff,0x00, 0xff,0x00, 0x00,0x00, 0x00 + ]; + let mut output: GenericArray = [0u8;32].into(); + let a = Fp25519::deserialize(&input.into()); + assert_eq!(a.0.as_bytes()[..32],input); + a.serialize(&mut output); + assert_eq!(a.0.as_bytes()[..32],output.as_slice()[..32]); + assert_eq!(input,output.as_slice()[..32]); + } + + // These are just simple arithmetic tests since arithmetics are checked by curve25519_dalek + #[test] + fn simple_arithmetics_25519() { + let a = Fp25519(Scalar::from_bytes_mod_order([ + 0x02, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00, + 0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00, + 0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00, + 0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00 + ])); + let b = Fp25519(Scalar::from_bytes_mod_order([ + 0x03, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00, + 0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00, + 0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00, + 0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00 + ])); + let c = Fp25519(Scalar::from_bytes_mod_order([ + 0x01, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00, + 0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00, + 0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00, + 0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00 + ])); + let d = Fp25519(Scalar::from_bytes_mod_order([ + 0x05, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00, + 0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00, + 0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00, + 0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00 + ])); + let e = Fp25519(Scalar::from_bytes_mod_order([ + 0x06, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00, + 0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00, + 0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00, + 0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00 + ])); + let cc = b-a; + let dc = a+b; + let ec = a*b; + assert_eq!(cc,c); + assert_eq!(dc,d); + assert_eq!(ec,e); + } + + #[test] + fn simple_random_25519(){ + let mut rng = thread_rng(); + assert_ne!(Fp25519::ZERO,rng.gen::()); + } + + #[test] + fn invert_25519(){ + let mut rng = thread_rng(); + let a=rng.gen::(); + let ia=a.invert(); + assert_eq!(a*ia, Fp25519(Scalar::ONE)); + } +} \ No newline at end of file diff --git a/src/ff/mod.rs b/src/ff/mod.rs index 453876175..2afd4a602 100644 --- a/src/ff/mod.rs +++ b/src/ff/mod.rs @@ -5,6 +5,7 @@ mod field; mod galois_field; mod prime_field; +mod ec_prime_field; use std::ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign}; From e59b214c7b7e7e33485eeaa565bbd944f35c719b Mon Sep 17 00:00:00 2001 From: Daniel Masny Date: Mon, 2 Oct 2023 11:49:49 -0700 Subject: [PATCH 02/76] add files, make ec pub --- src/ff/mod.rs | 2 +- src/protocol/mod.rs | 1 + src/protocol/prf_eval/eval.rs | 0 src/protocol/prf_eval/keygen.rs | 0 src/protocol/prf_eval/mod.rs | 0 5 files changed, 2 insertions(+), 1 deletion(-) create mode 100644 src/protocol/prf_eval/eval.rs create mode 100644 src/protocol/prf_eval/keygen.rs create mode 100644 src/protocol/prf_eval/mod.rs diff --git a/src/ff/mod.rs b/src/ff/mod.rs index b89208c43..c4d287e7a 100644 --- a/src/ff/mod.rs +++ b/src/ff/mod.rs @@ -5,7 +5,7 @@ mod field; mod galois_field; mod prime_field; -mod ec_prime_field; +pub mod ec_prime_field; use std::ops::{Add, AddAssign, Sub, SubAssign}; diff --git a/src/protocol/mod.rs b/src/protocol/mod.rs index 7931a1e37..530c12f74 100644 --- a/src/protocol/mod.rs +++ b/src/protocol/mod.rs @@ -6,6 +6,7 @@ pub mod context; pub mod dp; pub mod ipa; pub mod modulus_conversion; +pub mod prf_eval; #[cfg(feature = "descriptive-gate")] pub mod prf_sharding; pub mod prss; diff --git a/src/protocol/prf_eval/eval.rs b/src/protocol/prf_eval/eval.rs new file mode 100644 index 000000000..e69de29bb diff --git a/src/protocol/prf_eval/keygen.rs b/src/protocol/prf_eval/keygen.rs new file mode 100644 index 000000000..e69de29bb diff --git a/src/protocol/prf_eval/mod.rs b/src/protocol/prf_eval/mod.rs new file mode 100644 index 000000000..e69de29bb From 1b552f4c94381496b76f89994c06feddd3b27648 Mon Sep 17 00:00:00 2001 From: Daniel Masny Date: Mon, 2 Oct 2023 14:20:19 -0700 Subject: [PATCH 03/76] last commit before working on shared curve points --- src/protocol/prf_eval/eval.rs | 28 ++++++++++++++++++++++++++++ src/protocol/prf_eval/mod.rs | 2 ++ 2 files changed, 30 insertions(+) diff --git a/src/protocol/prf_eval/eval.rs b/src/protocol/prf_eval/eval.rs index e69de29bb..30c5c1d38 100644 --- a/src/protocol/prf_eval/eval.rs +++ b/src/protocol/prf_eval/eval.rs @@ -0,0 +1,28 @@ +use crate::{ + error::Error, + helpers::Direction, + ff::ec_prime_field::Fp25519, + protocol::{context::Context, step::BitOpStep, BasicProtocols, RecordId}, + secret_sharing::{Linear as LinearSecretSharing, LinearRefOps}, +}; + +/// evaluates the Dodis-Yampolski PRF g^(1/(k+x)) +/// the input x and k are secret shared over finite field Fp25519, i.e. the scalar field of curve 25519 +/// PRF key k is generated using keygen +/// In 3IPA, x is the match key +/// eval_DY outputs a u64 as specified in protocol/prf_sharding/mod.rs, all parties learn the output +pub async fn eval_dy( + ctx: C, + record_id: RecordId, + k: &[S], + x: &[S], +) -> Result + where + C: Context, + S: LinearSecretSharing + BasicProtocols, + for<'a> &'a S: LinearRefOps<'a, S, Fp25519>, +{ + let role = ctx.role(); + + Ok(5u64) +} \ No newline at end of file diff --git a/src/protocol/prf_eval/mod.rs b/src/protocol/prf_eval/mod.rs index e69de29bb..6183868b8 100644 --- a/src/protocol/prf_eval/mod.rs +++ b/src/protocol/prf_eval/mod.rs @@ -0,0 +1,2 @@ +mod eval; +mod keygen; \ No newline at end of file From 9dc50c47d6263852baa4e123c56a3754747c40cc Mon Sep 17 00:00:00 2001 From: Daniel Masny Date: Mon, 2 Oct 2023 16:48:31 -0700 Subject: [PATCH 04/76] adding curve points + conversion --- src/ff/curve_points.rs | 170 +++++++++++++++++++++++++++++++++++++++ src/ff/ec_prime_field.rs | 6 ++ src/ff/mod.rs | 1 + 3 files changed, 177 insertions(+) create mode 100644 src/ff/curve_points.rs diff --git a/src/ff/curve_points.rs b/src/ff/curve_points.rs new file mode 100644 index 000000000..3351efc51 --- /dev/null +++ b/src/ff/curve_points.rs @@ -0,0 +1,170 @@ +use std::ops::Mul; +use generic_array::GenericArray; +use curve25519_dalek::{ristretto::{CompressedRistretto, RistrettoPoint},constants, Scalar}; +use rand_core::RngCore; +use typenum::U32; + +use crate::{ + ff::{Serializable,ec_prime_field::Fp25519}, + secret_sharing::{Block, SharedValue}, +}; + +impl Block for CompressedRistretto { + type Size = U32; +} + +///ristretto point for curve 25519 +#[derive(Clone, Copy, PartialEq, Debug)] +pub struct RP25519(::Storage); + +//how to add const ONE: Self = Self(Scalar::ONE); within the struct, do I need to do it via a trait? + +/// using compressed ristretto point, Zero is generator of the curve, i.e. g^0 +impl SharedValue for RP25519 { + type Storage = CompressedRistretto; + const BITS: u32 = 256; + const ZERO: Self = Self(constants::RISTRETTO_BASEPOINT_COMPRESSED); +} + +impl Serializable for RP25519 { + type Size = <::Storage as Block>::Size; + + fn serialize(&self, buf: &mut GenericArray) { + let raw = &self.0.as_bytes()[..buf.len()] ; + buf.copy_from_slice(raw); + } + + fn deserialize(buf: &GenericArray) -> Self { + RP25519(CompressedRistretto::from_slice(buf).unwrap()) + } +} + + +impl rand::distributions::Distribution for rand::distributions::Standard { + fn sample(&self, rng: &mut R) -> RP25519 { + //Fp25519(Scalar::random(rng: &mut R)) + let mut scalar_bytes = [0u8; 64]; + rng.fill_bytes(&mut scalar_bytes); + RP25519(RistrettoPoint::from_uniform_bytes(&scalar_bytes).compress()) + } +} + + +impl std::ops::Add for RP25519 { +type Output = Self; + +fn add(self, rhs: Self) -> Self::Output { + Self((self.0.decompress().unwrap()+rhs.0.decompress().unwrap()).compress()) +} +} + +impl std::ops::AddAssign for RP25519 { +#[allow(clippy::assign_op_pattern)] +fn add_assign(&mut self, rhs: Self) { + *self = *self + rhs; +} +} + +impl std::ops::Neg for RP25519 { +type Output = Self; + +fn neg(self) -> Self::Output { + Self(self.0.decompress().unwrap().neg().compress()) +} +} + +impl std::ops::Sub for RP25519 { +type Output = Self; + +fn sub(self, rhs: Self) -> Self::Output { + Self((self.0.decompress().unwrap()-rhs.0.decompress().unwrap()).compress()) +} +} + +impl std::ops::SubAssign for RP25519 { +#[allow(clippy::assign_op_pattern)] +fn sub_assign(&mut self, rhs: Self) { + *self = *self - rhs; +} +} + + +///Scalar Multiplication +///<'a, 'b> std::ops::Mul<&'b Fp25519> for &'a +impl RP25519 { + +fn smul(self, rhs: Fp25519) -> RP25519 { + RP25519((self.0.decompress().unwrap() * >::into(rhs)).compress()) +} +} + +///<'a> std::ops::MulAssign<&'a Fp25519> for +impl RP25519 { +#[allow(clippy::assign_op_pattern)] +fn smul_assign(&mut self, rhs: Fp25519) { + *self = self.smul(rhs); +} +} + +///do not use +impl std::ops::Mul for RP25519 { + type Output = Self; + + fn mul(self, rhs: RP25519) -> Self::Output { + Self::ZERO + } +} + +///do not use +impl std::ops::MulAssign for RP25519 { + + fn mul_assign(& mut self, rhs: RP25519) { + *self=Self::ZERO; + } +} + +impl From for RP25519 { + fn from(s: Scalar) -> Self { + RP25519(RistrettoPoint::mul_base(&s).compress()) + } +} + +impl From for RP25519 { + fn from(s: Fp25519) -> Self { + RP25519(RistrettoPoint::mul_base(&s.into()).compress()) + } +} + +// impl Into for Fp25519 { +// fn into(self) -> RP25519 { +// RP25519(RistrettoPoint::mul_base(self.into()).compress()) +// } +// } + +#[cfg(all(test, unit_test))] +mod test { + use generic_array::GenericArray; + use crate::ff::curve_points::RP25519; + use crate::ff::Serializable; + use typenum::U32; + use curve25519_dalek::scalar::Scalar; + use rand::{thread_rng, Rng}; + use crate::secret_sharing::SharedValue; + + #[test] + fn serde_25519() { + let input:[u8;32] = [ + 0x01, 0xff,0x00, 0xff,0x00, 0xff,0x00, 0xff, + 0x00, 0xff,0x00, 0xff,0x00, 0xff,0x00, 0xff, + 0x00, 0xff,0x00, 0xff,0x00, 0xff,0x00, 0xff, + 0x00, 0xff,0x00, 0xff,0x00, 0x00,0x00, 0x00 + ]; + let mut output: GenericArray = [0u8;32].into(); + let a = RP25519::deserialize(&input.into()); + assert_eq!(a.0.as_bytes()[..32],input); + a.serialize(&mut output); + assert_eq!(a.0.as_bytes()[..32],output.as_slice()[..32]); + assert_eq!(input,output.as_slice()[..32]); + } + +} \ No newline at end of file diff --git a/src/ff/ec_prime_field.rs b/src/ff/ec_prime_field.rs index c87dbfa94..5e2d13fa5 100644 --- a/src/ff/ec_prime_field.rs +++ b/src/ff/ec_prime_field.rs @@ -24,6 +24,12 @@ impl SharedValue for Fp25519 { const ZERO: Self = Self(Scalar::ZERO); } +impl Into for Fp25519 { + fn into(self) -> Scalar { + self.0 + } +} + impl Serializable for Fp25519 { type Size = <::Storage as Block>::Size; diff --git a/src/ff/mod.rs b/src/ff/mod.rs index c4d287e7a..b26596086 100644 --- a/src/ff/mod.rs +++ b/src/ff/mod.rs @@ -6,6 +6,7 @@ mod field; mod galois_field; mod prime_field; pub mod ec_prime_field; +pub mod curve_points; use std::ops::{Add, AddAssign, Sub, SubAssign}; From 94597b1b5d97a12f364e9ed1b22d5bc004be72b4 Mon Sep 17 00:00:00 2001 From: Daniel Masny Date: Tue, 3 Oct 2023 10:17:02 -0700 Subject: [PATCH 05/76] from, into scalar for RP25519 + test --- src/ff/curve_points.rs | 22 +++++++++++++++++++--- src/ff/ec_prime_field.rs | 6 ++++++ 2 files changed, 25 insertions(+), 3 deletions(-) diff --git a/src/ff/curve_points.rs b/src/ff/curve_points.rs index 3351efc51..c0236c04a 100644 --- a/src/ff/curve_points.rs +++ b/src/ff/curve_points.rs @@ -93,7 +93,7 @@ fn sub_assign(&mut self, rhs: Self) { ///<'a, 'b> std::ops::Mul<&'b Fp25519> for &'a impl RP25519 { -fn smul(self, rhs: Fp25519) -> RP25519 { +fn s_mul(self, rhs: Fp25519) -> RP25519 { RP25519((self.0.decompress().unwrap() * >::into(rhs)).compress()) } } @@ -101,8 +101,8 @@ fn smul(self, rhs: Fp25519) -> RP25519 { ///<'a> std::ops::MulAssign<&'a Fp25519> for impl RP25519 { #[allow(clippy::assign_op_pattern)] -fn smul_assign(&mut self, rhs: Fp25519) { - *self = self.smul(rhs); +fn s_mul_assign(&mut self, rhs: Fp25519) { + *self = self.s_mul(rhs); } } @@ -149,6 +149,7 @@ mod test { use typenum::U32; use curve25519_dalek::scalar::Scalar; use rand::{thread_rng, Rng}; + use crate::ff::ec_prime_field::Fp25519; use crate::secret_sharing::SharedValue; #[test] @@ -167,4 +168,19 @@ mod test { assert_eq!(input,output.as_slice()[..32]); } + #[test] + fn scalar_to_point() { + let a = Scalar::ONE; + let b : RP25519 = a.clone().into(); + let d : Fp25519 = a.into(); + let c : RP25519 = RP25519::from(d); + assert_eq!(b,RP25519::ZERO); + assert_eq!(c,RP25519::ZERO); + } + + #[test] + fn curve_arithmetics() { + + } + } \ No newline at end of file diff --git a/src/ff/ec_prime_field.rs b/src/ff/ec_prime_field.rs index 5e2d13fa5..30ee3955e 100644 --- a/src/ff/ec_prime_field.rs +++ b/src/ff/ec_prime_field.rs @@ -117,6 +117,12 @@ impl Fp25519 { } } +impl From for Fp25519 { + fn from(s: Scalar) -> Self { + Fp25519(s) + } +} + #[cfg(all(test, unit_test))] mod test { use generic_array::GenericArray; From 4da801413bf8e055061ad107af0429e93f394888 Mon Sep 17 00:00:00 2001 From: Daniel Masny Date: Tue, 3 Oct 2023 11:03:32 -0700 Subject: [PATCH 06/76] test aritmetics for RP25519 --- src/ff/curve_points.rs | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/ff/curve_points.rs b/src/ff/curve_points.rs index c0236c04a..1678210d7 100644 --- a/src/ff/curve_points.rs +++ b/src/ff/curve_points.rs @@ -180,7 +180,19 @@ mod test { #[test] fn curve_arithmetics() { - + let mut rng = rand::thread_rng(); + let a = rng.gen::(); + let b = rng.gen::(); + let c = a+b; + let d = RP25519::from(a)+RP25519::from(b); + assert_eq!(d, RP25519::from(c)); + assert_ne!(d, RP25519::ZERO); + let e = rng.gen::(); + let f=rng.gen::(); + let g =e*f; + let h = RP25519::from(e).s_mul(f); + assert_eq!(h,RP25519::from(g)); + assert_ne!(h, RP25519::ZERO); } } \ No newline at end of file From fd6c28e4ba7aade1945dc5d2407f561a4675146e Mon Sep 17 00:00:00 2001 From: Daniel Masny Date: Wed, 4 Oct 2023 11:29:56 -0700 Subject: [PATCH 07/76] upgrade share to share --- src/ff/curve_points.rs | 3 +-- src/ff/ec_prime_field.rs | 7 ++++--- src/protocol/prf_eval/eval.rs | 13 +++++++++++-- 3 files changed, 16 insertions(+), 7 deletions(-) diff --git a/src/ff/curve_points.rs b/src/ff/curve_points.rs index 1678210d7..084b1a48d 100644 --- a/src/ff/curve_points.rs +++ b/src/ff/curve_points.rs @@ -1,4 +1,3 @@ -use std::ops::Mul; use generic_array::GenericArray; use curve25519_dalek::{ristretto::{CompressedRistretto, RistrettoPoint},constants, Scalar}; use rand_core::RngCore; @@ -180,7 +179,7 @@ mod test { #[test] fn curve_arithmetics() { - let mut rng = rand::thread_rng(); + let mut rng = thread_rng(); let a = rng.gen::(); let b = rng.gen::(); let c = a+b; diff --git a/src/ff/ec_prime_field.rs b/src/ff/ec_prime_field.rs index 30ee3955e..313cb9753 100644 --- a/src/ff/ec_prime_field.rs +++ b/src/ff/ec_prime_field.rs @@ -49,10 +49,11 @@ impl Serializable for Fp25519 { impl rand::distributions::Distribution for rand::distributions::Standard { fn sample(&self, rng: &mut R) -> Fp25519 { - //Fp25519(Scalar::random(rng: &mut R)) - let mut scalar_bytes = [0u8; 64]; + let mut scalar_bytes = [0u8; 32]; rng.fill_bytes(&mut scalar_bytes); - Fp25519(Scalar::from_bytes_mod_order_wide(&scalar_bytes)) + Fp25519(Scalar::from_bytes_mod_order(scalar_bytes)) + //not needed since above has sufficiently small bias + //Fp25519(Scalar::from_bytes_mod_order(&scalar_bytes)) } } diff --git a/src/protocol/prf_eval/eval.rs b/src/protocol/prf_eval/eval.rs index 30c5c1d38..0307f42b8 100644 --- a/src/protocol/prf_eval/eval.rs +++ b/src/protocol/prf_eval/eval.rs @@ -1,11 +1,20 @@ use crate::{ error::Error, helpers::Direction, - ff::ec_prime_field::Fp25519, + ff::{ec_prime_field::Fp25519, curve_points::RP25519}, protocol::{context::Context, step::BitOpStep, BasicProtocols, RecordId}, - secret_sharing::{Linear as LinearSecretSharing, LinearRefOps}, + secret_sharing::{Linear as LinearSecretSharing, LinearRefOps, SharedValue, replicated::{semi_honest::AdditiveShare,ReplicatedSecretSharing}}, }; + +impl Into> for AdditiveShare { + fn into(self) -> AdditiveShare + { + AdditiveShare::new(RP25519::from(self.left()),RP25519::from(self.right())) + } +} + + /// evaluates the Dodis-Yampolski PRF g^(1/(k+x)) /// the input x and k are secret shared over finite field Fp25519, i.e. the scalar field of curve 25519 /// PRF key k is generated using keygen From 3c5683e46e185b80141e316b148637ea3882b38b Mon Sep 17 00:00:00 2001 From: Daniel Masny Date: Wed, 4 Oct 2023 11:57:10 -0700 Subject: [PATCH 08/76] remove warning --- src/ff/ec_prime_field.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ff/ec_prime_field.rs b/src/ff/ec_prime_field.rs index 313cb9753..cedad411a 100644 --- a/src/ff/ec_prime_field.rs +++ b/src/ff/ec_prime_field.rs @@ -1,6 +1,6 @@ use generic_array::GenericArray; use curve25519_dalek::scalar::Scalar; -use rand_core::RngCore; +//use rand_core::RngCore; use typenum::U32; use crate::{ From b2164819941d9ec9bfb50c01eb33f81db2333425 Mon Sep 17 00:00:00 2001 From: Daniel Masny Date: Wed, 4 Oct 2023 15:47:45 -0700 Subject: [PATCH 09/76] add hash curve points --- src/ff/curve_points.rs | 65 +++++++++++++++++++++++++++++----------- src/ff/ec_prime_field.rs | 31 +++++++++---------- 2 files changed, 61 insertions(+), 35 deletions(-) diff --git a/src/ff/curve_points.rs b/src/ff/curve_points.rs index 084b1a48d..eed23e5ec 100644 --- a/src/ff/curve_points.rs +++ b/src/ff/curve_points.rs @@ -1,7 +1,9 @@ use generic_array::GenericArray; use curve25519_dalek::{ristretto::{CompressedRistretto, RistrettoPoint},constants, Scalar}; -use rand_core::RngCore; use typenum::U32; +use sha2::Sha256; +use hkdf::Hkdf; + use crate::{ ff::{Serializable,ec_prime_field::Fp25519}, @@ -93,32 +95,25 @@ fn sub_assign(&mut self, rhs: Self) { impl RP25519 { fn s_mul(self, rhs: Fp25519) -> RP25519 { - RP25519((self.0.decompress().unwrap() * >::into(rhs)).compress()) + RP25519((self.0.decompress().unwrap() * Scalar::from(rhs)).compress()) } } -///<'a> std::ops::MulAssign<&'a Fp25519> for -impl RP25519 { -#[allow(clippy::assign_op_pattern)] -fn s_mul_assign(&mut self, rhs: Fp25519) { - *self = self.s_mul(rhs); -} -} ///do not use impl std::ops::Mul for RP25519 { type Output = Self; - fn mul(self, rhs: RP25519) -> Self::Output { - Self::ZERO + fn mul(self, _rhs: RP25519) -> Self::Output { + panic!("Two curve points cannot be multiplied! Do not use *, *= for RP25519 or secret shares of RP25519"); } } ///do not use impl std::ops::MulAssign for RP25519 { - fn mul_assign(& mut self, rhs: RP25519) { - *self=Self::ZERO; + fn mul_assign(& mut self, _rhs: RP25519) { + panic!("Two curve points cannot be multiplied! Do not use *, *= for RP25519 or secret shares of RP25519"); } } @@ -134,11 +129,36 @@ impl From for RP25519 { } } -// impl Into for Fp25519 { -// fn into(self) -> RP25519 { -// RP25519(RistrettoPoint::mul_base(self.into()).compress()) -// } -// } +macro_rules! cp_hash_impl { + ( $u_type:ty, $byte_size:literal) => { + impl From for $u_type { + fn from(s: RP25519) -> Self { + let hk = Hkdf::::new(None, s.0.as_bytes()); + let mut okm = [0u8; $byte_size]; + //error invalid length from expand only happens when okm is very large + hk.expand(&[], &mut okm).unwrap(); + <$u_type>::from_le_bytes(okm) + } + } + } +} + +cp_hash_impl!( + u128, + 16 +); + +cp_hash_impl!( + u64, + 8 +); + +cp_hash_impl!( + u32, + 4 +); + + #[cfg(all(test, unit_test))] mod test { @@ -194,4 +214,13 @@ mod test { assert_ne!(h, RP25519::ZERO); } + #[test] + fn curve_point_to_hash() { + let mut rng = thread_rng(); + let a = rng.gen::(); + assert_ne!(0u128,u128::from(a)); + assert_ne!(0u64,u64::from(a)); + assert_ne!(0u32,u32::from(a)); + } + } \ No newline at end of file diff --git a/src/ff/ec_prime_field.rs b/src/ff/ec_prime_field.rs index cedad411a..3e4f762d8 100644 --- a/src/ff/ec_prime_field.rs +++ b/src/ff/ec_prime_field.rs @@ -15,7 +15,16 @@ impl Block for Scalar { #[derive(Clone, Copy, PartialEq, Debug)] pub struct Fp25519(::Storage); -//how to add const ONE: Self = Self(Scalar::ONE); within the struct, do I need to do it via a trait? + +impl Fp25519 { + const ONE: Self = Self(Scalar::ONE); + + //must not use with ZERO + pub fn invert(&self) -> Fp25519 { + Fp25519(self.0.invert()) + } + +} impl SharedValue for Fp25519 { @@ -24,9 +33,9 @@ impl SharedValue for Fp25519 { const ZERO: Self = Self(Scalar::ZERO); } -impl Into for Fp25519 { - fn into(self) -> Scalar { - self.0 +impl From for Scalar { + fn from(s: Fp25519) -> Self { + s.0 } } @@ -111,12 +120,6 @@ fn mul_assign(&mut self, rhs: Self) { } } -//must not use with ZERO -impl Fp25519 { - pub fn invert(&self) -> Fp25519 { - Fp25519(self.0.invert()) - } -} impl From for Fp25519 { fn from(s: Scalar) -> Self { @@ -165,12 +168,6 @@ mod test { 0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00, 0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00 ])); - let c = Fp25519(Scalar::from_bytes_mod_order([ - 0x01, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00, - 0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00, - 0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00, - 0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00 - ])); let d = Fp25519(Scalar::from_bytes_mod_order([ 0x05, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00, 0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00, @@ -186,7 +183,7 @@ mod test { let cc = b-a; let dc = a+b; let ec = a*b; - assert_eq!(cc,c); + assert_eq!(cc,Fp25519::ONE); assert_eq!(dc,d); assert_eq!(ec,e); } From 06f6eb1725ab740c0de941fb8598955f2da4c9a2 Mon Sep 17 00:00:00 2001 From: Daniel Masny Date: Thu, 5 Oct 2023 13:46:24 -0700 Subject: [PATCH 10/76] implementation of PRF eval protocol --- src/ff/curve_points.rs | 72 ++++++++++++++++++++++++++---- src/ff/ec_prime_field.rs | 79 ++++++++++++++++++++++++++++++++- src/protocol/prf_eval/eval.rs | 37 --------------- src/protocol/prf_eval/keygen.rs | 0 src/protocol/prf_eval/mod.rs | 67 +++++++++++++++++++++++++++- 5 files changed, 206 insertions(+), 49 deletions(-) delete mode 100644 src/protocol/prf_eval/eval.rs delete mode 100644 src/protocol/prf_eval/keygen.rs diff --git a/src/ff/curve_points.rs b/src/ff/curve_points.rs index eed23e5ec..fad671dd0 100644 --- a/src/ff/curve_points.rs +++ b/src/ff/curve_points.rs @@ -6,7 +6,7 @@ use hkdf::Hkdf; use crate::{ - ff::{Serializable,ec_prime_field::Fp25519}, + ff::{Serializable,ec_prime_field::Fp25519,Field}, secret_sharing::{Block, SharedValue}, }; @@ -93,8 +93,9 @@ fn sub_assign(&mut self, rhs: Self) { ///Scalar Multiplication ///<'a, 'b> std::ops::Mul<&'b Fp25519> for &'a impl RP25519 { + pub const ONE: Self = Self(constants::RISTRETTO_BASEPOINT_COMPRESSED); -fn s_mul(self, rhs: Fp25519) -> RP25519 { +pub fn s_mul(self, rhs: Fp25519) -> RP25519 { RP25519((self.0.decompress().unwrap() * Scalar::from(rhs)).compress()) } } @@ -129,6 +130,18 @@ impl From for RP25519 { } } +impl From for RP25519 { + fn from(s: CompressedRistretto) -> Self { + RP25519(s) + } +} + +impl From for CompressedRistretto { + fn from(s: RP25519) -> Self { + s.0 + } +} + macro_rules! cp_hash_impl { ( $u_type:ty, $byte_size:literal) => { impl From for $u_type { @@ -140,14 +153,19 @@ macro_rules! cp_hash_impl { <$u_type>::from_le_bytes(okm) } } + + impl From<$u_type> for RP25519 { + fn from(s: $u_type) -> Self { + let hk = Hkdf::::new(None, &s.to_le_bytes()); + let mut okm = [0u8; 32]; + //error invalid length from expand only happens when okm is very large + hk.expand(&[], &mut okm).unwrap(); + RP25519::deserialize(&okm.into()) + } + } } } -cp_hash_impl!( - u128, - 16 -); - cp_hash_impl!( u64, 8 @@ -158,6 +176,45 @@ cp_hash_impl!( 4 ); +/// Daniel had to implement this since Reveal wants it, prefer not to, I dont understand why it is +/// actually needed there, maybe to upgrade it to malicious? but it still shouldn't be needed +impl Field for RP25519 { + const ONE: RP25519= RP25519::ONE; + + ///both following methods are based on hashing and do not allow to actually convert elements in Fp25519 + /// from or into u128. However it is sufficient to generate random elements in Fp25519 + fn as_u128(&self) -> u128 { + let hk = Hkdf::::new(None, self.0.as_bytes()); + let mut okm = [0u8; 16]; + //error invalid length from expand only happens when okm is very large + hk.expand(&[], &mut okm).unwrap(); + u128::from_le_bytes(okm) + } + + ///PRSS uses truncate_from function, we need to expand the u128 using a PRG (Sha256) to a [u8;32] + fn truncate_from>(v: T) -> Self { + let hk = Hkdf::::new(None, &v.into().to_le_bytes()); + let mut okm = [0u8; 32]; + //error invalid length from expand only happens when okm is very large + hk.expand(&[], &mut okm).unwrap(); + RP25519::deserialize(&okm.into()) + } + +} + +impl TryFrom for RP25519 { + type Error = crate::error::Error; + + fn try_from(v: u128) -> Result { + let mut bits = [0u8; 32]; + bits[..].copy_from_slice(&v.to_le_bytes()); + let f: RP25519=RP25519::ONE; + f.serialize((&mut bits).into()); + Ok(f) + } +} + + #[cfg(all(test, unit_test))] @@ -218,7 +275,6 @@ mod test { fn curve_point_to_hash() { let mut rng = thread_rng(); let a = rng.gen::(); - assert_ne!(0u128,u128::from(a)); assert_ne!(0u64,u64::from(a)); assert_ne!(0u32,u32::from(a)); } diff --git a/src/ff/ec_prime_field.rs b/src/ff/ec_prime_field.rs index 3e4f762d8..2f88b07cc 100644 --- a/src/ff/ec_prime_field.rs +++ b/src/ff/ec_prime_field.rs @@ -2,9 +2,11 @@ use generic_array::GenericArray; use curve25519_dalek::scalar::Scalar; //use rand_core::RngCore; use typenum::U32; +use sha2::Sha256; +use hkdf::Hkdf; use crate::{ - ff::Serializable, + ff::{Serializable, Field}, secret_sharing::{Block, SharedValue}, }; @@ -17,7 +19,7 @@ pub struct Fp25519(::Storage); impl Fp25519 { - const ONE: Self = Self(Scalar::ONE); + pub const ONE: Self = Self(Scalar::ONE); //must not use with ZERO pub fn invert(&self) -> Fp25519 { @@ -127,6 +129,79 @@ impl From for Fp25519 { } } +macro_rules! sc_hash_impl { + ( $u_type:ty, $byte_size:literal) => { + impl From for $u_type { + fn from(s: Fp25519) -> Self { + let hk = Hkdf::::new(None, s.0.as_bytes()); + let mut okm = [0u8; $byte_size]; + //error invalid length from expand only happens when okm is very large + hk.expand(&[], &mut okm).unwrap(); + <$u_type>::from_le_bytes(okm) + } + } + + impl From<$u_type> for Fp25519 { + fn from(s: $u_type) -> Self { + let hk = Hkdf::::new(None, &s.to_le_bytes()); + let mut okm = [0u8; 32]; + //error invalid length from expand only happens when okm is very large + hk.expand(&[], &mut okm).unwrap(); + Fp25519::deserialize(&okm.into()) + } + } + } +} + + +sc_hash_impl!( + u64, + 8 +); + +sc_hash_impl!( + u32, + 4 +); + + +/// Daniel had to implement this since PRSS wants it, prefer not to +impl Field for Fp25519 { + const ONE: Fp25519= Fp25519::ONE; + + ///both following methods are based on hashing and do not allow to actually convert elements in Fp25519 + /// from or into u128. However it is sufficient to generate random elements in Fp25519 + fn as_u128(&self) -> u128 { + let hk = Hkdf::::new(None, self.0.as_bytes()); + let mut okm = [0u8; 16]; + //error invalid length from expand only happens when okm is very large + hk.expand(&[], &mut okm).unwrap(); + u128::from_le_bytes(okm) + } + + ///PRSS uses truncate_from function, we need to expand the u128 using a PRG (Sha256) to a [u8;32] + fn truncate_from>(v: T) -> Self { + let hk = Hkdf::::new(None, &v.into().to_le_bytes()); + let mut okm = [0u8; 32]; + //error invalid length from expand only happens when okm is very large + hk.expand(&[], &mut okm).unwrap(); + Fp25519::deserialize(&okm.into()) + } + +} + +impl TryFrom for Fp25519 { + type Error = crate::error::Error; + + fn try_from(v: u128) -> Result { + let mut bits = [0u8; 32]; + bits[..].copy_from_slice(&v.to_le_bytes()); + let f: Fp25519=Fp25519::ONE; + f.serialize((&mut bits).into()); + Ok(f) + } +} + #[cfg(all(test, unit_test))] mod test { use generic_array::GenericArray; diff --git a/src/protocol/prf_eval/eval.rs b/src/protocol/prf_eval/eval.rs deleted file mode 100644 index 0307f42b8..000000000 --- a/src/protocol/prf_eval/eval.rs +++ /dev/null @@ -1,37 +0,0 @@ -use crate::{ - error::Error, - helpers::Direction, - ff::{ec_prime_field::Fp25519, curve_points::RP25519}, - protocol::{context::Context, step::BitOpStep, BasicProtocols, RecordId}, - secret_sharing::{Linear as LinearSecretSharing, LinearRefOps, SharedValue, replicated::{semi_honest::AdditiveShare,ReplicatedSecretSharing}}, -}; - - -impl Into> for AdditiveShare { - fn into(self) -> AdditiveShare - { - AdditiveShare::new(RP25519::from(self.left()),RP25519::from(self.right())) - } -} - - -/// evaluates the Dodis-Yampolski PRF g^(1/(k+x)) -/// the input x and k are secret shared over finite field Fp25519, i.e. the scalar field of curve 25519 -/// PRF key k is generated using keygen -/// In 3IPA, x is the match key -/// eval_DY outputs a u64 as specified in protocol/prf_sharding/mod.rs, all parties learn the output -pub async fn eval_dy( - ctx: C, - record_id: RecordId, - k: &[S], - x: &[S], -) -> Result - where - C: Context, - S: LinearSecretSharing + BasicProtocols, - for<'a> &'a S: LinearRefOps<'a, S, Fp25519>, -{ - let role = ctx.role(); - - Ok(5u64) -} \ No newline at end of file diff --git a/src/protocol/prf_eval/keygen.rs b/src/protocol/prf_eval/keygen.rs deleted file mode 100644 index e69de29bb..000000000 diff --git a/src/protocol/prf_eval/mod.rs b/src/protocol/prf_eval/mod.rs index 6183868b8..193cb360c 100644 --- a/src/protocol/prf_eval/mod.rs +++ b/src/protocol/prf_eval/mod.rs @@ -1,2 +1,65 @@ -mod eval; -mod keygen; \ No newline at end of file +use crate::{ + error::Error, + ff::{ec_prime_field::Fp25519, curve_points::RP25519}, + protocol::{context::Context, RecordId, prss::SharedRandomness, basics::Reveal, basics::SecureMul}, + secret_sharing::{replicated::{semi_honest::AdditiveShare,ReplicatedSecretSharing}}, +}; + + +impl From> for AdditiveShare { + fn from(s: AdditiveShare) -> Self { + AdditiveShare::new(RP25519::from(s.left()),RP25519::from(s.right())) + } +} + +/// generates PRF key k as secret sharing over Fp25519 +pub fn gen_prf_key (ctx: C) -> AdditiveShare + where + C: Context, +{ + ctx.prss().generate_replicated(u128::MAX-100u128) +} + + +/// evaluates the Dodis-Yampolski PRF g^(1/(k+x)) +/// the input x and k are secret shared over finite field Fp25519, i.e. the scalar field of curve 25519 +/// PRF key k is generated using keygen +/// In 3IPA, x is the match key +/// eval_DY outputs a u64 as specified in protocol/prf_sharding/mod.rs, all parties learn the output +pub async fn eval_dy_prf( + ctx: C, + record_id: RecordId, + k: &AdditiveShare, + x: &AdditiveShare, +) -> Result + where + C: Context, +{ + // generate random shares using shared randomness, use index max/2 to not clash with multiply + let sh_r: AdditiveShare = ctx.prss().generate_replicated(u128::MAX/2+u128::from(record_id)); + + //compute (g^left, g^right) + let sh_gr = AdditiveShare::::from(sh_r.clone()); + + //compute x+k + let y =x+k; + + //compute y <- r*y + //Daniel: probably shouldn't use ctx anymore? why doesn't y need to be mutable? + y.multiply(&sh_r, ctx.clone(), record_id).await?; + + //reconstruct (z,R) + let mut gr: RP25519 = sh_gr.reveal(ctx, record_id).await?; + + //invert z + let mut z: Fp25519 = Fp25519::ONE; + z=z.invert(); + //compute R^z + gr=gr.s_mul(z); + Ok(u64::from(gr)) +} + +#[cfg(all(test, unit_test))] +mod test { + +} \ No newline at end of file From de5f32c87e5c7d4ef5e89c6c8f256819e77f190c Mon Sep 17 00:00:00 2001 From: Daniel Masny Date: Fri, 6 Oct 2023 13:47:06 -0700 Subject: [PATCH 11/76] prf eval test passes --- src/protocol/prf_eval/mod.rs | 134 +++++++++++++++++++++++++++++++---- 1 file changed, 119 insertions(+), 15 deletions(-) diff --git a/src/protocol/prf_eval/mod.rs b/src/protocol/prf_eval/mod.rs index 193cb360c..e3d0cd6a4 100644 --- a/src/protocol/prf_eval/mod.rs +++ b/src/protocol/prf_eval/mod.rs @@ -3,7 +3,31 @@ use crate::{ ff::{ec_prime_field::Fp25519, curve_points::RP25519}, protocol::{context::Context, RecordId, prss::SharedRandomness, basics::Reveal, basics::SecureMul}, secret_sharing::{replicated::{semi_honest::AdditiveShare,ReplicatedSecretSharing}}, + seq_join::seq_try_join_all, }; +use ipa_macros::Step; + +#[derive(Step)] +pub(crate) enum Step { + PRFKeyGen, + GenRandomMask, + MultMaskWithPRFInput, + RevealR, + Revealz, +} + +pub async fn compute_match_key_pseudonym( + sh_ctx: C, + prf_key: AdditiveShare, + input_match_keys: Vec>, +) -> Result, Error> + where + C: Context, +{ + let ctx =sh_ctx.set_total_records(input_match_keys.len()); + let futures=input_match_keys.iter().enumerate().map(|(i,x)|eval_dy_prf(ctx.clone(),i.into(),&prf_key,x)); + Ok(seq_try_join_all(sh_ctx.active_work(), futures).await?.iter().map(|&x|u64::from(x)).collect()) +} impl From> for AdditiveShare { @@ -17,7 +41,7 @@ pub fn gen_prf_key (ctx: C) -> AdditiveShare where C: Context, { - ctx.prss().generate_replicated(u128::MAX-100u128) + ctx.narrow(&Step::PRFKeyGen).prss().generate_replicated(u128::MAX-100u128) } @@ -26,7 +50,7 @@ pub fn gen_prf_key (ctx: C) -> AdditiveShare /// PRF key k is generated using keygen /// In 3IPA, x is the match key /// eval_DY outputs a u64 as specified in protocol/prf_sharding/mod.rs, all parties learn the output -pub async fn eval_dy_prf( +pub async fn eval_dy_prf( ctx: C, record_id: RecordId, k: &AdditiveShare, @@ -35,31 +59,111 @@ pub async fn eval_dy_prf( where C: Context, { - // generate random shares using shared randomness, use index max/2 to not clash with multiply - let sh_r: AdditiveShare = ctx.prss().generate_replicated(u128::MAX/2+u128::from(record_id)); + let sh_r: AdditiveShare = ctx.narrow(&Step::GenRandomMask).prss().generate_replicated(record_id); //compute (g^left, g^right) let sh_gr = AdditiveShare::::from(sh_r.clone()); //compute x+k - let y =x+k; + let mut y =x+k; //compute y <- r*y - //Daniel: probably shouldn't use ctx anymore? why doesn't y need to be mutable? - y.multiply(&sh_r, ctx.clone(), record_id).await?; + y = y.multiply(&sh_r, ctx.narrow(&Step::MultMaskWithPRFInput), record_id).await?; //reconstruct (z,R) - let mut gr: RP25519 = sh_gr.reveal(ctx, record_id).await?; - - //invert z - let mut z: Fp25519 = Fp25519::ONE; - z=z.invert(); - //compute R^z - gr=gr.s_mul(z); - Ok(u64::from(gr)) + let gr: RP25519 = sh_gr.reveal(ctx.narrow(&Step::RevealR), record_id).await?; + let z = y.reveal(ctx.narrow(&Step::Revealz), record_id).await?; + + + + //compute R^(1/z) to u64 + Ok(u64::from(gr.s_mul(z.invert()))) } #[cfg(all(test, unit_test))] mod test { + use rand::Rng; + use crate::{ + test_executor::run, + test_fixture::{TestWorld, Reconstruct, Runner}, + ff::{ec_prime_field::Fp25519, curve_points::RP25519}, + secret_sharing::{IntoShares,replicated::semi_honest::AdditiveShare}, + protocol::prf_eval::{compute_match_key_pseudonym}, + }; + + #[derive(Copy, Clone)] + struct ShuffledTestInput { + match_key: Fp25519, + } + + #[derive(Debug, PartialEq)] + struct TestOutput { + match_key_pseudonym: u64, + } + + fn test_input( mk: u64) -> ShuffledTestInput { + ShuffledTestInput { + match_key: Fp25519::from(mk), + } + } + + impl IntoShares> for ShuffledTestInput + { + fn share_with(self, rng: &mut R) -> [AdditiveShare; 3] { + self.match_key.share_with(rng) + } + } + + + impl Reconstruct for [&u64; 3] { + fn reconstruct(&self) -> TestOutput { + TestOutput{ + match_key_pseudonym: if *self[0]==*self[1] && *self[0]==*self[2] {*self[0]} else {0u64}, + } + } + } + + + #[test] + fn semi_honest() { + run(|| async move { + let world = TestWorld::default(); + + //first two need to be identical for test to succeed + let records: Vec = vec![ + test_input(3), + test_input(3), + test_input(23443524523), + test_input(56), + test_input(895764542), + test_input(456764576), + test_input(56), + test_input(3), + test_input(56), + test_input(23443524523), + ]; + + //PRF Key Gen + let u = 3216412445u64; + let k:Fp25519 = Fp25519::from(u); + + let expected: Vec=records.iter().map(|&x| TestOutput{match_key_pseudonym: (RP25519::from((x.match_key+k).invert())).into()} ).collect(); + + let result: Vec<_> = world + .semi_honest((records.into_iter(),k), |ctx, (input_match_keys,prf_key)| async move { + compute_match_key_pseudonym::<_>( + ctx, + prf_key, + input_match_keys, + ) + .await + .unwrap() + }) + .await + .reconstruct(); + assert_eq!(result, expected); + assert_eq!(result[0], result[1]); + }); + } } \ No newline at end of file From 552cc6210e992ed45df895aa0dc5f25718632913 Mon Sep 17 00:00:00 2001 From: Daniel Masny Date: Mon, 9 Oct 2023 15:03:41 -0700 Subject: [PATCH 12/76] fixed clippy complaints, panics when setting invalid curve points or multiply curve points --- src/error.rs | 2 ++ src/ff/curve_points.rs | 47 +++++++++++++++++++++--------------- src/ff/ec_prime_field.rs | 3 ++- src/protocol/prf_eval/mod.rs | 23 +++++++++++------- 4 files changed, 45 insertions(+), 30 deletions(-) diff --git a/src/error.rs b/src/error.rs index c68b325a8..7d6456c7f 100644 --- a/src/error.rs +++ b/src/error.rs @@ -58,6 +58,8 @@ pub enum Error { InvalidReport(#[from] InvalidReportError), #[error("unsupported: {0}")] Unsupported(String), + #[error("Decompressing invalid elliptic curve point")] + DecompressingInvalidCurvePoint, } impl Default for Error { diff --git a/src/ff/curve_points.rs b/src/ff/curve_points.rs index fad671dd0..d04eec535 100644 --- a/src/ff/curve_points.rs +++ b/src/ff/curve_points.rs @@ -5,7 +5,9 @@ use sha2::Sha256; use hkdf::Hkdf; + use crate::{ + error::Error, ff::{Serializable,ec_prime_field::Fp25519,Field}, secret_sharing::{Block, SharedValue}, }; @@ -91,12 +93,17 @@ fn sub_assign(&mut self, rhs: Self) { ///Scalar Multiplication -///<'a, 'b> std::ops::Mul<&'b Fp25519> for &'a +///<'a, 'b> `std::ops::Mul<&'b"` Fp25519 for &'a impl RP25519 { pub const ONE: Self = Self(constants::RISTRETTO_BASEPOINT_COMPRESSED); -pub fn s_mul(self, rhs: Fp25519) -> RP25519 { - RP25519((self.0.decompress().unwrap() * Scalar::from(rhs)).compress()) + /// # Errors + /// Propagates errors from decompressing invalid curve point +pub fn s_mul(self, rhs: Fp25519) -> Result { + self.0.decompress().map_or( + Err(Error::DecompressingInvalidCurvePoint), + |x| Ok((x * Scalar::from(rhs)).compress().into()) + ) } } @@ -191,7 +198,7 @@ impl Field for RP25519 { u128::from_le_bytes(okm) } - ///PRSS uses truncate_from function, we need to expand the u128 using a PRG (Sha256) to a [u8;32] + ///PRSS uses `truncate_from function`, we need to expand the u128 using a PRG (Sha256) to a [u8;32] fn truncate_from>(v: T) -> Self { let hk = Hkdf::::new(None, &v.into().to_le_bytes()); let mut okm = [0u8; 32]; @@ -247,7 +254,7 @@ mod test { #[test] fn scalar_to_point() { let a = Scalar::ONE; - let b : RP25519 = a.clone().into(); + let b : RP25519 = a.into(); let d : Fp25519 = a.into(); let c : RP25519 = RP25519::from(d); assert_eq!(b,RP25519::ZERO); @@ -257,26 +264,26 @@ mod test { #[test] fn curve_arithmetics() { let mut rng = thread_rng(); - let a = rng.gen::(); - let b = rng.gen::(); - let c = a+b; - let d = RP25519::from(a)+RP25519::from(b); - assert_eq!(d, RP25519::from(c)); - assert_ne!(d, RP25519::ZERO); - let e = rng.gen::(); - let f=rng.gen::(); - let g =e*f; - let h = RP25519::from(e).s_mul(f); - assert_eq!(h,RP25519::from(g)); - assert_ne!(h, RP25519::ZERO); + let fp_a = rng.gen::(); + let fp_b = rng.gen::(); + let fp_c = fp_a+fp_b; + let fp_d = RP25519::from(fp_a)+RP25519::from(fp_b); + assert_eq!(fp_d, RP25519::from(fp_c)); + assert_ne!(fp_d, RP25519::ZERO); + let fp_e = rng.gen::(); + let fp_f=rng.gen::(); + let fp_g =fp_e*fp_f; + let fp_h = RP25519::from(fp_e).s_mul(fp_f).unwrap(); + assert_eq!(fp_h,RP25519::from(fp_g)); + assert_ne!(fp_h, RP25519::ZERO); } #[test] fn curve_point_to_hash() { let mut rng = thread_rng(); - let a = rng.gen::(); - assert_ne!(0u64,u64::from(a)); - assert_ne!(0u32,u32::from(a)); + let fp_a = rng.gen::(); + assert_ne!(0u64,u64::from(fp_a)); + assert_ne!(0u32,u32::from(fp_a)); } } \ No newline at end of file diff --git a/src/ff/ec_prime_field.rs b/src/ff/ec_prime_field.rs index 2f88b07cc..624f91c64 100644 --- a/src/ff/ec_prime_field.rs +++ b/src/ff/ec_prime_field.rs @@ -22,6 +22,7 @@ impl Fp25519 { pub const ONE: Self = Self(Scalar::ONE); //must not use with ZERO + #[must_use] pub fn invert(&self) -> Fp25519 { Fp25519(self.0.invert()) } @@ -179,7 +180,7 @@ impl Field for Fp25519 { u128::from_le_bytes(okm) } - ///PRSS uses truncate_from function, we need to expand the u128 using a PRG (Sha256) to a [u8;32] + ///PRSS uses `truncate_from function`, we need to expand the u128 using a PRG (Sha256) to a [u8;32] fn truncate_from>(v: T) -> Self { let hk = Hkdf::::new(None, &v.into().to_le_bytes()); let mut okm = [0u8; 32]; diff --git a/src/protocol/prf_eval/mod.rs b/src/protocol/prf_eval/mod.rs index e3d0cd6a4..895ad524b 100644 --- a/src/protocol/prf_eval/mod.rs +++ b/src/protocol/prf_eval/mod.rs @@ -16,6 +16,8 @@ pub(crate) enum Step { Revealz, } +/// # Errors +/// Propagates errors from multiplications pub async fn compute_match_key_pseudonym( sh_ctx: C, prf_key: AdditiveShare, @@ -26,7 +28,7 @@ pub async fn compute_match_key_pseudonym( { let ctx =sh_ctx.set_total_records(input_match_keys.len()); let futures=input_match_keys.iter().enumerate().map(|(i,x)|eval_dy_prf(ctx.clone(),i.into(),&prf_key,x)); - Ok(seq_try_join_all(sh_ctx.active_work(), futures).await?.iter().map(|&x|u64::from(x)).collect()) + seq_try_join_all(sh_ctx.active_work(), futures).await } @@ -37,7 +39,7 @@ impl From> for AdditiveShare { } /// generates PRF key k as secret sharing over Fp25519 -pub fn gen_prf_key (ctx: C) -> AdditiveShare +pub fn gen_prf_key (ctx: &C) -> AdditiveShare where C: Context, { @@ -49,7 +51,10 @@ pub fn gen_prf_key (ctx: C) -> AdditiveShare /// the input x and k are secret shared over finite field Fp25519, i.e. the scalar field of curve 25519 /// PRF key k is generated using keygen /// In 3IPA, x is the match key -/// eval_DY outputs a u64 as specified in protocol/prf_sharding/mod.rs, all parties learn the output +/// outputs a u64 as specified in `protocol/prf_sharding/mod.rs`, all parties learn the output +/// # Errors +/// Propagates errors from multiplications, reveal and scalar multiplication + pub async fn eval_dy_prf( ctx: C, record_id: RecordId, @@ -77,7 +82,7 @@ pub async fn eval_dy_prf( //compute R^(1/z) to u64 - Ok(u64::from(gr.s_mul(z.invert()))) + Ok(u64::from(gr.s_mul(z.invert())?)) } #[cfg(all(test, unit_test))] @@ -133,18 +138,18 @@ mod test { let records: Vec = vec![ test_input(3), test_input(3), - test_input(23443524523), + test_input(23_443_524_523), test_input(56), - test_input(895764542), - test_input(456764576), + test_input(895_764_542), + test_input(456_764_576), test_input(56), test_input(3), test_input(56), - test_input(23443524523), + test_input(23_443_524_523), ]; //PRF Key Gen - let u = 3216412445u64; + let u = 3_216_412_445u64; let k:Fp25519 = Fp25519::from(u); let expected: Vec=records.iter().map(|&x| TestOutput{match_key_pseudonym: (RP25519::from((x.match_key+k).invert())).into()} ).collect(); From fe3f1308e625ee9f8971da8eb0a4aff03d0d68d0 Mon Sep 17 00:00:00 2001 From: Daniel Masny Date: Mon, 9 Oct 2023 15:49:42 -0700 Subject: [PATCH 13/76] remove comment --- src/ff/curve_points.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/ff/curve_points.rs b/src/ff/curve_points.rs index d04eec535..b8d6a2882 100644 --- a/src/ff/curve_points.rs +++ b/src/ff/curve_points.rs @@ -20,8 +20,6 @@ impl Block for CompressedRistretto { #[derive(Clone, Copy, PartialEq, Debug)] pub struct RP25519(::Storage); -//how to add const ONE: Self = Self(Scalar::ONE); within the struct, do I need to do it via a trait? - /// using compressed ristretto point, Zero is generator of the curve, i.e. g^0 impl SharedValue for RP25519 { type Storage = CompressedRistretto; From 159cd2cf37618f02b8d18d3c7905cc600f24c916 Mon Sep 17 00:00:00 2001 From: Daniel Masny Date: Mon, 9 Oct 2023 16:29:30 -0700 Subject: [PATCH 14/76] adding some of Martins suggestions --- src/ff/curve_points.rs | 159 ++++++++++++++----------------- src/ff/ec_prime_field.rs | 176 ++++++++++++++++------------------- src/ff/mod.rs | 4 +- src/protocol/prf_eval/mod.rs | 111 ++++++++++++---------- 4 files changed, 217 insertions(+), 233 deletions(-) diff --git a/src/ff/curve_points.rs b/src/ff/curve_points.rs index b8d6a2882..2b1f60f94 100644 --- a/src/ff/curve_points.rs +++ b/src/ff/curve_points.rs @@ -1,14 +1,16 @@ +use curve25519_dalek::{ + constants, + ristretto::{CompressedRistretto, RistrettoPoint}, + Scalar, +}; use generic_array::GenericArray; -use curve25519_dalek::{ristretto::{CompressedRistretto, RistrettoPoint},constants, Scalar}; -use typenum::U32; -use sha2::Sha256; use hkdf::Hkdf; - - +use sha2::Sha256; +use typenum::U32; use crate::{ error::Error, - ff::{Serializable,ec_prime_field::Fp25519,Field}, + ff::{ec_prime_field::Fp25519, Field, Serializable}, secret_sharing::{Block, SharedValue}, }; @@ -31,7 +33,7 @@ impl Serializable for RP25519 { type Size = <::Storage as Block>::Size; fn serialize(&self, buf: &mut GenericArray) { - let raw = &self.0.as_bytes()[..buf.len()] ; + let raw = &self.0.as_bytes()[..buf.len()]; buf.copy_from_slice(raw); } @@ -40,7 +42,6 @@ impl Serializable for RP25519 { } } - impl rand::distributions::Distribution for rand::distributions::Standard { fn sample(&self, rng: &mut R) -> RP25519 { //Fp25519(Scalar::random(rng: &mut R)) @@ -50,62 +51,59 @@ impl rand::distributions::Distribution for rand::distributions::Standar } } - impl std::ops::Add for RP25519 { -type Output = Self; + type Output = Self; -fn add(self, rhs: Self) -> Self::Output { - Self((self.0.decompress().unwrap()+rhs.0.decompress().unwrap()).compress()) -} + fn add(self, rhs: Self) -> Self::Output { + Self((self.0.decompress().unwrap() + rhs.0.decompress().unwrap()).compress()) + } } impl std::ops::AddAssign for RP25519 { -#[allow(clippy::assign_op_pattern)] -fn add_assign(&mut self, rhs: Self) { - *self = *self + rhs; -} + #[allow(clippy::assign_op_pattern)] + fn add_assign(&mut self, rhs: Self) { + *self = *self + rhs; + } } impl std::ops::Neg for RP25519 { -type Output = Self; + type Output = Self; -fn neg(self) -> Self::Output { - Self(self.0.decompress().unwrap().neg().compress()) -} + fn neg(self) -> Self::Output { + Self(self.0.decompress().unwrap().neg().compress()) + } } impl std::ops::Sub for RP25519 { -type Output = Self; + type Output = Self; -fn sub(self, rhs: Self) -> Self::Output { - Self((self.0.decompress().unwrap()-rhs.0.decompress().unwrap()).compress()) -} + fn sub(self, rhs: Self) -> Self::Output { + Self((self.0.decompress().unwrap() - rhs.0.decompress().unwrap()).compress()) + } } impl std::ops::SubAssign for RP25519 { -#[allow(clippy::assign_op_pattern)] -fn sub_assign(&mut self, rhs: Self) { - *self = *self - rhs; -} + #[allow(clippy::assign_op_pattern)] + fn sub_assign(&mut self, rhs: Self) { + *self = *self - rhs; + } } - ///Scalar Multiplication ///<'a, 'b> `std::ops::Mul<&'b"` Fp25519 for &'a impl RP25519 { - pub const ONE: Self = Self(constants::RISTRETTO_BASEPOINT_COMPRESSED); /// # Errors /// Propagates errors from decompressing invalid curve point -pub fn s_mul(self, rhs: Fp25519) -> Result { - self.0.decompress().map_or( - Err(Error::DecompressingInvalidCurvePoint), - |x| Ok((x * Scalar::from(rhs)).compress().into()) - ) -} + pub fn s_mul(self, rhs: Fp25519) -> Result { + self.0 + .decompress() + .map_or(Err(Error::DecompressingInvalidCurvePoint), |x| { + Ok((x * Scalar::from(rhs)).compress().into()) + }) + } } - ///do not use impl std::ops::Mul for RP25519 { type Output = Self; @@ -117,8 +115,7 @@ impl std::ops::Mul for RP25519 { ///do not use impl std::ops::MulAssign for RP25519 { - - fn mul_assign(& mut self, _rhs: RP25519) { + fn mul_assign(&mut self, _rhs: RP25519) { panic!("Two curve points cannot be multiplied! Do not use *, *= for RP25519 or secret shares of RP25519"); } } @@ -159,7 +156,7 @@ macro_rules! cp_hash_impl { } } - impl From<$u_type> for RP25519 { + impl From<$u_type> for RP25519 { fn from(s: $u_type) -> Self { let hk = Hkdf::::new(None, &s.to_le_bytes()); let mut okm = [0u8; 32]; @@ -168,23 +165,17 @@ macro_rules! cp_hash_impl { RP25519::deserialize(&okm.into()) } } - } + }; } -cp_hash_impl!( - u64, - 8 -); +cp_hash_impl!(u64, 8); -cp_hash_impl!( - u32, - 4 -); +cp_hash_impl!(u32, 4); /// Daniel had to implement this since Reveal wants it, prefer not to, I dont understand why it is /// actually needed there, maybe to upgrade it to malicious? but it still shouldn't be needed impl Field for RP25519 { - const ONE: RP25519= RP25519::ONE; + const ONE: RP25519 = Self(constants::RISTRETTO_BASEPOINT_COMPRESSED); ///both following methods are based on hashing and do not allow to actually convert elements in Fp25519 /// from or into u128. However it is sufficient to generate random elements in Fp25519 @@ -204,7 +195,6 @@ impl Field for RP25519 { hk.expand(&[], &mut okm).unwrap(); RP25519::deserialize(&okm.into()) } - } impl TryFrom for RP25519 { @@ -213,50 +203,46 @@ impl TryFrom for RP25519 { fn try_from(v: u128) -> Result { let mut bits = [0u8; 32]; bits[..].copy_from_slice(&v.to_le_bytes()); - let f: RP25519=RP25519::ONE; + let f: RP25519 = RP25519::ONE; f.serialize((&mut bits).into()); Ok(f) } } - - - #[cfg(all(test, unit_test))] mod test { - use generic_array::GenericArray; - use crate::ff::curve_points::RP25519; - use crate::ff::Serializable; - use typenum::U32; use curve25519_dalek::scalar::Scalar; + use generic_array::GenericArray; use rand::{thread_rng, Rng}; - use crate::ff::ec_prime_field::Fp25519; - use crate::secret_sharing::SharedValue; + use typenum::U32; + + use crate::{ + ff::{curve_points::RP25519, ec_prime_field::Fp25519, Serializable, field::Field}, + }; #[test] fn serde_25519() { - let input:[u8;32] = [ - 0x01, 0xff,0x00, 0xff,0x00, 0xff,0x00, 0xff, - 0x00, 0xff,0x00, 0xff,0x00, 0xff,0x00, 0xff, - 0x00, 0xff,0x00, 0xff,0x00, 0xff,0x00, 0xff, - 0x00, 0xff,0x00, 0xff,0x00, 0x00,0x00, 0x00 + let input: [u8; 32] = [ + 0x01, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, + 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, + 0x00, 0x00, 0x00, 0x00, ]; - let mut output: GenericArray = [0u8;32].into(); + let mut output: GenericArray = [0u8; 32].into(); let a = RP25519::deserialize(&input.into()); - assert_eq!(a.0.as_bytes()[..32],input); + assert_eq!(a.0.as_bytes()[..32], input); a.serialize(&mut output); - assert_eq!(a.0.as_bytes()[..32],output.as_slice()[..32]); - assert_eq!(input,output.as_slice()[..32]); + assert_eq!(a.0.as_bytes()[..32], output.as_slice()[..32]); + assert_eq!(input, output.as_slice()[..32]); } #[test] fn scalar_to_point() { let a = Scalar::ONE; - let b : RP25519 = a.into(); - let d : Fp25519 = a.into(); - let c : RP25519 = RP25519::from(d); - assert_eq!(b,RP25519::ZERO); - assert_eq!(c,RP25519::ZERO); + let b: RP25519 = a.into(); + let d: Fp25519 = a.into(); + let c: RP25519 = RP25519::from(d); + assert_eq!(b, RP25519::ONE); + assert_eq!(c, RP25519::ONE); } #[test] @@ -264,24 +250,23 @@ mod test { let mut rng = thread_rng(); let fp_a = rng.gen::(); let fp_b = rng.gen::(); - let fp_c = fp_a+fp_b; - let fp_d = RP25519::from(fp_a)+RP25519::from(fp_b); + let fp_c = fp_a + fp_b; + let fp_d = RP25519::from(fp_a) + RP25519::from(fp_b); assert_eq!(fp_d, RP25519::from(fp_c)); - assert_ne!(fp_d, RP25519::ZERO); + assert_ne!(fp_d, RP25519::ONE); let fp_e = rng.gen::(); - let fp_f=rng.gen::(); - let fp_g =fp_e*fp_f; + let fp_f = rng.gen::(); + let fp_g = fp_e * fp_f; let fp_h = RP25519::from(fp_e).s_mul(fp_f).unwrap(); - assert_eq!(fp_h,RP25519::from(fp_g)); - assert_ne!(fp_h, RP25519::ZERO); + assert_eq!(fp_h, RP25519::from(fp_g)); + assert_ne!(fp_h, RP25519::ONE); } #[test] fn curve_point_to_hash() { let mut rng = thread_rng(); let fp_a = rng.gen::(); - assert_ne!(0u64,u64::from(fp_a)); - assert_ne!(0u32,u32::from(fp_a)); + assert_ne!(0u64, u64::from(fp_a)); + assert_ne!(0u32, u32::from(fp_a)); } - -} \ No newline at end of file +} diff --git a/src/ff/ec_prime_field.rs b/src/ff/ec_prime_field.rs index 624f91c64..6613116f6 100644 --- a/src/ff/ec_prime_field.rs +++ b/src/ff/ec_prime_field.rs @@ -1,12 +1,12 @@ -use generic_array::GenericArray; use curve25519_dalek::scalar::Scalar; +use generic_array::GenericArray; +use hkdf::Hkdf; +use sha2::Sha256; //use rand_core::RngCore; use typenum::U32; -use sha2::Sha256; -use hkdf::Hkdf; use crate::{ - ff::{Serializable, Field}, + ff::{Field, Serializable}, secret_sharing::{Block, SharedValue}, }; @@ -17,7 +17,6 @@ impl Block for Scalar { #[derive(Clone, Copy, PartialEq, Debug)] pub struct Fp25519(::Storage); - impl Fp25519 { pub const ONE: Self = Self(Scalar::ONE); @@ -26,10 +25,8 @@ impl Fp25519 { pub fn invert(&self) -> Fp25519 { Fp25519(self.0.invert()) } - } - impl SharedValue for Fp25519 { type Storage = Scalar; const BITS: u32 = 256; @@ -46,7 +43,7 @@ impl Serializable for Fp25519 { type Size = <::Storage as Block>::Size; fn serialize(&self, buf: &mut GenericArray) { - let raw = &self.0.as_bytes()[..buf.len()] ; + let raw = &self.0.as_bytes()[..buf.len()]; buf.copy_from_slice(raw); } @@ -58,7 +55,6 @@ impl Serializable for Fp25519 { } } - impl rand::distributions::Distribution for rand::distributions::Standard { fn sample(&self, rng: &mut R) -> Fp25519 { let mut scalar_bytes = [0u8; 32]; @@ -69,61 +65,59 @@ impl rand::distributions::Distribution for rand::distributions::Standar } } - impl std::ops::Add for Fp25519 { -type Output = Self; + type Output = Self; -fn add(self, rhs: Self) -> Self::Output { - Self(self.0+rhs.0) -} + fn add(self, rhs: Self) -> Self::Output { + Self(self.0 + rhs.0) + } } impl std::ops::AddAssign for Fp25519 { -#[allow(clippy::assign_op_pattern)] -fn add_assign(&mut self, rhs: Self) { - *self = *self + rhs; -} + #[allow(clippy::assign_op_pattern)] + fn add_assign(&mut self, rhs: Self) { + *self = *self + rhs; + } } impl std::ops::Neg for Fp25519 { -type Output = Self; + type Output = Self; -fn neg(self) -> Self::Output { - Self(self.0.neg()) -} + fn neg(self) -> Self::Output { + Self(self.0.neg()) + } } impl std::ops::Sub for Fp25519 { -type Output = Self; + type Output = Self; -fn sub(self, rhs: Self) -> Self::Output { - Self(self.0- rhs.0) -} + fn sub(self, rhs: Self) -> Self::Output { + Self(self.0 - rhs.0) + } } impl std::ops::SubAssign for Fp25519 { -#[allow(clippy::assign_op_pattern)] -fn sub_assign(&mut self, rhs: Self) { - *self = *self - rhs; -} + #[allow(clippy::assign_op_pattern)] + fn sub_assign(&mut self, rhs: Self) { + *self = *self - rhs; + } } impl std::ops::Mul for Fp25519 { -type Output = Self; + type Output = Self; -fn mul(self, rhs: Self) -> Self::Output { - Self(self.0 * rhs.0) -} + fn mul(self, rhs: Self) -> Self::Output { + Self(self.0 * rhs.0) + } } impl std::ops::MulAssign for Fp25519 { -#[allow(clippy::assign_op_pattern)] -fn mul_assign(&mut self, rhs: Self) { - *self = *self * rhs; -} + #[allow(clippy::assign_op_pattern)] + fn mul_assign(&mut self, rhs: Self) { + *self = *self * rhs; + } } - impl From for Fp25519 { fn from(s: Scalar) -> Self { Fp25519(s) @@ -142,7 +136,7 @@ macro_rules! sc_hash_impl { } } - impl From<$u_type> for Fp25519 { + impl From<$u_type> for Fp25519 { fn from(s: $u_type) -> Self { let hk = Hkdf::::new(None, &s.to_le_bytes()); let mut okm = [0u8; 32]; @@ -151,24 +145,16 @@ macro_rules! sc_hash_impl { Fp25519::deserialize(&okm.into()) } } - } + }; } +sc_hash_impl!(u64, 8); -sc_hash_impl!( - u64, - 8 -); - -sc_hash_impl!( - u32, - 4 -); - +sc_hash_impl!(u32, 4); /// Daniel had to implement this since PRSS wants it, prefer not to impl Field for Fp25519 { - const ONE: Fp25519= Fp25519::ONE; + const ONE: Fp25519 = Fp25519::ONE; ///both following methods are based on hashing and do not allow to actually convert elements in Fp25519 /// from or into u128. However it is sufficient to generate random elements in Fp25519 @@ -188,7 +174,6 @@ impl Field for Fp25519 { hk.expand(&[], &mut okm).unwrap(); Fp25519::deserialize(&okm.into()) } - } impl TryFrom for Fp25519 { @@ -197,7 +182,7 @@ impl TryFrom for Fp25519 { fn try_from(v: u128) -> Result { let mut bits = [0u8; 32]; bits[..].copy_from_slice(&v.to_le_bytes()); - let f: Fp25519=Fp25519::ONE; + let f: Fp25519 = Fp25519::ONE; f.serialize((&mut bits).into()); Ok(f) } @@ -205,76 +190,73 @@ impl TryFrom for Fp25519 { #[cfg(all(test, unit_test))] mod test { - use generic_array::GenericArray; - use crate::ff::ec_prime_field::Fp25519; - use crate::ff::Serializable; - use typenum::U32; use curve25519_dalek::scalar::Scalar; + use generic_array::GenericArray; use rand::{thread_rng, Rng}; - use crate::secret_sharing::SharedValue; + use typenum::U32; + + use crate::{ + ff::{ec_prime_field::Fp25519, Serializable}, + secret_sharing::SharedValue, + }; #[test] fn serde_25519() { - let input:[u8;32] = [ - 0x01, 0xff,0x00, 0xff,0x00, 0xff,0x00, 0xff, - 0x00, 0xff,0x00, 0xff,0x00, 0xff,0x00, 0xff, - 0x00, 0xff,0x00, 0xff,0x00, 0xff,0x00, 0xff, - 0x00, 0xff,0x00, 0xff,0x00, 0x00,0x00, 0x00 + let input: [u8; 32] = [ + 0x01, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, + 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, + 0x00, 0x00, 0x00, 0x00, ]; - let mut output: GenericArray = [0u8;32].into(); + let mut output: GenericArray = [0u8; 32].into(); let a = Fp25519::deserialize(&input.into()); - assert_eq!(a.0.as_bytes()[..32],input); + assert_eq!(a.0.as_bytes()[..32], input); a.serialize(&mut output); - assert_eq!(a.0.as_bytes()[..32],output.as_slice()[..32]); - assert_eq!(input,output.as_slice()[..32]); + assert_eq!(a.0.as_bytes()[..32], output.as_slice()[..32]); + assert_eq!(input, output.as_slice()[..32]); } // These are just simple arithmetic tests since arithmetics are checked by curve25519_dalek #[test] fn simple_arithmetics_25519() { let a = Fp25519(Scalar::from_bytes_mod_order([ - 0x02, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00, - 0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00, - 0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00, - 0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00 + 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, ])); let b = Fp25519(Scalar::from_bytes_mod_order([ - 0x03, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00, - 0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00, - 0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00, - 0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00 + 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, ])); let d = Fp25519(Scalar::from_bytes_mod_order([ - 0x05, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00, - 0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00, - 0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00, - 0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00 + 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, ])); let e = Fp25519(Scalar::from_bytes_mod_order([ - 0x06, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00, - 0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00, - 0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00, - 0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00 + 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, ])); - let cc = b-a; - let dc = a+b; - let ec = a*b; - assert_eq!(cc,Fp25519::ONE); - assert_eq!(dc,d); - assert_eq!(ec,e); + let cc = b - a; + let dc = a + b; + let ec = a * b; + assert_eq!(cc, Fp25519::ONE); + assert_eq!(dc, d); + assert_eq!(ec, e); } #[test] - fn simple_random_25519(){ + fn simple_random_25519() { let mut rng = thread_rng(); - assert_ne!(Fp25519::ZERO,rng.gen::()); + assert_ne!(Fp25519::ZERO, rng.gen::()); } #[test] - fn invert_25519(){ + fn invert_25519() { let mut rng = thread_rng(); - let a=rng.gen::(); - let ia=a.invert(); - assert_eq!(a*ia, Fp25519(Scalar::ONE)); + let a = rng.gen::(); + let ia = a.invert(); + assert_eq!(a * ia, Fp25519(Scalar::ONE)); } -} \ No newline at end of file +} diff --git a/src/ff/mod.rs b/src/ff/mod.rs index b26596086..c858aaf93 100644 --- a/src/ff/mod.rs +++ b/src/ff/mod.rs @@ -2,11 +2,11 @@ // // This is where we store arithmetic shared secret data models. +pub mod curve_points; +pub mod ec_prime_field; mod field; mod galois_field; mod prime_field; -pub mod ec_prime_field; -pub mod curve_points; use std::ops::{Add, AddAssign, Sub, SubAssign}; diff --git a/src/protocol/prf_eval/mod.rs b/src/protocol/prf_eval/mod.rs index 895ad524b..ae43e55a1 100644 --- a/src/protocol/prf_eval/mod.rs +++ b/src/protocol/prf_eval/mod.rs @@ -1,11 +1,17 @@ +use ipa_macros::Step; + use crate::{ error::Error, - ff::{ec_prime_field::Fp25519, curve_points::RP25519}, - protocol::{context::Context, RecordId, prss::SharedRandomness, basics::Reveal, basics::SecureMul}, - secret_sharing::{replicated::{semi_honest::AdditiveShare,ReplicatedSecretSharing}}, + ff::{curve_points::RP25519, ec_prime_field::Fp25519}, + protocol::{ + basics::{Reveal, SecureMul}, + context::Context, + prss::SharedRandomness, + RecordId, + }, + secret_sharing::replicated::{semi_honest::AdditiveShare, ReplicatedSecretSharing}, seq_join::seq_try_join_all, }; -use ipa_macros::Step; #[derive(Step)] pub(crate) enum Step { @@ -23,30 +29,33 @@ pub async fn compute_match_key_pseudonym( prf_key: AdditiveShare, input_match_keys: Vec>, ) -> Result, Error> - where - C: Context, +where + C: Context, { - let ctx =sh_ctx.set_total_records(input_match_keys.len()); - let futures=input_match_keys.iter().enumerate().map(|(i,x)|eval_dy_prf(ctx.clone(),i.into(),&prf_key,x)); + let ctx = sh_ctx.set_total_records(input_match_keys.len()); + let futures = input_match_keys + .iter() + .enumerate() + .map(|(i, x)| eval_dy_prf(ctx.clone(), i.into(), &prf_key, x)); seq_try_join_all(sh_ctx.active_work(), futures).await } - impl From> for AdditiveShare { fn from(s: AdditiveShare) -> Self { - AdditiveShare::new(RP25519::from(s.left()),RP25519::from(s.right())) + AdditiveShare::new(RP25519::from(s.left()), RP25519::from(s.right())) } } /// generates PRF key k as secret sharing over Fp25519 -pub fn gen_prf_key (ctx: &C) -> AdditiveShare - where - C: Context, +pub fn gen_prf_key(ctx: &C) -> AdditiveShare +where + C: Context, { - ctx.narrow(&Step::PRFKeyGen).prss().generate_replicated(u128::MAX-100u128) + ctx.narrow(&Step::PRFKeyGen) + .prss() + .generate_replicated(u128::MAX - 100u128) } - /// evaluates the Dodis-Yampolski PRF g^(1/(k+x)) /// the input x and k are secret shared over finite field Fp25519, i.e. the scalar field of curve 25519 /// PRF key k is generated using keygen @@ -61,26 +70,29 @@ pub async fn eval_dy_prf( k: &AdditiveShare, x: &AdditiveShare, ) -> Result - where - C: Context, +where + C: Context, { - let sh_r: AdditiveShare = ctx.narrow(&Step::GenRandomMask).prss().generate_replicated(record_id); + let sh_r: AdditiveShare = ctx + .narrow(&Step::GenRandomMask) + .prss() + .generate_replicated(record_id); //compute (g^left, g^right) let sh_gr = AdditiveShare::::from(sh_r.clone()); //compute x+k - let mut y =x+k; + let mut y = x + k; //compute y <- r*y - y = y.multiply(&sh_r, ctx.narrow(&Step::MultMaskWithPRFInput), record_id).await?; + y = y + .multiply(&sh_r, ctx.narrow(&Step::MultMaskWithPRFInput), record_id) + .await?; //reconstruct (z,R) let gr: RP25519 = sh_gr.reveal(ctx.narrow(&Step::RevealR), record_id).await?; let z = y.reveal(ctx.narrow(&Step::Revealz), record_id).await?; - - //compute R^(1/z) to u64 Ok(u64::from(gr.s_mul(z.invert())?)) } @@ -88,12 +100,13 @@ pub async fn eval_dy_prf( #[cfg(all(test, unit_test))] mod test { use rand::Rng; + use crate::{ + ff::{curve_points::RP25519, ec_prime_field::Fp25519}, + protocol::prf_eval::compute_match_key_pseudonym, + secret_sharing::{replicated::semi_honest::AdditiveShare, IntoShares}, test_executor::run, - test_fixture::{TestWorld, Reconstruct, Runner}, - ff::{ec_prime_field::Fp25519, curve_points::RP25519}, - secret_sharing::{IntoShares,replicated::semi_honest::AdditiveShare}, - protocol::prf_eval::{compute_match_key_pseudonym}, + test_fixture::{Reconstruct, Runner, TestWorld}, }; #[derive(Copy, Clone)] @@ -106,29 +119,30 @@ mod test { match_key_pseudonym: u64, } - fn test_input( mk: u64) -> ShuffledTestInput { + fn test_input(mk: u64) -> ShuffledTestInput { ShuffledTestInput { match_key: Fp25519::from(mk), } } - impl IntoShares> for ShuffledTestInput - { + impl IntoShares> for ShuffledTestInput { fn share_with(self, rng: &mut R) -> [AdditiveShare; 3] { self.match_key.share_with(rng) } } - impl Reconstruct for [&u64; 3] { fn reconstruct(&self) -> TestOutput { - TestOutput{ - match_key_pseudonym: if *self[0]==*self[1] && *self[0]==*self[2] {*self[0]} else {0u64}, + TestOutput { + match_key_pseudonym: if *self[0] == *self[1] && *self[0] == *self[2] { + *self[0] + } else { + 0u64 + }, } } } - #[test] fn semi_honest() { run(|| async move { @@ -146,29 +160,32 @@ mod test { test_input(3), test_input(56), test_input(23_443_524_523), - ]; + ]; //PRF Key Gen let u = 3_216_412_445u64; - let k:Fp25519 = Fp25519::from(u); + let k: Fp25519 = Fp25519::from(u); - let expected: Vec=records.iter().map(|&x| TestOutput{match_key_pseudonym: (RP25519::from((x.match_key+k).invert())).into()} ).collect(); + let expected: Vec = records + .iter() + .map(|&x| TestOutput { + match_key_pseudonym: (RP25519::from((x.match_key + k).invert())).into(), + }) + .collect(); let result: Vec<_> = world - .semi_honest((records.into_iter(),k), |ctx, (input_match_keys,prf_key)| async move { - compute_match_key_pseudonym::<_>( - ctx, - prf_key, - input_match_keys, - ) - .await - .unwrap() - }) + .semi_honest( + (records.into_iter(), k), + |ctx, (input_match_keys, prf_key)| async move { + compute_match_key_pseudonym::<_>(ctx, prf_key, input_match_keys) + .await + .unwrap() + }, + ) .await .reconstruct(); assert_eq!(result, expected); assert_eq!(result[0], result[1]); }); } - -} \ No newline at end of file +} From 301a6e56d5d80445fac47370a3c7393a4cc5a887 Mon Sep 17 00:00:00 2001 From: Daniel Masny Date: Mon, 16 Oct 2023 12:14:20 -0700 Subject: [PATCH 15/76] Alex suggestions, serialize, deserialize --- src/ff/curve_points.rs | 3 +-- src/ff/ec_prime_field.rs | 8 ++------ 2 files changed, 3 insertions(+), 8 deletions(-) diff --git a/src/ff/curve_points.rs b/src/ff/curve_points.rs index 2b1f60f94..38908dadf 100644 --- a/src/ff/curve_points.rs +++ b/src/ff/curve_points.rs @@ -33,8 +33,7 @@ impl Serializable for RP25519 { type Size = <::Storage as Block>::Size; fn serialize(&self, buf: &mut GenericArray) { - let raw = &self.0.as_bytes()[..buf.len()]; - buf.copy_from_slice(raw); + *buf.as_mut() = self.0.to_bytes(); } fn deserialize(buf: &GenericArray) -> Self { diff --git a/src/ff/ec_prime_field.rs b/src/ff/ec_prime_field.rs index 6613116f6..d7348ca1b 100644 --- a/src/ff/ec_prime_field.rs +++ b/src/ff/ec_prime_field.rs @@ -43,15 +43,11 @@ impl Serializable for Fp25519 { type Size = <::Storage as Block>::Size; fn serialize(&self, buf: &mut GenericArray) { - let raw = &self.0.as_bytes()[..buf.len()]; - buf.copy_from_slice(raw); + *buf.as_mut() = self.0.to_bytes() } fn deserialize(buf: &GenericArray) -> Self { - let mut buf_to = [0u8; 32]; - buf_to[..buf.len()].copy_from_slice(buf); - - Fp25519(Scalar::from_bytes_mod_order(buf_to)) + Fp25519(Scalar::from_bytes_mod_order((*buf).into())) } } From 9a1fa7cbe1040d29e1472a51f96cbdb00fab84db Mon Sep 17 00:00:00 2001 From: danielmasny <46358615+danielmasny@users.noreply.github.com> Date: Mon, 16 Oct 2023 12:19:22 -0700 Subject: [PATCH 16/76] Update src/ff/curve_points.rs Co-authored-by: Alex Koshelev --- src/ff/curve_points.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ff/curve_points.rs b/src/ff/curve_points.rs index 38908dadf..bddc71d50 100644 --- a/src/ff/curve_points.rs +++ b/src/ff/curve_points.rs @@ -119,7 +119,7 @@ impl std::ops::MulAssign for RP25519 { } } -impl From for RP25519 { +impl From<&Scalar> for RP25519 { fn from(s: Scalar) -> Self { RP25519(RistrettoPoint::mul_base(&s).compress()) } From 8386d243f0e442c6489f0b5c7e3ce3ea4435f56d Mon Sep 17 00:00:00 2001 From: Daniel Masny Date: Mon, 16 Oct 2023 12:29:06 -0700 Subject: [PATCH 17/76] Alex suggestions, simplify u32, u64 macros --- src/ff/curve_points.rs | 8 ++++---- src/ff/ec_prime_field.rs | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/ff/curve_points.rs b/src/ff/curve_points.rs index 38908dadf..0890903a5 100644 --- a/src/ff/curve_points.rs +++ b/src/ff/curve_points.rs @@ -144,11 +144,11 @@ impl From for CompressedRistretto { } macro_rules! cp_hash_impl { - ( $u_type:ty, $byte_size:literal) => { + ( $u_type:ty) => { impl From for $u_type { fn from(s: RP25519) -> Self { let hk = Hkdf::::new(None, s.0.as_bytes()); - let mut okm = [0u8; $byte_size]; + let mut okm = <$u_type>::MIN.to_le_bytes(); //error invalid length from expand only happens when okm is very large hk.expand(&[], &mut okm).unwrap(); <$u_type>::from_le_bytes(okm) @@ -167,9 +167,9 @@ macro_rules! cp_hash_impl { }; } -cp_hash_impl!(u64, 8); +cp_hash_impl!(u64); -cp_hash_impl!(u32, 4); +cp_hash_impl!(u32); /// Daniel had to implement this since Reveal wants it, prefer not to, I dont understand why it is /// actually needed there, maybe to upgrade it to malicious? but it still shouldn't be needed diff --git a/src/ff/ec_prime_field.rs b/src/ff/ec_prime_field.rs index d7348ca1b..9234cb346 100644 --- a/src/ff/ec_prime_field.rs +++ b/src/ff/ec_prime_field.rs @@ -121,11 +121,11 @@ impl From for Fp25519 { } macro_rules! sc_hash_impl { - ( $u_type:ty, $byte_size:literal) => { + ( $u_type:ty) => { impl From for $u_type { fn from(s: Fp25519) -> Self { let hk = Hkdf::::new(None, s.0.as_bytes()); - let mut okm = [0u8; $byte_size]; + let mut okm = <$u_type>::MIN.to_le_bytes(); //error invalid length from expand only happens when okm is very large hk.expand(&[], &mut okm).unwrap(); <$u_type>::from_le_bytes(okm) @@ -144,9 +144,9 @@ macro_rules! sc_hash_impl { }; } -sc_hash_impl!(u64, 8); +sc_hash_impl!(u64); -sc_hash_impl!(u32, 4); +sc_hash_impl!(u32); /// Daniel had to implement this since PRSS wants it, prefer not to impl Field for Fp25519 { From 5dc07a070a25670ff332a5fd20907c286abd3eec Mon Sep 17 00:00:00 2001 From: danielmasny <46358615+danielmasny@users.noreply.github.com> Date: Mon, 16 Oct 2023 13:06:29 -0700 Subject: [PATCH 18/76] Update src/ff/curve_points.rs Co-authored-by: Alex Koshelev --- src/ff/curve_points.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ff/curve_points.rs b/src/ff/curve_points.rs index bddc71d50..5ce8bf0bf 100644 --- a/src/ff/curve_points.rs +++ b/src/ff/curve_points.rs @@ -125,7 +125,7 @@ impl From<&Scalar> for RP25519 { } } -impl From for RP25519 { +impl From<&Fp25519> for RP25519 { fn from(s: Fp25519) -> Self { RP25519(RistrettoPoint::mul_base(&s.into()).compress()) } From ea8da0d888a48032a0f517eecec7462215779db8 Mon Sep 17 00:00:00 2001 From: Daniel Masny Date: Mon, 16 Oct 2023 15:17:02 -0700 Subject: [PATCH 19/76] simplify serde test --- src/ff/curve_points.rs | 102 ++++++++++----------------------------- src/ff/ec_prime_field.rs | 23 ++++----- 2 files changed, 34 insertions(+), 91 deletions(-) diff --git a/src/ff/curve_points.rs b/src/ff/curve_points.rs index 76657874a..bf09072ef 100644 --- a/src/ff/curve_points.rs +++ b/src/ff/curve_points.rs @@ -10,7 +10,7 @@ use typenum::U32; use crate::{ error::Error, - ff::{ec_prime_field::Fp25519, Field, Serializable}, + ff::{ec_prime_field::Fp25519, Serializable}, secret_sharing::{Block, SharedValue}, }; @@ -37,16 +37,7 @@ impl Serializable for RP25519 { } fn deserialize(buf: &GenericArray) -> Self { - RP25519(CompressedRistretto::from_slice(buf).unwrap()) - } -} - -impl rand::distributions::Distribution for rand::distributions::Standard { - fn sample(&self, rng: &mut R) -> RP25519 { - //Fp25519(Scalar::random(rng: &mut R)) - let mut scalar_bytes = [0u8; 64]; - rng.fill_bytes(&mut scalar_bytes); - RP25519(RistrettoPoint::from_uniform_bytes(&scalar_bytes).compress()) + RP25519(CompressedRistretto((*buf).into())) } } @@ -91,7 +82,6 @@ impl std::ops::SubAssign for RP25519 { ///Scalar Multiplication ///<'a, 'b> `std::ops::Mul<&'b"` Fp25519 for &'a impl RP25519 { - /// # Errors /// Propagates errors from decompressing invalid curve point pub fn s_mul(self, rhs: Fp25519) -> Result { @@ -119,13 +109,13 @@ impl std::ops::MulAssign for RP25519 { } } -impl From<&Scalar> for RP25519 { +impl From for RP25519 { fn from(s: Scalar) -> Self { RP25519(RistrettoPoint::mul_base(&s).compress()) } } -impl From<&Fp25519> for RP25519 { +impl From for RP25519 { fn from(s: Fp25519) -> Self { RP25519(RistrettoPoint::mul_base(&s.into()).compress()) } @@ -154,84 +144,42 @@ macro_rules! cp_hash_impl { <$u_type>::from_le_bytes(okm) } } - - impl From<$u_type> for RP25519 { - fn from(s: $u_type) -> Self { - let hk = Hkdf::::new(None, &s.to_le_bytes()); - let mut okm = [0u8; 32]; - //error invalid length from expand only happens when okm is very large - hk.expand(&[], &mut okm).unwrap(); - RP25519::deserialize(&okm.into()) - } - } }; } +cp_hash_impl!(u128); + cp_hash_impl!(u64); +#[cfg(test)] cp_hash_impl!(u32); -/// Daniel had to implement this since Reveal wants it, prefer not to, I dont understand why it is -/// actually needed there, maybe to upgrade it to malicious? but it still shouldn't be needed -impl Field for RP25519 { - const ONE: RP25519 = Self(constants::RISTRETTO_BASEPOINT_COMPRESSED); - - ///both following methods are based on hashing and do not allow to actually convert elements in Fp25519 - /// from or into u128. However it is sufficient to generate random elements in Fp25519 - fn as_u128(&self) -> u128 { - let hk = Hkdf::::new(None, self.0.as_bytes()); - let mut okm = [0u8; 16]; - //error invalid length from expand only happens when okm is very large - hk.expand(&[], &mut okm).unwrap(); - u128::from_le_bytes(okm) - } - - ///PRSS uses `truncate_from function`, we need to expand the u128 using a PRG (Sha256) to a [u8;32] - fn truncate_from>(v: T) -> Self { - let hk = Hkdf::::new(None, &v.into().to_le_bytes()); - let mut okm = [0u8; 32]; - //error invalid length from expand only happens when okm is very large - hk.expand(&[], &mut okm).unwrap(); - RP25519::deserialize(&okm.into()) - } -} - -impl TryFrom for RP25519 { - type Error = crate::error::Error; - - fn try_from(v: u128) -> Result { - let mut bits = [0u8; 32]; - bits[..].copy_from_slice(&v.to_le_bytes()); - let f: RP25519 = RP25519::ONE; - f.serialize((&mut bits).into()); - Ok(f) +#[cfg(test)] +impl rand::distributions::Distribution for rand::distributions::Standard { + fn sample(&self, rng: &mut R) -> RP25519 { + let mut scalar_bytes = [0u8; 64]; + rng.fill_bytes(&mut scalar_bytes); + RP25519(RistrettoPoint::from_uniform_bytes(&scalar_bytes).compress()) } } #[cfg(all(test, unit_test))] mod test { - use curve25519_dalek::scalar::Scalar; + use curve25519_dalek::{constants, scalar::Scalar}; use generic_array::GenericArray; use rand::{thread_rng, Rng}; use typenum::U32; - use crate::{ - ff::{curve_points::RP25519, ec_prime_field::Fp25519, Serializable, field::Field}, - }; + use crate::ff::{curve_points::RP25519, ec_prime_field::Fp25519, Serializable}; #[test] fn serde_25519() { - let input: [u8; 32] = [ - 0x01, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, - 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, - 0x00, 0x00, 0x00, 0x00, - ]; - let mut output: GenericArray = [0u8; 32].into(); - let a = RP25519::deserialize(&input.into()); - assert_eq!(a.0.as_bytes()[..32], input); - a.serialize(&mut output); - assert_eq!(a.0.as_bytes()[..32], output.as_slice()[..32]); - assert_eq!(input, output.as_slice()[..32]); + let mut rng = thread_rng(); + let input = rng.gen::(); + let mut a: GenericArray = [0u8; 32].into(); + input.serialize(&mut a); + let output = RP25519::deserialize(&a); + assert_eq!(input, output); } #[test] @@ -240,8 +188,8 @@ mod test { let b: RP25519 = a.into(); let d: Fp25519 = a.into(); let c: RP25519 = RP25519::from(d); - assert_eq!(b, RP25519::ONE); - assert_eq!(c, RP25519::ONE); + assert_eq!(b, RP25519(constants::RISTRETTO_BASEPOINT_COMPRESSED)); + assert_eq!(c, RP25519(constants::RISTRETTO_BASEPOINT_COMPRESSED)); } #[test] @@ -252,13 +200,13 @@ mod test { let fp_c = fp_a + fp_b; let fp_d = RP25519::from(fp_a) + RP25519::from(fp_b); assert_eq!(fp_d, RP25519::from(fp_c)); - assert_ne!(fp_d, RP25519::ONE); + assert_ne!(fp_d, RP25519(constants::RISTRETTO_BASEPOINT_COMPRESSED)); let fp_e = rng.gen::(); let fp_f = rng.gen::(); let fp_g = fp_e * fp_f; let fp_h = RP25519::from(fp_e).s_mul(fp_f).unwrap(); assert_eq!(fp_h, RP25519::from(fp_g)); - assert_ne!(fp_h, RP25519::ONE); + assert_ne!(fp_h, RP25519(constants::RISTRETTO_BASEPOINT_COMPRESSED)); } #[test] diff --git a/src/ff/ec_prime_field.rs b/src/ff/ec_prime_field.rs index 9234cb346..e67ffa235 100644 --- a/src/ff/ec_prime_field.rs +++ b/src/ff/ec_prime_field.rs @@ -2,7 +2,6 @@ use curve25519_dalek::scalar::Scalar; use generic_array::GenericArray; use hkdf::Hkdf; use sha2::Sha256; -//use rand_core::RngCore; use typenum::U32; use crate::{ @@ -23,6 +22,7 @@ impl Fp25519 { //must not use with ZERO #[must_use] pub fn invert(&self) -> Fp25519 { + assert_ne!(*self, Fp25519::ZERO); Fp25519(self.0.invert()) } } @@ -56,8 +56,6 @@ impl rand::distributions::Distribution for rand::distributions::Standar let mut scalar_bytes = [0u8; 32]; rng.fill_bytes(&mut scalar_bytes); Fp25519(Scalar::from_bytes_mod_order(scalar_bytes)) - //not needed since above has sufficiently small bias - //Fp25519(Scalar::from_bytes_mod_order(&scalar_bytes)) } } @@ -144,8 +142,10 @@ macro_rules! sc_hash_impl { }; } +#[cfg(test)] sc_hash_impl!(u64); +#[cfg(test)] sc_hash_impl!(u32); /// Daniel had to implement this since PRSS wants it, prefer not to @@ -198,17 +198,12 @@ mod test { #[test] fn serde_25519() { - let input: [u8; 32] = [ - 0x01, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, - 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, - 0x00, 0x00, 0x00, 0x00, - ]; - let mut output: GenericArray = [0u8; 32].into(); - let a = Fp25519::deserialize(&input.into()); - assert_eq!(a.0.as_bytes()[..32], input); - a.serialize(&mut output); - assert_eq!(a.0.as_bytes()[..32], output.as_slice()[..32]); - assert_eq!(input, output.as_slice()[..32]); + let mut rng = thread_rng(); + let input = rng.gen::(); + let mut a: GenericArray = [0u8; 32].into(); + input.serialize(&mut a); + let output = Fp25519::deserialize(&a); + assert_eq!(input, output); } // These are just simple arithmetic tests since arithmetics are checked by curve25519_dalek From bcea6c6fffa98562d02f434431be44b9d8b7fa0e Mon Sep 17 00:00:00 2001 From: Daniel Masny Date: Mon, 16 Oct 2023 15:21:42 -0700 Subject: [PATCH 20/76] simplify serde test --- src/ff/ec_prime_field.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/ff/ec_prime_field.rs b/src/ff/ec_prime_field.rs index e67ffa235..d0ff48b72 100644 --- a/src/ff/ec_prime_field.rs +++ b/src/ff/ec_prime_field.rs @@ -19,7 +19,8 @@ pub struct Fp25519(::Storage); impl Fp25519 { pub const ONE: Self = Self(Scalar::ONE); - //must not use with ZERO + ///# Panics + /// Panics when self is zero #[must_use] pub fn invert(&self) -> Fp25519 { assert_ne!(*self, Fp25519::ZERO); @@ -43,7 +44,7 @@ impl Serializable for Fp25519 { type Size = <::Storage as Block>::Size; fn serialize(&self, buf: &mut GenericArray) { - *buf.as_mut() = self.0.to_bytes() + *buf.as_mut() = self.0.to_bytes(); } fn deserialize(buf: &GenericArray) -> Self { From 8bca6609c4813763f2d9412b79b63773f15bf0ef Mon Sep 17 00:00:00 2001 From: Daniel Masny Date: Mon, 16 Oct 2023 17:57:38 -0700 Subject: [PATCH 21/76] error recursion limit --- src/ff/curve_points.rs | 8 ++-- src/secret_sharing/mod.rs | 47 ++++++++++++++++--- src/secret_sharing/replicated/mod.rs | 4 +- .../replicated/semi_honest/additive_share.rs | 43 ++++++++--------- src/secret_sharing/scheme.rs | 4 +- 5 files changed, 70 insertions(+), 36 deletions(-) diff --git a/src/ff/curve_points.rs b/src/ff/curve_points.rs index bf09072ef..cf182fd69 100644 --- a/src/ff/curve_points.rs +++ b/src/ff/curve_points.rs @@ -11,7 +11,7 @@ use typenum::U32; use crate::{ error::Error, ff::{ec_prime_field::Fp25519, Serializable}, - secret_sharing::{Block, SharedValue}, + secret_sharing::{Block, WeakSharedValue}, }; impl Block for CompressedRistretto { @@ -20,17 +20,17 @@ impl Block for CompressedRistretto { ///ristretto point for curve 25519 #[derive(Clone, Copy, PartialEq, Debug)] -pub struct RP25519(::Storage); +pub struct RP25519(::Storage); /// using compressed ristretto point, Zero is generator of the curve, i.e. g^0 -impl SharedValue for RP25519 { +impl WeakSharedValue for RP25519 { type Storage = CompressedRistretto; const BITS: u32 = 256; const ZERO: Self = Self(constants::RISTRETTO_BASEPOINT_COMPRESSED); } impl Serializable for RP25519 { - type Size = <::Storage as Block>::Size; + type Size = <::Storage as Block>::Size; fn serialize(&self, buf: &mut GenericArray) { *buf.as_mut() = self.0.to_bytes(); diff --git a/src/secret_sharing/mod.rs b/src/secret_sharing/mod.rs index 908a45feb..191ad5df7 100644 --- a/src/secret_sharing/mod.rs +++ b/src/secret_sharing/mod.rs @@ -23,22 +23,33 @@ pub use scheme::{Bitwise, Linear, LinearRefOps, SecretSharing}; use crate::ff::{AddSub, AddSubAssign, Serializable}; +/// Operations supported for weak shared values. +pub trait Additive: +AddSub ++ AddSubAssign ++ Neg +{ +} + +impl Additive for T where + T: AddSub + + AddSubAssign + + Neg +{ +} + /// Operations supported for shared values. pub trait Arithmetic: - AddSub - + AddSubAssign + Additive + Mul + MulAssign - + Neg { } impl Arithmetic for T where - T: AddSub - + AddSubAssign + T: Additive + Mul + MulAssign - + Neg { } @@ -48,6 +59,16 @@ pub trait Block: Sized + Copy + Debug { type Size: ArrayLength; } +pub trait WeakSharedValue: +Clone + Copy + PartialEq + Debug + Send + Sync + Sized + Additive + Serializable + 'static +{ + type Storage: Block; + + const BITS: u32; + + const ZERO: Self; +} + pub trait SharedValue: Clone + Copy + PartialEq + Debug + Send + Sync + Sized + Arithmetic + Serializable + 'static { @@ -58,10 +79,22 @@ pub trait SharedValue: const ZERO: Self; } +impl WeakSharedValue for T where + T: SharedValue, +{ + type Storage = T::Storage; + + const BITS: u32 = T::BITS; + + const ZERO: Self = T::ZERO; +} + + + #[cfg(any(test, feature = "test-fixture", feature = "cli"))] impl IntoShares> for V where - V: SharedValue, + V: WeakSharedValue, Standard: Distribution, { fn share_with(self, rng: &mut R) -> [AdditiveShare; 3] { diff --git a/src/secret_sharing/replicated/mod.rs b/src/secret_sharing/replicated/mod.rs index dcf51494e..80c8167b0 100644 --- a/src/secret_sharing/replicated/mod.rs +++ b/src/secret_sharing/replicated/mod.rs @@ -1,9 +1,9 @@ pub mod malicious; pub mod semi_honest; -use super::{SecretSharing, SharedValue}; +use super::{SecretSharing, SharedValue, WeakSharedValue}; -pub trait ReplicatedSecretSharing: SecretSharing { +pub trait ReplicatedSecretSharing: SecretSharing { fn new(a: V, b: V) -> Self; fn left(&self) -> V; fn right(&self) -> V; diff --git a/src/secret_sharing/replicated/semi_honest/additive_share.rs b/src/secret_sharing/replicated/semi_honest/additive_share.rs index cc48cf78b..03f35f647 100644 --- a/src/secret_sharing/replicated/semi_honest/additive_share.rs +++ b/src/secret_sharing/replicated/semi_honest/additive_share.rs @@ -11,31 +11,32 @@ use crate::{ secret_sharing::{ replicated::ReplicatedSecretSharing, Linear as LinearSecretSharing, SecretSharing, SharedValue, + WeakSharedValue, }, }; #[derive(Clone, PartialEq, Eq)] -pub struct AdditiveShare(V, V); +pub struct AdditiveShare(V, V); -impl SecretSharing for AdditiveShare { +impl SecretSharing for AdditiveShare { const ZERO: Self = AdditiveShare::ZERO; } impl LinearSecretSharing for AdditiveShare {} -impl Debug for AdditiveShare { +impl Debug for AdditiveShare { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { write!(f, "({:?}, {:?})", self.0, self.1) } } -impl Default for AdditiveShare { +impl Default for AdditiveShare { fn default() -> Self { AdditiveShare::new(V::ZERO, V::ZERO) } } -impl AdditiveShare { +impl AdditiveShare { /// Replicated secret share where both left and right values are `F::ZERO` pub const ZERO: Self = Self(V::ZERO, V::ZERO); @@ -44,7 +45,7 @@ impl AdditiveShare { } } -impl ReplicatedSecretSharing for AdditiveShare { +impl ReplicatedSecretSharing for AdditiveShare { fn new(a: V, b: V) -> Self { Self(a, b) } @@ -58,7 +59,7 @@ impl ReplicatedSecretSharing for AdditiveShare { } } -impl AdditiveShare +impl AdditiveShare where Self: Serializable, { @@ -73,7 +74,7 @@ where } } -impl<'a, 'b, V: SharedValue> Add<&'b AdditiveShare> for &'a AdditiveShare { +impl<'a, 'b, V: WeakSharedValue> Add<&'b AdditiveShare> for &'a AdditiveShare { type Output = AdditiveShare; fn add(self, rhs: &'b AdditiveShare) -> Self::Output { @@ -81,7 +82,7 @@ impl<'a, 'b, V: SharedValue> Add<&'b AdditiveShare> for &'a AdditiveShare } } -impl Add for AdditiveShare { +impl Add for AdditiveShare { type Output = Self; fn add(self, rhs: Self) -> Self::Output { @@ -89,7 +90,7 @@ impl Add for AdditiveShare { } } -impl Add> for &AdditiveShare { +impl Add> for &AdditiveShare { type Output = AdditiveShare; fn add(self, rhs: AdditiveShare) -> Self::Output { @@ -97,7 +98,7 @@ impl Add> for &AdditiveShare { } } -impl Add<&AdditiveShare> for AdditiveShare { +impl Add<&AdditiveShare> for AdditiveShare { type Output = Self; fn add(self, rhs: &Self) -> Self::Output { @@ -105,20 +106,20 @@ impl Add<&AdditiveShare> for AdditiveShare { } } -impl AddAssign<&Self> for AdditiveShare { +impl AddAssign<&Self> for AdditiveShare { fn add_assign(&mut self, rhs: &Self) { self.0 += rhs.0; self.1 += rhs.1; } } -impl AddAssign for AdditiveShare { +impl AddAssign for AdditiveShare { fn add_assign(&mut self, rhs: Self) { AddAssign::add_assign(self, &rhs); } } -impl Neg for &AdditiveShare { +impl Neg for &AdditiveShare { type Output = AdditiveShare; fn neg(self) -> Self::Output { @@ -126,7 +127,7 @@ impl Neg for &AdditiveShare { } } -impl Neg for AdditiveShare { +impl Neg for AdditiveShare { type Output = Self; fn neg(self) -> Self::Output { @@ -134,7 +135,7 @@ impl Neg for AdditiveShare { } } -impl Sub for &AdditiveShare { +impl Sub for &AdditiveShare { type Output = AdditiveShare; fn sub(self, rhs: Self) -> Self::Output { @@ -142,7 +143,7 @@ impl Sub for &AdditiveShare { } } -impl Sub for AdditiveShare { +impl Sub for AdditiveShare { type Output = Self; fn sub(self, rhs: Self) -> Self::Output { @@ -150,7 +151,7 @@ impl Sub for AdditiveShare { } } -impl Sub<&Self> for AdditiveShare { +impl Sub<&Self> for AdditiveShare { type Output = Self; fn sub(self, rhs: &Self) -> Self::Output { @@ -158,7 +159,7 @@ impl Sub<&Self> for AdditiveShare { } } -impl Sub> for &AdditiveShare { +impl Sub> for &AdditiveShare { type Output = AdditiveShare; fn sub(self, rhs: AdditiveShare) -> Self::Output { @@ -166,14 +167,14 @@ impl Sub> for &AdditiveShare { } } -impl SubAssign<&Self> for AdditiveShare { +impl SubAssign<&Self> for AdditiveShare { fn sub_assign(&mut self, rhs: &Self) { self.0 -= rhs.0; self.1 -= rhs.1; } } -impl SubAssign for AdditiveShare { +impl SubAssign for AdditiveShare { fn sub_assign(&mut self, rhs: Self) { SubAssign::sub_assign(self, &rhs); } diff --git a/src/secret_sharing/scheme.rs b/src/secret_sharing/scheme.rs index cd6556211..4d843f4b8 100644 --- a/src/secret_sharing/scheme.rs +++ b/src/secret_sharing/scheme.rs @@ -3,11 +3,11 @@ use std::{ ops::{Mul, Neg}, }; -use super::SharedValue; +use super::{SharedValue,WeakSharedValue}; use crate::ff::{AddSub, AddSubAssign, GaloisField}; /// Secret sharing scheme i.e. Replicated secret sharing -pub trait SecretSharing: Clone + Debug + Sized + Send + Sync { +pub trait SecretSharing: Clone + Debug + Sized + Send + Sync { const ZERO: Self; } From 64dac775d82ed0769451972c549da8c7475451a8 Mon Sep 17 00:00:00 2001 From: Alex Koshelev Date: Mon, 16 Oct 2023 22:38:49 -0700 Subject: [PATCH 22/76] Fix compiler recursion error --- src/ff/curve_points.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/ff/curve_points.rs b/src/ff/curve_points.rs index cf182fd69..3fc51f896 100644 --- a/src/ff/curve_points.rs +++ b/src/ff/curve_points.rs @@ -13,6 +13,7 @@ use crate::{ ff::{ec_prime_field::Fp25519, Serializable}, secret_sharing::{Block, WeakSharedValue}, }; +use crate::secret_sharing::Additive; impl Block for CompressedRistretto { type Size = U32; @@ -20,7 +21,7 @@ impl Block for CompressedRistretto { ///ristretto point for curve 25519 #[derive(Clone, Copy, PartialEq, Debug)] -pub struct RP25519(::Storage); +pub struct RP25519(CompressedRistretto); /// using compressed ristretto point, Zero is generator of the curve, i.e. g^0 impl WeakSharedValue for RP25519 { From 884aeec2e2136087ffa136bcf799a07dbcbd129c Mon Sep 17 00:00:00 2001 From: Daniel Masny Date: Tue, 17 Oct 2023 15:04:59 -0700 Subject: [PATCH 23/76] define WeakSharedValue, adding ipa-prf feature --- Cargo.toml | 4 ++- src/ff/curve_points.rs | 48 +++++++++++++++++------------------ src/helpers/mod.rs | 4 +-- src/protocol/basics/reveal.rs | 4 +-- src/protocol/mod.rs | 1 + src/protocol/prf_eval/mod.rs | 2 +- 6 files changed, 32 insertions(+), 31 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 11e15fdc7..a1433ecea 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,7 +12,8 @@ default = [ "tracing/max_level_trace", "tracing/release_max_level_info", "descriptive-gate", - "aggregate-circuit" + "aggregate-circuit", + "ipa-prf" ] cli = ["comfy-table", "clap"] enable-serde = ["serde", "serde_json"] @@ -41,6 +42,7 @@ compact-gate = ["ipa-macros/compact-gate"] # Standalone aggregation protocol. We use IPA infra for communication # but it has nothing to do with IPA. aggregate-circuit = [] +ipa-prf = ["descriptive-gate"] [dependencies] ipa-macros = { version = "*", path = "./ipa-macros" } diff --git a/src/ff/curve_points.rs b/src/ff/curve_points.rs index 3fc51f896..1094079d4 100644 --- a/src/ff/curve_points.rs +++ b/src/ff/curve_points.rs @@ -9,11 +9,10 @@ use sha2::Sha256; use typenum::U32; use crate::{ - error::Error, ff::{ec_prime_field::Fp25519, Serializable}, secret_sharing::{Block, WeakSharedValue}, }; -use crate::secret_sharing::Additive; + impl Block for CompressedRistretto { type Size = U32; @@ -23,7 +22,7 @@ impl Block for CompressedRistretto { #[derive(Clone, Copy, PartialEq, Debug)] pub struct RP25519(CompressedRistretto); -/// using compressed ristretto point, Zero is generator of the curve, i.e. g^0 +/// using compressed ristretto point impl WeakSharedValue for RP25519 { type Storage = CompressedRistretto; const BITS: u32 = 256; @@ -42,6 +41,10 @@ impl Serializable for RP25519 { } } + +///## Panics +/// Panics when decompressing invalid curve point. This can happen when deserialize curve point +/// from bit array that does not have a valid representation on the curve impl std::ops::Add for RP25519 { type Output = Self; @@ -57,6 +60,9 @@ impl std::ops::AddAssign for RP25519 { } } +///## Panics +/// Panics when decompressing invalid curve point. This can happen when deserialize curve point +/// from bit array that does not have a valid representation on the curve impl std::ops::Neg for RP25519 { type Output = Self; @@ -65,6 +71,9 @@ impl std::ops::Neg for RP25519 { } } +///## Panics +/// Panics when decompressing invalid curve point. This can happen when deserialize curve point +/// from bit array that does not have a valid representation on the curve impl std::ops::Sub for RP25519 { type Output = Self; @@ -82,34 +91,23 @@ impl std::ops::SubAssign for RP25519 { ///Scalar Multiplication ///<'a, 'b> `std::ops::Mul<&'b"` Fp25519 for &'a -impl RP25519 { - /// # Errors - /// Propagates errors from decompressing invalid curve point - pub fn s_mul(self, rhs: Fp25519) -> Result { - self.0 - .decompress() - .map_or(Err(Error::DecompressingInvalidCurvePoint), |x| { - Ok((x * Scalar::from(rhs)).compress().into()) - }) - } -} - -///do not use -impl std::ops::Mul for RP25519 { +///## Panics +/// Panics when decompressing invalid curve point. This can happen when deserialize curve point +/// from bit array that does not have a valid representation on the curve +impl std::ops::Mul< Fp25519> for RP25519 { type Output = Self; - fn mul(self, _rhs: RP25519) -> Self::Output { - panic!("Two curve points cannot be multiplied! Do not use *, *= for RP25519 or secret shares of RP25519"); + fn mul(self, rhs: Fp25519) -> RP25519 { + (self.0.decompress().unwrap() * Scalar::from(rhs)).compress().into() } } -///do not use -impl std::ops::MulAssign for RP25519 { - fn mul_assign(&mut self, _rhs: RP25519) { - panic!("Two curve points cannot be multiplied! Do not use *, *= for RP25519 or secret shares of RP25519"); - } +impl std::ops::MulAssign< Fp25519> for RP25519 { + #[allow(clippy::assign_op_pattern)] + fn mul_assign(&mut self, rhs: Fp25519) {*self = *self * rhs} } + impl From for RP25519 { fn from(s: Scalar) -> Self { RP25519(RistrettoPoint::mul_base(&s).compress()) @@ -205,7 +203,7 @@ mod test { let fp_e = rng.gen::(); let fp_f = rng.gen::(); let fp_g = fp_e * fp_f; - let fp_h = RP25519::from(fp_e).s_mul(fp_f).unwrap(); + let fp_h = RP25519::from(fp_e) * fp_f; assert_eq!(fp_h, RP25519::from(fp_g)); assert_ne!(fp_h, RP25519(constants::RISTRETTO_BASEPOINT_COMPRESSED)); } diff --git a/src/helpers/mod.rs b/src/helpers/mod.rs index 373070736..6e27bbf69 100644 --- a/src/helpers/mod.rs +++ b/src/helpers/mod.rs @@ -40,7 +40,7 @@ use crate::{ Role::{H1, H2, H3}, }, protocol::{step::Gate, RecordId}, - secret_sharing::SharedValue, + secret_sharing::WeakSharedValue, }; // TODO work with ArrayLength only @@ -409,7 +409,7 @@ impl Debug for ChannelId { pub trait Message: Debug + Send + Serializable + 'static + Sized {} /// Any shared value can be send as a message -impl Message for V {} +impl Message for V {} impl Serializable for PublicKey { type Size = typenum::U32; diff --git a/src/protocol/basics/reveal.rs b/src/protocol/basics/reveal.rs index 672c8a473..9fddb65b8 100644 --- a/src/protocol/basics/reveal.rs +++ b/src/protocol/basics/reveal.rs @@ -18,7 +18,7 @@ use crate::{ malicious::{AdditiveShare as MaliciousReplicated, ExtendableField}, semi_honest::AdditiveShare as Replicated, }, - SecretSharing, SharedValue, + SecretSharing, WeakSharedValue, }, }; @@ -47,7 +47,7 @@ pub trait Reveal: Sized { /// i.e. their own shares and received share. #[async_trait] #[embed_doc_image("reveal", "images/reveal.png")] -impl Reveal for Replicated { +impl Reveal for Replicated { type Output = V; async fn reveal<'fut>(&self, ctx: C, record_id: RecordId) -> Result diff --git a/src/protocol/mod.rs b/src/protocol/mod.rs index 530c12f74..c50a86738 100644 --- a/src/protocol/mod.rs +++ b/src/protocol/mod.rs @@ -6,6 +6,7 @@ pub mod context; pub mod dp; pub mod ipa; pub mod modulus_conversion; +#[cfg(feature = "ipa-prf")] pub mod prf_eval; #[cfg(feature = "descriptive-gate")] pub mod prf_sharding; diff --git a/src/protocol/prf_eval/mod.rs b/src/protocol/prf_eval/mod.rs index ae43e55a1..3a0a99a21 100644 --- a/src/protocol/prf_eval/mod.rs +++ b/src/protocol/prf_eval/mod.rs @@ -94,7 +94,7 @@ where let z = y.reveal(ctx.narrow(&Step::Revealz), record_id).await?; //compute R^(1/z) to u64 - Ok(u64::from(gr.s_mul(z.invert())?)) + Ok(u64::from(gr * (z.invert()))) } #[cfg(all(test, unit_test))] From a620e347f9de1d01de975e08bc4470caf5fa7348 Mon Sep 17 00:00:00 2001 From: Daniel Masny Date: Tue, 17 Oct 2023 15:15:12 -0700 Subject: [PATCH 24/76] fix zero --- src/ff/curve_points.rs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/ff/curve_points.rs b/src/ff/curve_points.rs index 1094079d4..1d60f934a 100644 --- a/src/ff/curve_points.rs +++ b/src/ff/curve_points.rs @@ -1,5 +1,4 @@ use curve25519_dalek::{ - constants, ristretto::{CompressedRistretto, RistrettoPoint}, Scalar, }; @@ -26,7 +25,7 @@ pub struct RP25519(CompressedRistretto); impl WeakSharedValue for RP25519 { type Storage = CompressedRistretto; const BITS: u32 = 256; - const ZERO: Self = Self(constants::RISTRETTO_BASEPOINT_COMPRESSED); + const ZERO: Self = Self(CompressedRistretto([0_u8;32])); } impl Serializable for RP25519 { @@ -169,7 +168,10 @@ mod test { use rand::{thread_rng, Rng}; use typenum::U32; - use crate::ff::{curve_points::RP25519, ec_prime_field::Fp25519, Serializable}; + use crate::{ + ff::{curve_points::RP25519, ec_prime_field::Fp25519, Serializable}, + secret_sharing::WeakSharedValue, + }; #[test] fn serde_25519() { @@ -206,6 +208,7 @@ mod test { let fp_h = RP25519::from(fp_e) * fp_f; assert_eq!(fp_h, RP25519::from(fp_g)); assert_ne!(fp_h, RP25519(constants::RISTRETTO_BASEPOINT_COMPRESSED)); + assert_eq!(RP25519::ZERO,fp_h*Scalar::ZERO.into()); } #[test] From 55cef132834337db90817903017df0ac3c6d9f68 Mon Sep 17 00:00:00 2001 From: Daniel Masny Date: Tue, 17 Oct 2023 15:16:16 -0700 Subject: [PATCH 25/76] fmt --- src/ff/curve_points.rs | 21 +++++++++-------- src/secret_sharing/mod.rs | 23 ++++++------------- .../replicated/semi_honest/additive_share.rs | 3 +-- src/secret_sharing/scheme.rs | 2 +- 4 files changed, 20 insertions(+), 29 deletions(-) diff --git a/src/ff/curve_points.rs b/src/ff/curve_points.rs index 1d60f934a..99aac7f18 100644 --- a/src/ff/curve_points.rs +++ b/src/ff/curve_points.rs @@ -12,7 +12,6 @@ use crate::{ secret_sharing::{Block, WeakSharedValue}, }; - impl Block for CompressedRistretto { type Size = U32; } @@ -25,7 +24,7 @@ pub struct RP25519(CompressedRistretto); impl WeakSharedValue for RP25519 { type Storage = CompressedRistretto; const BITS: u32 = 256; - const ZERO: Self = Self(CompressedRistretto([0_u8;32])); + const ZERO: Self = Self(CompressedRistretto([0_u8; 32])); } impl Serializable for RP25519 { @@ -40,7 +39,6 @@ impl Serializable for RP25519 { } } - ///## Panics /// Panics when decompressing invalid curve point. This can happen when deserialize curve point /// from bit array that does not have a valid representation on the curve @@ -93,20 +91,23 @@ impl std::ops::SubAssign for RP25519 { ///## Panics /// Panics when decompressing invalid curve point. This can happen when deserialize curve point /// from bit array that does not have a valid representation on the curve -impl std::ops::Mul< Fp25519> for RP25519 { +impl std::ops::Mul for RP25519 { type Output = Self; - fn mul(self, rhs: Fp25519) -> RP25519 { - (self.0.decompress().unwrap() * Scalar::from(rhs)).compress().into() + fn mul(self, rhs: Fp25519) -> RP25519 { + (self.0.decompress().unwrap() * Scalar::from(rhs)) + .compress() + .into() } } -impl std::ops::MulAssign< Fp25519> for RP25519 { +impl std::ops::MulAssign for RP25519 { #[allow(clippy::assign_op_pattern)] - fn mul_assign(&mut self, rhs: Fp25519) {*self = *self * rhs} + fn mul_assign(&mut self, rhs: Fp25519) { + *self = *self * rhs + } } - impl From for RP25519 { fn from(s: Scalar) -> Self { RP25519(RistrettoPoint::mul_base(&s).compress()) @@ -208,7 +209,7 @@ mod test { let fp_h = RP25519::from(fp_e) * fp_f; assert_eq!(fp_h, RP25519::from(fp_g)); assert_ne!(fp_h, RP25519(constants::RISTRETTO_BASEPOINT_COMPRESSED)); - assert_eq!(RP25519::ZERO,fp_h*Scalar::ZERO.into()); + assert_eq!(RP25519::ZERO, fp_h * Scalar::ZERO.into()); } #[test] diff --git a/src/secret_sharing/mod.rs b/src/secret_sharing/mod.rs index 191ad5df7..1fadc42ef 100644 --- a/src/secret_sharing/mod.rs +++ b/src/secret_sharing/mod.rs @@ -25,31 +25,23 @@ use crate::ff::{AddSub, AddSubAssign, Serializable}; /// Operations supported for weak shared values. pub trait Additive: -AddSub -+ AddSubAssign -+ Neg + AddSub + AddSubAssign + Neg { } impl Additive for T where - T: AddSub - + AddSubAssign - + Neg + T: AddSub + AddSubAssign + Neg { } /// Operations supported for shared values. pub trait Arithmetic: - Additive - + Mul - + MulAssign + Additive + Mul + MulAssign { } impl Arithmetic for T where - T: Additive - + Mul - + MulAssign + T: Additive + Mul + MulAssign { } @@ -60,7 +52,7 @@ pub trait Block: Sized + Copy + Debug { } pub trait WeakSharedValue: -Clone + Copy + PartialEq + Debug + Send + Sync + Sized + Additive + Serializable + 'static + Clone + Copy + PartialEq + Debug + Send + Sync + Sized + Additive + Serializable + 'static { type Storage: Block; @@ -79,7 +71,8 @@ pub trait SharedValue: const ZERO: Self; } -impl WeakSharedValue for T where +impl WeakSharedValue for T +where T: SharedValue, { type Storage = T::Storage; @@ -89,8 +82,6 @@ impl WeakSharedValue for T where const ZERO: Self = T::ZERO; } - - #[cfg(any(test, feature = "test-fixture", feature = "cli"))] impl IntoShares> for V where diff --git a/src/secret_sharing/replicated/semi_honest/additive_share.rs b/src/secret_sharing/replicated/semi_honest/additive_share.rs index 03f35f647..0e3e57bd2 100644 --- a/src/secret_sharing/replicated/semi_honest/additive_share.rs +++ b/src/secret_sharing/replicated/semi_honest/additive_share.rs @@ -10,8 +10,7 @@ use crate::{ ff::Serializable, secret_sharing::{ replicated::ReplicatedSecretSharing, Linear as LinearSecretSharing, SecretSharing, - SharedValue, - WeakSharedValue, + SharedValue, WeakSharedValue, }, }; diff --git a/src/secret_sharing/scheme.rs b/src/secret_sharing/scheme.rs index 4d843f4b8..0d2131eeb 100644 --- a/src/secret_sharing/scheme.rs +++ b/src/secret_sharing/scheme.rs @@ -3,7 +3,7 @@ use std::{ ops::{Mul, Neg}, }; -use super::{SharedValue,WeakSharedValue}; +use super::{SharedValue, WeakSharedValue}; use crate::ff::{AddSub, AddSubAssign, GaloisField}; /// Secret sharing scheme i.e. Replicated secret sharing From 9736b7138cb68efd975a93e67474b7771a8a83cd Mon Sep 17 00:00:00 2001 From: Daniel Masny Date: Tue, 17 Oct 2023 15:19:38 -0700 Subject: [PATCH 26/76] fix clippy --- src/ff/curve_points.rs | 2 +- src/ff/ec_prime_field.rs | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/ff/curve_points.rs b/src/ff/curve_points.rs index 99aac7f18..a084b14a0 100644 --- a/src/ff/curve_points.rs +++ b/src/ff/curve_points.rs @@ -104,7 +104,7 @@ impl std::ops::Mul for RP25519 { impl std::ops::MulAssign for RP25519 { #[allow(clippy::assign_op_pattern)] fn mul_assign(&mut self, rhs: Fp25519) { - *self = *self * rhs + *self = *self * rhs; } } diff --git a/src/ff/ec_prime_field.rs b/src/ff/ec_prime_field.rs index d0ff48b72..15d5f33a7 100644 --- a/src/ff/ec_prime_field.rs +++ b/src/ff/ec_prime_field.rs @@ -119,6 +119,7 @@ impl From for Fp25519 { } } +#[cfg(test)] macro_rules! sc_hash_impl { ( $u_type:ty) => { impl From for $u_type { From b0ae43f37887ec908ec1819a45c0621cff25377b Mon Sep 17 00:00:00 2001 From: Daniel Masny Date: Wed, 18 Oct 2023 11:03:53 -0700 Subject: [PATCH 27/76] refactor prf_ipa in separate module --- src/protocol/ipa_prf/mod.rs | 2 ++ src/protocol/{ => ipa_prf}/prf_eval/mod.rs | 6 +++--- src/protocol/{ => ipa_prf}/prf_sharding/bucket.rs | 4 ++-- .../{ => ipa_prf}/prf_sharding/feature_label_dot_product.rs | 2 +- src/protocol/{ => ipa_prf}/prf_sharding/mod.rs | 2 +- src/protocol/mod.rs | 4 +--- 6 files changed, 10 insertions(+), 10 deletions(-) create mode 100644 src/protocol/ipa_prf/mod.rs rename src/protocol/{ => ipa_prf}/prf_eval/mod.rs (95%) rename src/protocol/{ => ipa_prf}/prf_sharding/bucket.rs (98%) rename src/protocol/{ => ipa_prf}/prf_sharding/feature_label_dot_product.rs (99%) rename src/protocol/{ => ipa_prf}/prf_sharding/mod.rs (99%) diff --git a/src/protocol/ipa_prf/mod.rs b/src/protocol/ipa_prf/mod.rs new file mode 100644 index 000000000..755ef87a5 --- /dev/null +++ b/src/protocol/ipa_prf/mod.rs @@ -0,0 +1,2 @@ +pub mod prf_eval; +pub mod prf_sharding; diff --git a/src/protocol/prf_eval/mod.rs b/src/protocol/ipa_prf/prf_eval/mod.rs similarity index 95% rename from src/protocol/prf_eval/mod.rs rename to src/protocol/ipa_prf/prf_eval/mod.rs index 3a0a99a21..6d95e40cd 100644 --- a/src/protocol/prf_eval/mod.rs +++ b/src/protocol/ipa_prf/prf_eval/mod.rs @@ -9,7 +9,7 @@ use crate::{ prss::SharedRandomness, RecordId, }, - secret_sharing::replicated::{semi_honest::AdditiveShare, ReplicatedSecretSharing}, + secret_sharing::replicated::{ReplicatedSecretSharing, semi_honest::AdditiveShare}, seq_join::seq_try_join_all, }; @@ -103,11 +103,11 @@ mod test { use crate::{ ff::{curve_points::RP25519, ec_prime_field::Fp25519}, - protocol::prf_eval::compute_match_key_pseudonym, - secret_sharing::{replicated::semi_honest::AdditiveShare, IntoShares}, + secret_sharing::{IntoShares, replicated::semi_honest::AdditiveShare}, test_executor::run, test_fixture::{Reconstruct, Runner, TestWorld}, }; + use crate::protocol::ipa_prf::prf_eval::compute_match_key_pseudonym; #[derive(Copy, Clone)] struct ShuffledTestInput { diff --git a/src/protocol/prf_sharding/bucket.rs b/src/protocol/ipa_prf/prf_sharding/bucket.rs similarity index 98% rename from src/protocol/prf_sharding/bucket.rs rename to src/protocol/ipa_prf/prf_sharding/bucket.rs index 6349f91a6..d3501e757 100644 --- a/src/protocol/prf_sharding/bucket.rs +++ b/src/protocol/ipa_prf/prf_sharding/bucket.rs @@ -4,7 +4,7 @@ use crate::{ error::Error, ff::{GaloisField, PrimeField, Serializable}, protocol::{ - basics::SecureMul, context::UpgradedContext, prf_sharding::BinaryTreeDepthStep, + basics::SecureMul, context::UpgradedContext, ipa_prf::prf_sharding::BinaryTreeDepthStep, step::BitOpStep, RecordId, }, secret_sharing::{ @@ -99,7 +99,7 @@ pub mod tests { ff::{Field, Fp32BitPrime, Gf5Bit, Gf8Bit}, protocol::{ context::{Context, UpgradableContext, Validator}, - prf_sharding::bucket::move_single_value_to_bucket, + ipa_prf::prf_sharding::bucket::move_single_value_to_bucket, RecordId, }, rand::Rng, diff --git a/src/protocol/prf_sharding/feature_label_dot_product.rs b/src/protocol/ipa_prf/prf_sharding/feature_label_dot_product.rs similarity index 99% rename from src/protocol/prf_sharding/feature_label_dot_product.rs rename to src/protocol/ipa_prf/prf_sharding/feature_label_dot_product.rs index f87f788d8..bc492b62c 100644 --- a/src/protocol/prf_sharding/feature_label_dot_product.rs +++ b/src/protocol/ipa_prf/prf_sharding/feature_label_dot_product.rs @@ -371,7 +371,7 @@ where pub mod tests { use crate::{ ff::{Field, Fp32BitPrime, GaloisField, Gf2, Gf32Bit}, - protocol::prf_sharding::feature_label_dot_product::{ + protocol::ipa_prf::prf_sharding::feature_label_dot_product::{ compute_feature_label_dot_product, PrfShardedIpaInputRow, }, rand::Rng, diff --git a/src/protocol/prf_sharding/mod.rs b/src/protocol/ipa_prf/prf_sharding/mod.rs similarity index 99% rename from src/protocol/prf_sharding/mod.rs rename to src/protocol/ipa_prf/prf_sharding/mod.rs index 110dc452a..8c1c6b7f2 100644 --- a/src/protocol/prf_sharding/mod.rs +++ b/src/protocol/ipa_prf/prf_sharding/mod.rs @@ -667,7 +667,7 @@ pub mod tests { ff::{Field, Fp32BitPrime, GaloisField, Gf2, Gf3Bit, Gf5Bit}, protocol::{ context::{UpgradableContext, Validator}, - prf_sharding::{attribution_and_capping_and_aggregation, do_aggregation}, + ipa_prf::prf_sharding::{attribution_and_capping_and_aggregation, do_aggregation}, }, rand::Rng, secret_sharing::{ diff --git a/src/protocol/mod.rs b/src/protocol/mod.rs index c50a86738..02c8d8786 100644 --- a/src/protocol/mod.rs +++ b/src/protocol/mod.rs @@ -7,9 +7,7 @@ pub mod dp; pub mod ipa; pub mod modulus_conversion; #[cfg(feature = "ipa-prf")] -pub mod prf_eval; -#[cfg(feature = "descriptive-gate")] -pub mod prf_sharding; +pub mod ipa_prf; pub mod prss; pub mod sort; pub mod step; From da13880cd5d72dfaac8ffdbfb81a4d0d22e37414 Mon Sep 17 00:00:00 2001 From: Daniel Masny Date: Wed, 18 Oct 2023 11:05:41 -0700 Subject: [PATCH 28/76] fmt --- src/protocol/ipa_prf/prf_eval/mod.rs | 6 +++--- src/protocol/mod.rs | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/protocol/ipa_prf/prf_eval/mod.rs b/src/protocol/ipa_prf/prf_eval/mod.rs index 6d95e40cd..4da81759c 100644 --- a/src/protocol/ipa_prf/prf_eval/mod.rs +++ b/src/protocol/ipa_prf/prf_eval/mod.rs @@ -9,7 +9,7 @@ use crate::{ prss::SharedRandomness, RecordId, }, - secret_sharing::replicated::{ReplicatedSecretSharing, semi_honest::AdditiveShare}, + secret_sharing::replicated::{semi_honest::AdditiveShare, ReplicatedSecretSharing}, seq_join::seq_try_join_all, }; @@ -103,11 +103,11 @@ mod test { use crate::{ ff::{curve_points::RP25519, ec_prime_field::Fp25519}, - secret_sharing::{IntoShares, replicated::semi_honest::AdditiveShare}, + protocol::ipa_prf::prf_eval::compute_match_key_pseudonym, + secret_sharing::{replicated::semi_honest::AdditiveShare, IntoShares}, test_executor::run, test_fixture::{Reconstruct, Runner, TestWorld}, }; - use crate::protocol::ipa_prf::prf_eval::compute_match_key_pseudonym; #[derive(Copy, Clone)] struct ShuffledTestInput { diff --git a/src/protocol/mod.rs b/src/protocol/mod.rs index 02c8d8786..f10df2cf8 100644 --- a/src/protocol/mod.rs +++ b/src/protocol/mod.rs @@ -5,9 +5,9 @@ pub mod boolean; pub mod context; pub mod dp; pub mod ipa; -pub mod modulus_conversion; #[cfg(feature = "ipa-prf")] pub mod ipa_prf; +pub mod modulus_conversion; pub mod prss; pub mod sort; pub mod step; From 160ba83fed3becc710f02d3a6926f361217a4caf Mon Sep 17 00:00:00 2001 From: Daniel Masny Date: Fri, 20 Oct 2023 15:00:05 -0700 Subject: [PATCH 29/76] adressing Alex's comments --- src/error.rs | 4 ++-- src/ff/curve_points.rs | 10 +++++----- src/ff/ec_prime_field.rs | 10 +++++++--- src/protocol/ipa_prf/prf_eval/mod.rs | 5 ++--- 4 files changed, 16 insertions(+), 13 deletions(-) diff --git a/src/error.rs b/src/error.rs index 7d6456c7f..de41eda4b 100644 --- a/src/error.rs +++ b/src/error.rs @@ -58,8 +58,8 @@ pub enum Error { InvalidReport(#[from] InvalidReportError), #[error("unsupported: {0}")] Unsupported(String), - #[error("Decompressing invalid elliptic curve point")] - DecompressingInvalidCurvePoint, + #[error("Decompressing invalid elliptic curve point: {0}")] + DecompressingInvalidCurvePoint(String), } impl Default for Error { diff --git a/src/ff/curve_points.rs b/src/ff/curve_points.rs index a084b14a0..f4cb50bba 100644 --- a/src/ff/curve_points.rs +++ b/src/ff/curve_points.rs @@ -3,8 +3,6 @@ use curve25519_dalek::{ Scalar, }; use generic_array::GenericArray; -use hkdf::Hkdf; -use sha2::Sha256; use typenum::U32; use crate::{ @@ -35,6 +33,7 @@ impl Serializable for RP25519 { } fn deserialize(buf: &GenericArray) -> Self { + debug_assert!(CompressedRistretto((*buf).into()).decompress().is_some()); RP25519(CompressedRistretto((*buf).into())) } } @@ -87,7 +86,6 @@ impl std::ops::SubAssign for RP25519 { } ///Scalar Multiplication -///<'a, 'b> `std::ops::Mul<&'b"` Fp25519 for &'a ///## Panics /// Panics when decompressing invalid curve point. This can happen when deserialize curve point /// from bit array that does not have a valid representation on the curve @@ -136,6 +134,8 @@ macro_rules! cp_hash_impl { ( $u_type:ty) => { impl From for $u_type { fn from(s: RP25519) -> Self { + use hkdf::Hkdf; + use sha2::Sha256; let hk = Hkdf::::new(None, s.0.as_bytes()); let mut okm = <$u_type>::MIN.to_le_bytes(); //error invalid length from expand only happens when okm is very large @@ -150,8 +150,6 @@ cp_hash_impl!(u128); cp_hash_impl!(u64); -#[cfg(test)] -cp_hash_impl!(u32); #[cfg(test)] impl rand::distributions::Distribution for rand::distributions::Standard { @@ -174,6 +172,8 @@ mod test { secret_sharing::WeakSharedValue, }; + cp_hash_impl!(u32); + #[test] fn serde_25519() { let mut rng = thread_rng(); diff --git a/src/ff/ec_prime_field.rs b/src/ff/ec_prime_field.rs index 15d5f33a7..02f0742df 100644 --- a/src/ff/ec_prime_field.rs +++ b/src/ff/ec_prime_field.rs @@ -124,6 +124,8 @@ macro_rules! sc_hash_impl { ( $u_type:ty) => { impl From for $u_type { fn from(s: Fp25519) -> Self { + use hkdf::Hkdf; + use sha2::Sha256; let hk = Hkdf::::new(None, s.0.as_bytes()); let mut okm = <$u_type>::MIN.to_le_bytes(); //error invalid length from expand only happens when okm is very large @@ -134,6 +136,8 @@ macro_rules! sc_hash_impl { impl From<$u_type> for Fp25519 { fn from(s: $u_type) -> Self { + use hkdf::Hkdf; + use sha2::Sha256; let hk = Hkdf::::new(None, &s.to_le_bytes()); let mut okm = [0u8; 32]; //error invalid length from expand only happens when okm is very large @@ -147,10 +151,7 @@ macro_rules! sc_hash_impl { #[cfg(test)] sc_hash_impl!(u64); -#[cfg(test)] -sc_hash_impl!(u32); -/// Daniel had to implement this since PRSS wants it, prefer not to impl Field for Fp25519 { const ONE: Fp25519 = Fp25519::ONE; @@ -198,6 +199,9 @@ mod test { secret_sharing::SharedValue, }; + + sc_hash_impl!(u32); + #[test] fn serde_25519() { let mut rng = thread_rng(); diff --git a/src/protocol/ipa_prf/prf_eval/mod.rs b/src/protocol/ipa_prf/prf_eval/mod.rs index 4da81759c..fe9b2540e 100644 --- a/src/protocol/ipa_prf/prf_eval/mod.rs +++ b/src/protocol/ipa_prf/prf_eval/mod.rs @@ -10,7 +10,6 @@ use crate::{ RecordId, }, secret_sharing::replicated::{semi_honest::AdditiveShare, ReplicatedSecretSharing}, - seq_join::seq_try_join_all, }; #[derive(Step)] @@ -37,7 +36,7 @@ where .iter() .enumerate() .map(|(i, x)| eval_dy_prf(ctx.clone(), i.into(), &prf_key, x)); - seq_try_join_all(sh_ctx.active_work(), futures).await + ctx.try_join(futures).await } impl From> for AdditiveShare { @@ -53,7 +52,7 @@ where { ctx.narrow(&Step::PRFKeyGen) .prss() - .generate_replicated(u128::MAX - 100u128) + .generate_replicated(RecordId(0)) } /// evaluates the Dodis-Yampolski PRF g^(1/(k+x)) From 8407938cab4e476ab375fb0fa14b25431d9582d5 Mon Sep 17 00:00:00 2001 From: Daniel Masny Date: Fri, 20 Oct 2023 15:01:26 -0700 Subject: [PATCH 30/76] fmt --- src/ff/curve_points.rs | 1 - src/ff/ec_prime_field.rs | 2 -- 2 files changed, 3 deletions(-) diff --git a/src/ff/curve_points.rs b/src/ff/curve_points.rs index f4cb50bba..2b06f973e 100644 --- a/src/ff/curve_points.rs +++ b/src/ff/curve_points.rs @@ -150,7 +150,6 @@ cp_hash_impl!(u128); cp_hash_impl!(u64); - #[cfg(test)] impl rand::distributions::Distribution for rand::distributions::Standard { fn sample(&self, rng: &mut R) -> RP25519 { diff --git a/src/ff/ec_prime_field.rs b/src/ff/ec_prime_field.rs index 02f0742df..ba753eb40 100644 --- a/src/ff/ec_prime_field.rs +++ b/src/ff/ec_prime_field.rs @@ -151,7 +151,6 @@ macro_rules! sc_hash_impl { #[cfg(test)] sc_hash_impl!(u64); - impl Field for Fp25519 { const ONE: Fp25519 = Fp25519::ONE; @@ -199,7 +198,6 @@ mod test { secret_sharing::SharedValue, }; - sc_hash_impl!(u32); #[test] From 43696a67ecac2e51fefac351492d33e1732c55d7 Mon Sep 17 00:00:00 2001 From: Daniel Masny Date: Fri, 20 Oct 2023 16:59:31 -0700 Subject: [PATCH 31/76] add comments --- src/ff/curve_points.rs | 22 ++++++++++++++++++++-- src/ff/ec_prime_field.rs | 14 +++++++++++++- src/protocol/ipa_prf/prf_eval/mod.rs | 12 ++++++++++-- src/secret_sharing/mod.rs | 4 ++++ 4 files changed, 47 insertions(+), 5 deletions(-) diff --git a/src/ff/curve_points.rs b/src/ff/curve_points.rs index 2b06f973e..ec42eba76 100644 --- a/src/ff/curve_points.rs +++ b/src/ff/curve_points.rs @@ -14,11 +14,21 @@ impl Block for CompressedRistretto { type Size = U32; } -///ristretto point for curve 25519 +///ristretto point for curve 25519, +/// we store it in compressed format since it is 3 times smaller and we do a limited amount of +/// arithmetic operations on the curve points +/// +/// We use ristretto points such that we have a prime order elliptic curve, +/// This is needed for the Dodis Yampolski PRF +/// +/// decompressing invalid curve points will cause panics, +/// since we always generate curve points from scalars (elements in Fp25519) and +/// only deserialize previously serialized valid points, panics will not occur +/// However, we still added a debug assert to deserialize since values are sent by other servers #[derive(Clone, Copy, PartialEq, Debug)] pub struct RP25519(CompressedRistretto); -/// using compressed ristretto point +/// Implementing trait for secret sharing impl WeakSharedValue for RP25519 { type Storage = CompressedRistretto; const BITS: u32 = 256; @@ -86,6 +96,7 @@ impl std::ops::SubAssign for RP25519 { } ///Scalar Multiplication +/// allows to multiply curve points with scalars from Fp25519 ///## Panics /// Panics when decompressing invalid curve point. This can happen when deserialize curve point /// from bit array that does not have a valid representation on the curve @@ -130,6 +141,7 @@ impl From for CompressedRistretto { } } +///allows to convert curve points into unsigned integers, preserving high entropy macro_rules! cp_hash_impl { ( $u_type:ty) => { impl From for $u_type { @@ -150,6 +162,8 @@ cp_hash_impl!(u128); cp_hash_impl!(u64); +/// implementing random curve point generation for testing purposes, +/// in the actual IPA protocol, we generate them from scalars, i.e. Fp25519 #[cfg(test)] impl rand::distributions::Distribution for rand::distributions::Standard { fn sample(&self, rng: &mut R) -> RP25519 { @@ -173,6 +187,7 @@ mod test { cp_hash_impl!(u32); + ///testing serialize and deserialize #[test] fn serde_25519() { let mut rng = thread_rng(); @@ -183,6 +198,7 @@ mod test { assert_eq!(input, output); } + ///testing conversion from scalar to Fp25519 and curve point, i.e. RP25519 #[test] fn scalar_to_point() { let a = Scalar::ONE; @@ -193,6 +209,7 @@ mod test { assert_eq!(c, RP25519(constants::RISTRETTO_BASEPOINT_COMPRESSED)); } + ///testing simple curve arithmetics to check that curve25519_dalek library is used correctly #[test] fn curve_arithmetics() { let mut rng = thread_rng(); @@ -211,6 +228,7 @@ mod test { assert_eq!(RP25519::ZERO, fp_h * Scalar::ZERO.into()); } + ///testing curve to unsigned integer conversion has entropy (!= 0) #[test] fn curve_point_to_hash() { let mut rng = thread_rng(); diff --git a/src/ff/ec_prime_field.rs b/src/ff/ec_prime_field.rs index ba753eb40..9bd31ddbb 100644 --- a/src/ff/ec_prime_field.rs +++ b/src/ff/ec_prime_field.rs @@ -13,12 +13,15 @@ impl Block for Scalar { type Size = U32; } +///implements the Scalar field for elliptic curve 25519 +/// we use elements in Fp25519 to generate curve points and operate on the curve #[derive(Clone, Copy, PartialEq, Debug)] pub struct Fp25519(::Storage); impl Fp25519 { pub const ONE: Self = Self(Scalar::ONE); + ///allow invert for scalars, i.e. computes 1/a mod p ///# Panics /// Panics when self is zero #[must_use] @@ -28,12 +31,14 @@ impl Fp25519 { } } +///trait for secret sharing impl SharedValue for Fp25519 { type Storage = Scalar; const BITS: u32 = 256; const ZERO: Self = Self(Scalar::ZERO); } +///conversion to Scalar struct of curve25519_dalek impl From for Scalar { fn from(s: Fp25519) -> Self { s.0 @@ -52,6 +57,7 @@ impl Serializable for Fp25519 { } } +///generate random elements in Fp25519 impl rand::distributions::Distribution for rand::distributions::Standard { fn sample(&self, rng: &mut R) -> Fp25519 { let mut scalar_bytes = [0u8; 32]; @@ -119,6 +125,7 @@ impl From for Fp25519 { } } +///conversion from and to unsigned integers, preserving entropy, for testing purposes only #[cfg(test)] macro_rules! sc_hash_impl { ( $u_type:ty) => { @@ -151,6 +158,7 @@ macro_rules! sc_hash_impl { #[cfg(test)] sc_hash_impl!(u64); +///implement Field because required by PRSS impl Field for Fp25519 { const ONE: Fp25519 = Fp25519::ONE; @@ -174,6 +182,7 @@ impl Field for Fp25519 { } } +///implement TryFrom since required by Field impl TryFrom for Fp25519 { type Error = crate::error::Error; @@ -200,6 +209,7 @@ mod test { sc_hash_impl!(u32); + ///test serialize and deserialize #[test] fn serde_25519() { let mut rng = thread_rng(); @@ -210,7 +220,7 @@ mod test { assert_eq!(input, output); } - // These are just simple arithmetic tests since arithmetics are checked by curve25519_dalek + ///test simple arithmetics to check that curve25519_dalek is used correctly #[test] fn simple_arithmetics_25519() { let a = Fp25519(Scalar::from_bytes_mod_order([ @@ -241,12 +251,14 @@ mod test { assert_eq!(ec, e); } + ///test random field element generation (!= 0) #[test] fn simple_random_25519() { let mut rng = thread_rng(); assert_ne!(Fp25519::ZERO, rng.gen::()); } + ///test inversion for field elements #[test] fn invert_25519() { let mut rng = thread_rng(); diff --git a/src/protocol/ipa_prf/prf_eval/mod.rs b/src/protocol/ipa_prf/prf_eval/mod.rs index fe9b2540e..7a65c0191 100644 --- a/src/protocol/ipa_prf/prf_eval/mod.rs +++ b/src/protocol/ipa_prf/prf_eval/mod.rs @@ -21,6 +21,10 @@ pub(crate) enum Step { Revealz, } +/// generates match key pseudonyms from match keys (in Fp25519 format) and PRF key +/// PRF key needs to be generated separately using gen_prf_key +/// +/// gen_prf_key is not included such that compute_match_key_pseudonym can be tested for correctness /// # Errors /// Propagates errors from multiplications pub async fn compute_match_key_pseudonym( @@ -57,8 +61,8 @@ where /// evaluates the Dodis-Yampolski PRF g^(1/(k+x)) /// the input x and k are secret shared over finite field Fp25519, i.e. the scalar field of curve 25519 -/// PRF key k is generated using keygen -/// In 3IPA, x is the match key +/// PRF key k needs to be generated using gen_prf_key +/// x is the match key in Fp25519 format /// outputs a u64 as specified in `protocol/prf_sharding/mod.rs`, all parties learn the output /// # Errors /// Propagates errors from multiplications, reveal and scalar multiplication @@ -108,11 +112,13 @@ mod test { test_fixture::{Reconstruct, Runner, TestWorld}, }; + ///defining test input struct #[derive(Copy, Clone)] struct ShuffledTestInput { match_key: Fp25519, } + ///defining test output struct #[derive(Debug, PartialEq)] struct TestOutput { match_key_pseudonym: u64, @@ -142,6 +148,8 @@ mod test { } } + ///testing correctness of DY PRF evaluation + /// by checking MPC generated pseudonym with pseudonym generated in the clear #[test] fn semi_honest() { run(|| async move { diff --git a/src/secret_sharing/mod.rs b/src/secret_sharing/mod.rs index 8564bf4be..1a7dda8c2 100644 --- a/src/secret_sharing/mod.rs +++ b/src/secret_sharing/mod.rs @@ -51,6 +51,8 @@ pub trait Block: Sized + Copy + Debug { type Size: ArrayLength; } + +///allows basic secret sharing operations pub trait WeakSharedValue: Clone + Copy + PartialEq + Debug + Send + Sync + Sized + Additive + Serializable + 'static { @@ -61,6 +63,7 @@ pub trait WeakSharedValue: const ZERO: Self; } +///allows advanced secret sharing operations, requires multiplication pub trait SharedValue: Clone + Copy + PartialEq + Debug + Send + Sync + Sized + Arithmetic + Serializable + 'static { @@ -71,6 +74,7 @@ pub trait SharedValue: const ZERO: Self; } +///any SharedValue is also a WeakSharedValue impl WeakSharedValue for T where T: SharedValue, From 4268a0590d8264fd75bc7ff870343433dac18df9 Mon Sep 17 00:00:00 2001 From: Daniel Masny Date: Fri, 20 Oct 2023 17:02:24 -0700 Subject: [PATCH 32/76] fix lint --- src/ff/curve_points.rs | 2 +- src/ff/ec_prime_field.rs | 6 +++--- src/protocol/ipa_prf/prf_eval/mod.rs | 6 +++--- src/secret_sharing/mod.rs | 2 +- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/ff/curve_points.rs b/src/ff/curve_points.rs index ec42eba76..8eaa57623 100644 --- a/src/ff/curve_points.rs +++ b/src/ff/curve_points.rs @@ -209,7 +209,7 @@ mod test { assert_eq!(c, RP25519(constants::RISTRETTO_BASEPOINT_COMPRESSED)); } - ///testing simple curve arithmetics to check that curve25519_dalek library is used correctly + ///testing simple curve arithmetics to check that `curve25519_dalek` library is used correctly #[test] fn curve_arithmetics() { let mut rng = thread_rng(); diff --git a/src/ff/ec_prime_field.rs b/src/ff/ec_prime_field.rs index 9bd31ddbb..3385f10e8 100644 --- a/src/ff/ec_prime_field.rs +++ b/src/ff/ec_prime_field.rs @@ -38,7 +38,7 @@ impl SharedValue for Fp25519 { const ZERO: Self = Self(Scalar::ZERO); } -///conversion to Scalar struct of curve25519_dalek +///conversion to Scalar struct of `curve25519_dalek` impl From for Scalar { fn from(s: Fp25519) -> Self { s.0 @@ -182,7 +182,7 @@ impl Field for Fp25519 { } } -///implement TryFrom since required by Field +///implement `TryFrom` since required by Field impl TryFrom for Fp25519 { type Error = crate::error::Error; @@ -220,7 +220,7 @@ mod test { assert_eq!(input, output); } - ///test simple arithmetics to check that curve25519_dalek is used correctly + ///test simple arithmetics to check that `curve25519_dalek` is used correctly #[test] fn simple_arithmetics_25519() { let a = Fp25519(Scalar::from_bytes_mod_order([ diff --git a/src/protocol/ipa_prf/prf_eval/mod.rs b/src/protocol/ipa_prf/prf_eval/mod.rs index 7a65c0191..ff37e30eb 100644 --- a/src/protocol/ipa_prf/prf_eval/mod.rs +++ b/src/protocol/ipa_prf/prf_eval/mod.rs @@ -22,9 +22,9 @@ pub(crate) enum Step { } /// generates match key pseudonyms from match keys (in Fp25519 format) and PRF key -/// PRF key needs to be generated separately using gen_prf_key +/// PRF key needs to be generated separately using `gen_prf_key` /// -/// gen_prf_key is not included such that compute_match_key_pseudonym can be tested for correctness +/// `gen_prf_key` is not included such that `compute_match_key_pseudonym` can be tested for correctness /// # Errors /// Propagates errors from multiplications pub async fn compute_match_key_pseudonym( @@ -61,7 +61,7 @@ where /// evaluates the Dodis-Yampolski PRF g^(1/(k+x)) /// the input x and k are secret shared over finite field Fp25519, i.e. the scalar field of curve 25519 -/// PRF key k needs to be generated using gen_prf_key +/// PRF key k needs to be generated using `gen_prf_key` /// x is the match key in Fp25519 format /// outputs a u64 as specified in `protocol/prf_sharding/mod.rs`, all parties learn the output /// # Errors diff --git a/src/secret_sharing/mod.rs b/src/secret_sharing/mod.rs index 1a7dda8c2..155b1f609 100644 --- a/src/secret_sharing/mod.rs +++ b/src/secret_sharing/mod.rs @@ -74,7 +74,7 @@ pub trait SharedValue: const ZERO: Self; } -///any SharedValue is also a WeakSharedValue +///any `SharedValue` is also a `WeakSharedValue` impl WeakSharedValue for T where T: SharedValue, From 4208d1b91385953c21f5ed45b331a1d33d83cd69 Mon Sep 17 00:00:00 2001 From: Daniel Masny Date: Fri, 20 Oct 2023 17:03:06 -0700 Subject: [PATCH 33/76] fmt --- src/secret_sharing/mod.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/secret_sharing/mod.rs b/src/secret_sharing/mod.rs index 155b1f609..441fe1f21 100644 --- a/src/secret_sharing/mod.rs +++ b/src/secret_sharing/mod.rs @@ -51,7 +51,6 @@ pub trait Block: Sized + Copy + Debug { type Size: ArrayLength; } - ///allows basic secret sharing operations pub trait WeakSharedValue: Clone + Copy + PartialEq + Debug + Send + Sync + Sized + Additive + Serializable + 'static From 9b7649bffb434033ac9dac43fa6c911f532068ee Mon Sep 17 00:00:00 2001 From: Daniel Masny Date: Mon, 2 Oct 2023 09:44:30 -0700 Subject: [PATCH 34/76] added 25519 prime field --- Cargo.toml | 1 + src/ff/ec_prime_field.rs | 194 +++++++++++++++++++++++++++++++++++++++ src/ff/mod.rs | 1 + 3 files changed, 196 insertions(+) create mode 100644 src/ff/ec_prime_field.rs diff --git a/Cargo.toml b/Cargo.toml index 1767e8e24..c3161a216 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -54,6 +54,7 @@ clap = { version = "4.3.2", optional = true, features = ["derive"] } comfy-table = { version = "7.0", optional = true } config = "0.13.2" criterion = { version = "0.5.1", optional = true, default-features = false, features = ["async_tokio", "plotters", "html_reports"] } +curve25519-dalek = "4.1.1" dashmap = "5.4" dhat = "0.3.2" embed-doc-image = "0.1.4" diff --git a/src/ff/ec_prime_field.rs b/src/ff/ec_prime_field.rs new file mode 100644 index 000000000..c87dbfa94 --- /dev/null +++ b/src/ff/ec_prime_field.rs @@ -0,0 +1,194 @@ +use generic_array::GenericArray; +use curve25519_dalek::scalar::Scalar; +use rand_core::RngCore; +use typenum::U32; + +use crate::{ + ff::Serializable, + secret_sharing::{Block, SharedValue}, +}; + +impl Block for Scalar { + type Size = U32; +} + +#[derive(Clone, Copy, PartialEq, Debug)] +pub struct Fp25519(::Storage); + +//how to add const ONE: Self = Self(Scalar::ONE); within the struct, do I need to do it via a trait? + + +impl SharedValue for Fp25519 { + type Storage = Scalar; + const BITS: u32 = 256; + const ZERO: Self = Self(Scalar::ZERO); +} + +impl Serializable for Fp25519 { + type Size = <::Storage as Block>::Size; + + fn serialize(&self, buf: &mut GenericArray) { + let raw = &self.0.as_bytes()[..buf.len()] ; + buf.copy_from_slice(raw); + } + + fn deserialize(buf: &GenericArray) -> Self { + let mut buf_to = [0u8; 32]; + buf_to[..buf.len()].copy_from_slice(buf); + + Fp25519(Scalar::from_bytes_mod_order(buf_to)) + } +} + + +impl rand::distributions::Distribution for rand::distributions::Standard { + fn sample(&self, rng: &mut R) -> Fp25519 { + //Fp25519(Scalar::random(rng: &mut R)) + let mut scalar_bytes = [0u8; 64]; + rng.fill_bytes(&mut scalar_bytes); + Fp25519(Scalar::from_bytes_mod_order_wide(&scalar_bytes)) + } +} + + +impl std::ops::Add for Fp25519 { +type Output = Self; + +fn add(self, rhs: Self) -> Self::Output { + Self(self.0+rhs.0) +} +} + +impl std::ops::AddAssign for Fp25519 { +#[allow(clippy::assign_op_pattern)] +fn add_assign(&mut self, rhs: Self) { + *self = *self + rhs; +} +} + +impl std::ops::Neg for Fp25519 { +type Output = Self; + +fn neg(self) -> Self::Output { + Self(self.0.neg()) +} +} + +impl std::ops::Sub for Fp25519 { +type Output = Self; + +fn sub(self, rhs: Self) -> Self::Output { + Self(self.0- rhs.0) +} +} + +impl std::ops::SubAssign for Fp25519 { +#[allow(clippy::assign_op_pattern)] +fn sub_assign(&mut self, rhs: Self) { + *self = *self - rhs; +} +} + +impl std::ops::Mul for Fp25519 { +type Output = Self; + +fn mul(self, rhs: Self) -> Self::Output { + Self(self.0 * rhs.0) +} +} + +impl std::ops::MulAssign for Fp25519 { +#[allow(clippy::assign_op_pattern)] +fn mul_assign(&mut self, rhs: Self) { + *self = *self * rhs; +} +} + +//must not use with ZERO +impl Fp25519 { + pub fn invert(&self) -> Fp25519 { + Fp25519(self.0.invert()) + } +} + +#[cfg(all(test, unit_test))] +mod test { + use generic_array::GenericArray; + use crate::ff::ec_prime_field::Fp25519; + use crate::ff::Serializable; + use typenum::U32; + use curve25519_dalek::scalar::Scalar; + use rand::{thread_rng, Rng}; + use crate::secret_sharing::SharedValue; + + #[test] + fn serde_25519() { + let input:[u8;32] = [ + 0x01, 0xff,0x00, 0xff,0x00, 0xff,0x00, 0xff, + 0x00, 0xff,0x00, 0xff,0x00, 0xff,0x00, 0xff, + 0x00, 0xff,0x00, 0xff,0x00, 0xff,0x00, 0xff, + 0x00, 0xff,0x00, 0xff,0x00, 0x00,0x00, 0x00 + ]; + let mut output: GenericArray = [0u8;32].into(); + let a = Fp25519::deserialize(&input.into()); + assert_eq!(a.0.as_bytes()[..32],input); + a.serialize(&mut output); + assert_eq!(a.0.as_bytes()[..32],output.as_slice()[..32]); + assert_eq!(input,output.as_slice()[..32]); + } + + // These are just simple arithmetic tests since arithmetics are checked by curve25519_dalek + #[test] + fn simple_arithmetics_25519() { + let a = Fp25519(Scalar::from_bytes_mod_order([ + 0x02, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00, + 0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00, + 0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00, + 0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00 + ])); + let b = Fp25519(Scalar::from_bytes_mod_order([ + 0x03, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00, + 0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00, + 0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00, + 0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00 + ])); + let c = Fp25519(Scalar::from_bytes_mod_order([ + 0x01, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00, + 0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00, + 0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00, + 0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00 + ])); + let d = Fp25519(Scalar::from_bytes_mod_order([ + 0x05, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00, + 0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00, + 0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00, + 0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00 + ])); + let e = Fp25519(Scalar::from_bytes_mod_order([ + 0x06, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00, + 0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00, + 0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00, + 0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00 + ])); + let cc = b-a; + let dc = a+b; + let ec = a*b; + assert_eq!(cc,c); + assert_eq!(dc,d); + assert_eq!(ec,e); + } + + #[test] + fn simple_random_25519(){ + let mut rng = thread_rng(); + assert_ne!(Fp25519::ZERO,rng.gen::()); + } + + #[test] + fn invert_25519(){ + let mut rng = thread_rng(); + let a=rng.gen::(); + let ia=a.invert(); + assert_eq!(a*ia, Fp25519(Scalar::ONE)); + } +} \ No newline at end of file diff --git a/src/ff/mod.rs b/src/ff/mod.rs index 5f18196c7..27e312663 100644 --- a/src/ff/mod.rs +++ b/src/ff/mod.rs @@ -5,6 +5,7 @@ mod field; mod galois_field; mod prime_field; +mod ec_prime_field; use std::ops::{Add, AddAssign, Sub, SubAssign}; From 786d7c85084c00f8d4651d3ec1e1492a1aed43c2 Mon Sep 17 00:00:00 2001 From: Daniel Masny Date: Mon, 2 Oct 2023 11:49:49 -0700 Subject: [PATCH 35/76] add files, make ec pub --- src/ff/mod.rs | 2 +- src/protocol/mod.rs | 2 ++ src/protocol/prf_eval/eval.rs | 0 src/protocol/prf_eval/keygen.rs | 0 src/protocol/prf_eval/mod.rs | 0 5 files changed, 3 insertions(+), 1 deletion(-) create mode 100644 src/protocol/prf_eval/eval.rs create mode 100644 src/protocol/prf_eval/keygen.rs create mode 100644 src/protocol/prf_eval/mod.rs diff --git a/src/ff/mod.rs b/src/ff/mod.rs index 27e312663..a438bee3c 100644 --- a/src/ff/mod.rs +++ b/src/ff/mod.rs @@ -5,7 +5,7 @@ mod field; mod galois_field; mod prime_field; -mod ec_prime_field; +pub mod ec_prime_field; use std::ops::{Add, AddAssign, Sub, SubAssign}; diff --git a/src/protocol/mod.rs b/src/protocol/mod.rs index 8c5e72c7d..d9d1ea382 100644 --- a/src/protocol/mod.rs +++ b/src/protocol/mod.rs @@ -6,6 +6,8 @@ pub mod context; pub mod dp; pub mod ipa; pub mod modulus_conversion; +pub mod prf_eval; +#[cfg(feature = "descriptive-gate")] pub mod prf_sharding; pub mod prss; pub mod sort; diff --git a/src/protocol/prf_eval/eval.rs b/src/protocol/prf_eval/eval.rs new file mode 100644 index 000000000..e69de29bb diff --git a/src/protocol/prf_eval/keygen.rs b/src/protocol/prf_eval/keygen.rs new file mode 100644 index 000000000..e69de29bb diff --git a/src/protocol/prf_eval/mod.rs b/src/protocol/prf_eval/mod.rs new file mode 100644 index 000000000..e69de29bb From c9cb5ee0e6859bb95e44fff3df3796be3db08f1c Mon Sep 17 00:00:00 2001 From: Daniel Masny Date: Mon, 2 Oct 2023 14:20:19 -0700 Subject: [PATCH 36/76] last commit before working on shared curve points --- src/protocol/prf_eval/eval.rs | 28 ++++++++++++++++++++++++++++ src/protocol/prf_eval/mod.rs | 2 ++ 2 files changed, 30 insertions(+) diff --git a/src/protocol/prf_eval/eval.rs b/src/protocol/prf_eval/eval.rs index e69de29bb..30c5c1d38 100644 --- a/src/protocol/prf_eval/eval.rs +++ b/src/protocol/prf_eval/eval.rs @@ -0,0 +1,28 @@ +use crate::{ + error::Error, + helpers::Direction, + ff::ec_prime_field::Fp25519, + protocol::{context::Context, step::BitOpStep, BasicProtocols, RecordId}, + secret_sharing::{Linear as LinearSecretSharing, LinearRefOps}, +}; + +/// evaluates the Dodis-Yampolski PRF g^(1/(k+x)) +/// the input x and k are secret shared over finite field Fp25519, i.e. the scalar field of curve 25519 +/// PRF key k is generated using keygen +/// In 3IPA, x is the match key +/// eval_DY outputs a u64 as specified in protocol/prf_sharding/mod.rs, all parties learn the output +pub async fn eval_dy( + ctx: C, + record_id: RecordId, + k: &[S], + x: &[S], +) -> Result + where + C: Context, + S: LinearSecretSharing + BasicProtocols, + for<'a> &'a S: LinearRefOps<'a, S, Fp25519>, +{ + let role = ctx.role(); + + Ok(5u64) +} \ No newline at end of file diff --git a/src/protocol/prf_eval/mod.rs b/src/protocol/prf_eval/mod.rs index e69de29bb..6183868b8 100644 --- a/src/protocol/prf_eval/mod.rs +++ b/src/protocol/prf_eval/mod.rs @@ -0,0 +1,2 @@ +mod eval; +mod keygen; \ No newline at end of file From 31cbde8465d81e08f9be052789ad3ba44fa9630e Mon Sep 17 00:00:00 2001 From: Daniel Masny Date: Mon, 2 Oct 2023 16:48:31 -0700 Subject: [PATCH 37/76] adding curve points + conversion --- src/ff/curve_points.rs | 170 +++++++++++++++++++++++++++++++++++++++ src/ff/ec_prime_field.rs | 6 ++ src/ff/mod.rs | 1 + 3 files changed, 177 insertions(+) create mode 100644 src/ff/curve_points.rs diff --git a/src/ff/curve_points.rs b/src/ff/curve_points.rs new file mode 100644 index 000000000..3351efc51 --- /dev/null +++ b/src/ff/curve_points.rs @@ -0,0 +1,170 @@ +use std::ops::Mul; +use generic_array::GenericArray; +use curve25519_dalek::{ristretto::{CompressedRistretto, RistrettoPoint},constants, Scalar}; +use rand_core::RngCore; +use typenum::U32; + +use crate::{ + ff::{Serializable,ec_prime_field::Fp25519}, + secret_sharing::{Block, SharedValue}, +}; + +impl Block for CompressedRistretto { + type Size = U32; +} + +///ristretto point for curve 25519 +#[derive(Clone, Copy, PartialEq, Debug)] +pub struct RP25519(::Storage); + +//how to add const ONE: Self = Self(Scalar::ONE); within the struct, do I need to do it via a trait? + +/// using compressed ristretto point, Zero is generator of the curve, i.e. g^0 +impl SharedValue for RP25519 { + type Storage = CompressedRistretto; + const BITS: u32 = 256; + const ZERO: Self = Self(constants::RISTRETTO_BASEPOINT_COMPRESSED); +} + +impl Serializable for RP25519 { + type Size = <::Storage as Block>::Size; + + fn serialize(&self, buf: &mut GenericArray) { + let raw = &self.0.as_bytes()[..buf.len()] ; + buf.copy_from_slice(raw); + } + + fn deserialize(buf: &GenericArray) -> Self { + RP25519(CompressedRistretto::from_slice(buf).unwrap()) + } +} + + +impl rand::distributions::Distribution for rand::distributions::Standard { + fn sample(&self, rng: &mut R) -> RP25519 { + //Fp25519(Scalar::random(rng: &mut R)) + let mut scalar_bytes = [0u8; 64]; + rng.fill_bytes(&mut scalar_bytes); + RP25519(RistrettoPoint::from_uniform_bytes(&scalar_bytes).compress()) + } +} + + +impl std::ops::Add for RP25519 { +type Output = Self; + +fn add(self, rhs: Self) -> Self::Output { + Self((self.0.decompress().unwrap()+rhs.0.decompress().unwrap()).compress()) +} +} + +impl std::ops::AddAssign for RP25519 { +#[allow(clippy::assign_op_pattern)] +fn add_assign(&mut self, rhs: Self) { + *self = *self + rhs; +} +} + +impl std::ops::Neg for RP25519 { +type Output = Self; + +fn neg(self) -> Self::Output { + Self(self.0.decompress().unwrap().neg().compress()) +} +} + +impl std::ops::Sub for RP25519 { +type Output = Self; + +fn sub(self, rhs: Self) -> Self::Output { + Self((self.0.decompress().unwrap()-rhs.0.decompress().unwrap()).compress()) +} +} + +impl std::ops::SubAssign for RP25519 { +#[allow(clippy::assign_op_pattern)] +fn sub_assign(&mut self, rhs: Self) { + *self = *self - rhs; +} +} + + +///Scalar Multiplication +///<'a, 'b> std::ops::Mul<&'b Fp25519> for &'a +impl RP25519 { + +fn smul(self, rhs: Fp25519) -> RP25519 { + RP25519((self.0.decompress().unwrap() * >::into(rhs)).compress()) +} +} + +///<'a> std::ops::MulAssign<&'a Fp25519> for +impl RP25519 { +#[allow(clippy::assign_op_pattern)] +fn smul_assign(&mut self, rhs: Fp25519) { + *self = self.smul(rhs); +} +} + +///do not use +impl std::ops::Mul for RP25519 { + type Output = Self; + + fn mul(self, rhs: RP25519) -> Self::Output { + Self::ZERO + } +} + +///do not use +impl std::ops::MulAssign for RP25519 { + + fn mul_assign(& mut self, rhs: RP25519) { + *self=Self::ZERO; + } +} + +impl From for RP25519 { + fn from(s: Scalar) -> Self { + RP25519(RistrettoPoint::mul_base(&s).compress()) + } +} + +impl From for RP25519 { + fn from(s: Fp25519) -> Self { + RP25519(RistrettoPoint::mul_base(&s.into()).compress()) + } +} + +// impl Into for Fp25519 { +// fn into(self) -> RP25519 { +// RP25519(RistrettoPoint::mul_base(self.into()).compress()) +// } +// } + +#[cfg(all(test, unit_test))] +mod test { + use generic_array::GenericArray; + use crate::ff::curve_points::RP25519; + use crate::ff::Serializable; + use typenum::U32; + use curve25519_dalek::scalar::Scalar; + use rand::{thread_rng, Rng}; + use crate::secret_sharing::SharedValue; + + #[test] + fn serde_25519() { + let input:[u8;32] = [ + 0x01, 0xff,0x00, 0xff,0x00, 0xff,0x00, 0xff, + 0x00, 0xff,0x00, 0xff,0x00, 0xff,0x00, 0xff, + 0x00, 0xff,0x00, 0xff,0x00, 0xff,0x00, 0xff, + 0x00, 0xff,0x00, 0xff,0x00, 0x00,0x00, 0x00 + ]; + let mut output: GenericArray = [0u8;32].into(); + let a = RP25519::deserialize(&input.into()); + assert_eq!(a.0.as_bytes()[..32],input); + a.serialize(&mut output); + assert_eq!(a.0.as_bytes()[..32],output.as_slice()[..32]); + assert_eq!(input,output.as_slice()[..32]); + } + +} \ No newline at end of file diff --git a/src/ff/ec_prime_field.rs b/src/ff/ec_prime_field.rs index c87dbfa94..5e2d13fa5 100644 --- a/src/ff/ec_prime_field.rs +++ b/src/ff/ec_prime_field.rs @@ -24,6 +24,12 @@ impl SharedValue for Fp25519 { const ZERO: Self = Self(Scalar::ZERO); } +impl Into for Fp25519 { + fn into(self) -> Scalar { + self.0 + } +} + impl Serializable for Fp25519 { type Size = <::Storage as Block>::Size; diff --git a/src/ff/mod.rs b/src/ff/mod.rs index a438bee3c..e617359d1 100644 --- a/src/ff/mod.rs +++ b/src/ff/mod.rs @@ -6,6 +6,7 @@ mod field; mod galois_field; mod prime_field; pub mod ec_prime_field; +pub mod curve_points; use std::ops::{Add, AddAssign, Sub, SubAssign}; From 6219b4cc2f44d47511b4e7d6fa084f903b4dc32d Mon Sep 17 00:00:00 2001 From: Daniel Masny Date: Tue, 3 Oct 2023 10:17:02 -0700 Subject: [PATCH 38/76] from, into scalar for RP25519 + test --- src/ff/curve_points.rs | 22 +++++++++++++++++++--- src/ff/ec_prime_field.rs | 6 ++++++ 2 files changed, 25 insertions(+), 3 deletions(-) diff --git a/src/ff/curve_points.rs b/src/ff/curve_points.rs index 3351efc51..c0236c04a 100644 --- a/src/ff/curve_points.rs +++ b/src/ff/curve_points.rs @@ -93,7 +93,7 @@ fn sub_assign(&mut self, rhs: Self) { ///<'a, 'b> std::ops::Mul<&'b Fp25519> for &'a impl RP25519 { -fn smul(self, rhs: Fp25519) -> RP25519 { +fn s_mul(self, rhs: Fp25519) -> RP25519 { RP25519((self.0.decompress().unwrap() * >::into(rhs)).compress()) } } @@ -101,8 +101,8 @@ fn smul(self, rhs: Fp25519) -> RP25519 { ///<'a> std::ops::MulAssign<&'a Fp25519> for impl RP25519 { #[allow(clippy::assign_op_pattern)] -fn smul_assign(&mut self, rhs: Fp25519) { - *self = self.smul(rhs); +fn s_mul_assign(&mut self, rhs: Fp25519) { + *self = self.s_mul(rhs); } } @@ -149,6 +149,7 @@ mod test { use typenum::U32; use curve25519_dalek::scalar::Scalar; use rand::{thread_rng, Rng}; + use crate::ff::ec_prime_field::Fp25519; use crate::secret_sharing::SharedValue; #[test] @@ -167,4 +168,19 @@ mod test { assert_eq!(input,output.as_slice()[..32]); } + #[test] + fn scalar_to_point() { + let a = Scalar::ONE; + let b : RP25519 = a.clone().into(); + let d : Fp25519 = a.into(); + let c : RP25519 = RP25519::from(d); + assert_eq!(b,RP25519::ZERO); + assert_eq!(c,RP25519::ZERO); + } + + #[test] + fn curve_arithmetics() { + + } + } \ No newline at end of file diff --git a/src/ff/ec_prime_field.rs b/src/ff/ec_prime_field.rs index 5e2d13fa5..30ee3955e 100644 --- a/src/ff/ec_prime_field.rs +++ b/src/ff/ec_prime_field.rs @@ -117,6 +117,12 @@ impl Fp25519 { } } +impl From for Fp25519 { + fn from(s: Scalar) -> Self { + Fp25519(s) + } +} + #[cfg(all(test, unit_test))] mod test { use generic_array::GenericArray; From c65a93f27de80fa1ebb82a43c557b7c301f2eee6 Mon Sep 17 00:00:00 2001 From: Daniel Masny Date: Tue, 3 Oct 2023 11:03:32 -0700 Subject: [PATCH 39/76] test aritmetics for RP25519 --- src/ff/curve_points.rs | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/ff/curve_points.rs b/src/ff/curve_points.rs index c0236c04a..1678210d7 100644 --- a/src/ff/curve_points.rs +++ b/src/ff/curve_points.rs @@ -180,7 +180,19 @@ mod test { #[test] fn curve_arithmetics() { - + let mut rng = rand::thread_rng(); + let a = rng.gen::(); + let b = rng.gen::(); + let c = a+b; + let d = RP25519::from(a)+RP25519::from(b); + assert_eq!(d, RP25519::from(c)); + assert_ne!(d, RP25519::ZERO); + let e = rng.gen::(); + let f=rng.gen::(); + let g =e*f; + let h = RP25519::from(e).s_mul(f); + assert_eq!(h,RP25519::from(g)); + assert_ne!(h, RP25519::ZERO); } } \ No newline at end of file From 1acb8696706a13206902fd71d78a3b7600a73e31 Mon Sep 17 00:00:00 2001 From: Daniel Masny Date: Wed, 4 Oct 2023 11:29:56 -0700 Subject: [PATCH 40/76] upgrade share to share --- src/ff/curve_points.rs | 3 +-- src/ff/ec_prime_field.rs | 7 ++++--- src/protocol/prf_eval/eval.rs | 13 +++++++++++-- 3 files changed, 16 insertions(+), 7 deletions(-) diff --git a/src/ff/curve_points.rs b/src/ff/curve_points.rs index 1678210d7..084b1a48d 100644 --- a/src/ff/curve_points.rs +++ b/src/ff/curve_points.rs @@ -1,4 +1,3 @@ -use std::ops::Mul; use generic_array::GenericArray; use curve25519_dalek::{ristretto::{CompressedRistretto, RistrettoPoint},constants, Scalar}; use rand_core::RngCore; @@ -180,7 +179,7 @@ mod test { #[test] fn curve_arithmetics() { - let mut rng = rand::thread_rng(); + let mut rng = thread_rng(); let a = rng.gen::(); let b = rng.gen::(); let c = a+b; diff --git a/src/ff/ec_prime_field.rs b/src/ff/ec_prime_field.rs index 30ee3955e..313cb9753 100644 --- a/src/ff/ec_prime_field.rs +++ b/src/ff/ec_prime_field.rs @@ -49,10 +49,11 @@ impl Serializable for Fp25519 { impl rand::distributions::Distribution for rand::distributions::Standard { fn sample(&self, rng: &mut R) -> Fp25519 { - //Fp25519(Scalar::random(rng: &mut R)) - let mut scalar_bytes = [0u8; 64]; + let mut scalar_bytes = [0u8; 32]; rng.fill_bytes(&mut scalar_bytes); - Fp25519(Scalar::from_bytes_mod_order_wide(&scalar_bytes)) + Fp25519(Scalar::from_bytes_mod_order(scalar_bytes)) + //not needed since above has sufficiently small bias + //Fp25519(Scalar::from_bytes_mod_order(&scalar_bytes)) } } diff --git a/src/protocol/prf_eval/eval.rs b/src/protocol/prf_eval/eval.rs index 30c5c1d38..0307f42b8 100644 --- a/src/protocol/prf_eval/eval.rs +++ b/src/protocol/prf_eval/eval.rs @@ -1,11 +1,20 @@ use crate::{ error::Error, helpers::Direction, - ff::ec_prime_field::Fp25519, + ff::{ec_prime_field::Fp25519, curve_points::RP25519}, protocol::{context::Context, step::BitOpStep, BasicProtocols, RecordId}, - secret_sharing::{Linear as LinearSecretSharing, LinearRefOps}, + secret_sharing::{Linear as LinearSecretSharing, LinearRefOps, SharedValue, replicated::{semi_honest::AdditiveShare,ReplicatedSecretSharing}}, }; + +impl Into> for AdditiveShare { + fn into(self) -> AdditiveShare + { + AdditiveShare::new(RP25519::from(self.left()),RP25519::from(self.right())) + } +} + + /// evaluates the Dodis-Yampolski PRF g^(1/(k+x)) /// the input x and k are secret shared over finite field Fp25519, i.e. the scalar field of curve 25519 /// PRF key k is generated using keygen From 644a6fc59afab5ca1e58f15116f82b0b658f0ae5 Mon Sep 17 00:00:00 2001 From: Daniel Masny Date: Wed, 4 Oct 2023 11:57:10 -0700 Subject: [PATCH 41/76] remove warning --- src/ff/ec_prime_field.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ff/ec_prime_field.rs b/src/ff/ec_prime_field.rs index 313cb9753..cedad411a 100644 --- a/src/ff/ec_prime_field.rs +++ b/src/ff/ec_prime_field.rs @@ -1,6 +1,6 @@ use generic_array::GenericArray; use curve25519_dalek::scalar::Scalar; -use rand_core::RngCore; +//use rand_core::RngCore; use typenum::U32; use crate::{ From 851f624e826e72593df78af684eabe13565ff151 Mon Sep 17 00:00:00 2001 From: Daniel Masny Date: Wed, 4 Oct 2023 15:47:45 -0700 Subject: [PATCH 42/76] add hash curve points --- src/ff/curve_points.rs | 65 +++++++++++++++++++++++++++++----------- src/ff/ec_prime_field.rs | 31 +++++++++---------- 2 files changed, 61 insertions(+), 35 deletions(-) diff --git a/src/ff/curve_points.rs b/src/ff/curve_points.rs index 084b1a48d..eed23e5ec 100644 --- a/src/ff/curve_points.rs +++ b/src/ff/curve_points.rs @@ -1,7 +1,9 @@ use generic_array::GenericArray; use curve25519_dalek::{ristretto::{CompressedRistretto, RistrettoPoint},constants, Scalar}; -use rand_core::RngCore; use typenum::U32; +use sha2::Sha256; +use hkdf::Hkdf; + use crate::{ ff::{Serializable,ec_prime_field::Fp25519}, @@ -93,32 +95,25 @@ fn sub_assign(&mut self, rhs: Self) { impl RP25519 { fn s_mul(self, rhs: Fp25519) -> RP25519 { - RP25519((self.0.decompress().unwrap() * >::into(rhs)).compress()) + RP25519((self.0.decompress().unwrap() * Scalar::from(rhs)).compress()) } } -///<'a> std::ops::MulAssign<&'a Fp25519> for -impl RP25519 { -#[allow(clippy::assign_op_pattern)] -fn s_mul_assign(&mut self, rhs: Fp25519) { - *self = self.s_mul(rhs); -} -} ///do not use impl std::ops::Mul for RP25519 { type Output = Self; - fn mul(self, rhs: RP25519) -> Self::Output { - Self::ZERO + fn mul(self, _rhs: RP25519) -> Self::Output { + panic!("Two curve points cannot be multiplied! Do not use *, *= for RP25519 or secret shares of RP25519"); } } ///do not use impl std::ops::MulAssign for RP25519 { - fn mul_assign(& mut self, rhs: RP25519) { - *self=Self::ZERO; + fn mul_assign(& mut self, _rhs: RP25519) { + panic!("Two curve points cannot be multiplied! Do not use *, *= for RP25519 or secret shares of RP25519"); } } @@ -134,11 +129,36 @@ impl From for RP25519 { } } -// impl Into for Fp25519 { -// fn into(self) -> RP25519 { -// RP25519(RistrettoPoint::mul_base(self.into()).compress()) -// } -// } +macro_rules! cp_hash_impl { + ( $u_type:ty, $byte_size:literal) => { + impl From for $u_type { + fn from(s: RP25519) -> Self { + let hk = Hkdf::::new(None, s.0.as_bytes()); + let mut okm = [0u8; $byte_size]; + //error invalid length from expand only happens when okm is very large + hk.expand(&[], &mut okm).unwrap(); + <$u_type>::from_le_bytes(okm) + } + } + } +} + +cp_hash_impl!( + u128, + 16 +); + +cp_hash_impl!( + u64, + 8 +); + +cp_hash_impl!( + u32, + 4 +); + + #[cfg(all(test, unit_test))] mod test { @@ -194,4 +214,13 @@ mod test { assert_ne!(h, RP25519::ZERO); } + #[test] + fn curve_point_to_hash() { + let mut rng = thread_rng(); + let a = rng.gen::(); + assert_ne!(0u128,u128::from(a)); + assert_ne!(0u64,u64::from(a)); + assert_ne!(0u32,u32::from(a)); + } + } \ No newline at end of file diff --git a/src/ff/ec_prime_field.rs b/src/ff/ec_prime_field.rs index cedad411a..3e4f762d8 100644 --- a/src/ff/ec_prime_field.rs +++ b/src/ff/ec_prime_field.rs @@ -15,7 +15,16 @@ impl Block for Scalar { #[derive(Clone, Copy, PartialEq, Debug)] pub struct Fp25519(::Storage); -//how to add const ONE: Self = Self(Scalar::ONE); within the struct, do I need to do it via a trait? + +impl Fp25519 { + const ONE: Self = Self(Scalar::ONE); + + //must not use with ZERO + pub fn invert(&self) -> Fp25519 { + Fp25519(self.0.invert()) + } + +} impl SharedValue for Fp25519 { @@ -24,9 +33,9 @@ impl SharedValue for Fp25519 { const ZERO: Self = Self(Scalar::ZERO); } -impl Into for Fp25519 { - fn into(self) -> Scalar { - self.0 +impl From for Scalar { + fn from(s: Fp25519) -> Self { + s.0 } } @@ -111,12 +120,6 @@ fn mul_assign(&mut self, rhs: Self) { } } -//must not use with ZERO -impl Fp25519 { - pub fn invert(&self) -> Fp25519 { - Fp25519(self.0.invert()) - } -} impl From for Fp25519 { fn from(s: Scalar) -> Self { @@ -165,12 +168,6 @@ mod test { 0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00, 0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00 ])); - let c = Fp25519(Scalar::from_bytes_mod_order([ - 0x01, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00, - 0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00, - 0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00, - 0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00 - ])); let d = Fp25519(Scalar::from_bytes_mod_order([ 0x05, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00, 0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00, @@ -186,7 +183,7 @@ mod test { let cc = b-a; let dc = a+b; let ec = a*b; - assert_eq!(cc,c); + assert_eq!(cc,Fp25519::ONE); assert_eq!(dc,d); assert_eq!(ec,e); } From 45b2a46122c0f6e4799ffacb9bf0fe037cd6d6e6 Mon Sep 17 00:00:00 2001 From: Daniel Masny Date: Thu, 5 Oct 2023 13:46:24 -0700 Subject: [PATCH 43/76] implementation of PRF eval protocol --- src/ff/curve_points.rs | 72 ++++++++++++++++++++++++++---- src/ff/ec_prime_field.rs | 79 ++++++++++++++++++++++++++++++++- src/protocol/prf_eval/eval.rs | 37 --------------- src/protocol/prf_eval/keygen.rs | 0 src/protocol/prf_eval/mod.rs | 67 +++++++++++++++++++++++++++- 5 files changed, 206 insertions(+), 49 deletions(-) delete mode 100644 src/protocol/prf_eval/eval.rs delete mode 100644 src/protocol/prf_eval/keygen.rs diff --git a/src/ff/curve_points.rs b/src/ff/curve_points.rs index eed23e5ec..fad671dd0 100644 --- a/src/ff/curve_points.rs +++ b/src/ff/curve_points.rs @@ -6,7 +6,7 @@ use hkdf::Hkdf; use crate::{ - ff::{Serializable,ec_prime_field::Fp25519}, + ff::{Serializable,ec_prime_field::Fp25519,Field}, secret_sharing::{Block, SharedValue}, }; @@ -93,8 +93,9 @@ fn sub_assign(&mut self, rhs: Self) { ///Scalar Multiplication ///<'a, 'b> std::ops::Mul<&'b Fp25519> for &'a impl RP25519 { + pub const ONE: Self = Self(constants::RISTRETTO_BASEPOINT_COMPRESSED); -fn s_mul(self, rhs: Fp25519) -> RP25519 { +pub fn s_mul(self, rhs: Fp25519) -> RP25519 { RP25519((self.0.decompress().unwrap() * Scalar::from(rhs)).compress()) } } @@ -129,6 +130,18 @@ impl From for RP25519 { } } +impl From for RP25519 { + fn from(s: CompressedRistretto) -> Self { + RP25519(s) + } +} + +impl From for CompressedRistretto { + fn from(s: RP25519) -> Self { + s.0 + } +} + macro_rules! cp_hash_impl { ( $u_type:ty, $byte_size:literal) => { impl From for $u_type { @@ -140,14 +153,19 @@ macro_rules! cp_hash_impl { <$u_type>::from_le_bytes(okm) } } + + impl From<$u_type> for RP25519 { + fn from(s: $u_type) -> Self { + let hk = Hkdf::::new(None, &s.to_le_bytes()); + let mut okm = [0u8; 32]; + //error invalid length from expand only happens when okm is very large + hk.expand(&[], &mut okm).unwrap(); + RP25519::deserialize(&okm.into()) + } + } } } -cp_hash_impl!( - u128, - 16 -); - cp_hash_impl!( u64, 8 @@ -158,6 +176,45 @@ cp_hash_impl!( 4 ); +/// Daniel had to implement this since Reveal wants it, prefer not to, I dont understand why it is +/// actually needed there, maybe to upgrade it to malicious? but it still shouldn't be needed +impl Field for RP25519 { + const ONE: RP25519= RP25519::ONE; + + ///both following methods are based on hashing and do not allow to actually convert elements in Fp25519 + /// from or into u128. However it is sufficient to generate random elements in Fp25519 + fn as_u128(&self) -> u128 { + let hk = Hkdf::::new(None, self.0.as_bytes()); + let mut okm = [0u8; 16]; + //error invalid length from expand only happens when okm is very large + hk.expand(&[], &mut okm).unwrap(); + u128::from_le_bytes(okm) + } + + ///PRSS uses truncate_from function, we need to expand the u128 using a PRG (Sha256) to a [u8;32] + fn truncate_from>(v: T) -> Self { + let hk = Hkdf::::new(None, &v.into().to_le_bytes()); + let mut okm = [0u8; 32]; + //error invalid length from expand only happens when okm is very large + hk.expand(&[], &mut okm).unwrap(); + RP25519::deserialize(&okm.into()) + } + +} + +impl TryFrom for RP25519 { + type Error = crate::error::Error; + + fn try_from(v: u128) -> Result { + let mut bits = [0u8; 32]; + bits[..].copy_from_slice(&v.to_le_bytes()); + let f: RP25519=RP25519::ONE; + f.serialize((&mut bits).into()); + Ok(f) + } +} + + #[cfg(all(test, unit_test))] @@ -218,7 +275,6 @@ mod test { fn curve_point_to_hash() { let mut rng = thread_rng(); let a = rng.gen::(); - assert_ne!(0u128,u128::from(a)); assert_ne!(0u64,u64::from(a)); assert_ne!(0u32,u32::from(a)); } diff --git a/src/ff/ec_prime_field.rs b/src/ff/ec_prime_field.rs index 3e4f762d8..2f88b07cc 100644 --- a/src/ff/ec_prime_field.rs +++ b/src/ff/ec_prime_field.rs @@ -2,9 +2,11 @@ use generic_array::GenericArray; use curve25519_dalek::scalar::Scalar; //use rand_core::RngCore; use typenum::U32; +use sha2::Sha256; +use hkdf::Hkdf; use crate::{ - ff::Serializable, + ff::{Serializable, Field}, secret_sharing::{Block, SharedValue}, }; @@ -17,7 +19,7 @@ pub struct Fp25519(::Storage); impl Fp25519 { - const ONE: Self = Self(Scalar::ONE); + pub const ONE: Self = Self(Scalar::ONE); //must not use with ZERO pub fn invert(&self) -> Fp25519 { @@ -127,6 +129,79 @@ impl From for Fp25519 { } } +macro_rules! sc_hash_impl { + ( $u_type:ty, $byte_size:literal) => { + impl From for $u_type { + fn from(s: Fp25519) -> Self { + let hk = Hkdf::::new(None, s.0.as_bytes()); + let mut okm = [0u8; $byte_size]; + //error invalid length from expand only happens when okm is very large + hk.expand(&[], &mut okm).unwrap(); + <$u_type>::from_le_bytes(okm) + } + } + + impl From<$u_type> for Fp25519 { + fn from(s: $u_type) -> Self { + let hk = Hkdf::::new(None, &s.to_le_bytes()); + let mut okm = [0u8; 32]; + //error invalid length from expand only happens when okm is very large + hk.expand(&[], &mut okm).unwrap(); + Fp25519::deserialize(&okm.into()) + } + } + } +} + + +sc_hash_impl!( + u64, + 8 +); + +sc_hash_impl!( + u32, + 4 +); + + +/// Daniel had to implement this since PRSS wants it, prefer not to +impl Field for Fp25519 { + const ONE: Fp25519= Fp25519::ONE; + + ///both following methods are based on hashing and do not allow to actually convert elements in Fp25519 + /// from or into u128. However it is sufficient to generate random elements in Fp25519 + fn as_u128(&self) -> u128 { + let hk = Hkdf::::new(None, self.0.as_bytes()); + let mut okm = [0u8; 16]; + //error invalid length from expand only happens when okm is very large + hk.expand(&[], &mut okm).unwrap(); + u128::from_le_bytes(okm) + } + + ///PRSS uses truncate_from function, we need to expand the u128 using a PRG (Sha256) to a [u8;32] + fn truncate_from>(v: T) -> Self { + let hk = Hkdf::::new(None, &v.into().to_le_bytes()); + let mut okm = [0u8; 32]; + //error invalid length from expand only happens when okm is very large + hk.expand(&[], &mut okm).unwrap(); + Fp25519::deserialize(&okm.into()) + } + +} + +impl TryFrom for Fp25519 { + type Error = crate::error::Error; + + fn try_from(v: u128) -> Result { + let mut bits = [0u8; 32]; + bits[..].copy_from_slice(&v.to_le_bytes()); + let f: Fp25519=Fp25519::ONE; + f.serialize((&mut bits).into()); + Ok(f) + } +} + #[cfg(all(test, unit_test))] mod test { use generic_array::GenericArray; diff --git a/src/protocol/prf_eval/eval.rs b/src/protocol/prf_eval/eval.rs deleted file mode 100644 index 0307f42b8..000000000 --- a/src/protocol/prf_eval/eval.rs +++ /dev/null @@ -1,37 +0,0 @@ -use crate::{ - error::Error, - helpers::Direction, - ff::{ec_prime_field::Fp25519, curve_points::RP25519}, - protocol::{context::Context, step::BitOpStep, BasicProtocols, RecordId}, - secret_sharing::{Linear as LinearSecretSharing, LinearRefOps, SharedValue, replicated::{semi_honest::AdditiveShare,ReplicatedSecretSharing}}, -}; - - -impl Into> for AdditiveShare { - fn into(self) -> AdditiveShare - { - AdditiveShare::new(RP25519::from(self.left()),RP25519::from(self.right())) - } -} - - -/// evaluates the Dodis-Yampolski PRF g^(1/(k+x)) -/// the input x and k are secret shared over finite field Fp25519, i.e. the scalar field of curve 25519 -/// PRF key k is generated using keygen -/// In 3IPA, x is the match key -/// eval_DY outputs a u64 as specified in protocol/prf_sharding/mod.rs, all parties learn the output -pub async fn eval_dy( - ctx: C, - record_id: RecordId, - k: &[S], - x: &[S], -) -> Result - where - C: Context, - S: LinearSecretSharing + BasicProtocols, - for<'a> &'a S: LinearRefOps<'a, S, Fp25519>, -{ - let role = ctx.role(); - - Ok(5u64) -} \ No newline at end of file diff --git a/src/protocol/prf_eval/keygen.rs b/src/protocol/prf_eval/keygen.rs deleted file mode 100644 index e69de29bb..000000000 diff --git a/src/protocol/prf_eval/mod.rs b/src/protocol/prf_eval/mod.rs index 6183868b8..193cb360c 100644 --- a/src/protocol/prf_eval/mod.rs +++ b/src/protocol/prf_eval/mod.rs @@ -1,2 +1,65 @@ -mod eval; -mod keygen; \ No newline at end of file +use crate::{ + error::Error, + ff::{ec_prime_field::Fp25519, curve_points::RP25519}, + protocol::{context::Context, RecordId, prss::SharedRandomness, basics::Reveal, basics::SecureMul}, + secret_sharing::{replicated::{semi_honest::AdditiveShare,ReplicatedSecretSharing}}, +}; + + +impl From> for AdditiveShare { + fn from(s: AdditiveShare) -> Self { + AdditiveShare::new(RP25519::from(s.left()),RP25519::from(s.right())) + } +} + +/// generates PRF key k as secret sharing over Fp25519 +pub fn gen_prf_key (ctx: C) -> AdditiveShare + where + C: Context, +{ + ctx.prss().generate_replicated(u128::MAX-100u128) +} + + +/// evaluates the Dodis-Yampolski PRF g^(1/(k+x)) +/// the input x and k are secret shared over finite field Fp25519, i.e. the scalar field of curve 25519 +/// PRF key k is generated using keygen +/// In 3IPA, x is the match key +/// eval_DY outputs a u64 as specified in protocol/prf_sharding/mod.rs, all parties learn the output +pub async fn eval_dy_prf( + ctx: C, + record_id: RecordId, + k: &AdditiveShare, + x: &AdditiveShare, +) -> Result + where + C: Context, +{ + // generate random shares using shared randomness, use index max/2 to not clash with multiply + let sh_r: AdditiveShare = ctx.prss().generate_replicated(u128::MAX/2+u128::from(record_id)); + + //compute (g^left, g^right) + let sh_gr = AdditiveShare::::from(sh_r.clone()); + + //compute x+k + let y =x+k; + + //compute y <- r*y + //Daniel: probably shouldn't use ctx anymore? why doesn't y need to be mutable? + y.multiply(&sh_r, ctx.clone(), record_id).await?; + + //reconstruct (z,R) + let mut gr: RP25519 = sh_gr.reveal(ctx, record_id).await?; + + //invert z + let mut z: Fp25519 = Fp25519::ONE; + z=z.invert(); + //compute R^z + gr=gr.s_mul(z); + Ok(u64::from(gr)) +} + +#[cfg(all(test, unit_test))] +mod test { + +} \ No newline at end of file From dd07d7ac48c13377e3d5254b85d617e4f2ad0de3 Mon Sep 17 00:00:00 2001 From: Daniel Masny Date: Fri, 6 Oct 2023 13:47:06 -0700 Subject: [PATCH 44/76] prf eval test passes --- src/protocol/prf_eval/mod.rs | 134 +++++++++++++++++++++++++++++++---- 1 file changed, 119 insertions(+), 15 deletions(-) diff --git a/src/protocol/prf_eval/mod.rs b/src/protocol/prf_eval/mod.rs index 193cb360c..e3d0cd6a4 100644 --- a/src/protocol/prf_eval/mod.rs +++ b/src/protocol/prf_eval/mod.rs @@ -3,7 +3,31 @@ use crate::{ ff::{ec_prime_field::Fp25519, curve_points::RP25519}, protocol::{context::Context, RecordId, prss::SharedRandomness, basics::Reveal, basics::SecureMul}, secret_sharing::{replicated::{semi_honest::AdditiveShare,ReplicatedSecretSharing}}, + seq_join::seq_try_join_all, }; +use ipa_macros::Step; + +#[derive(Step)] +pub(crate) enum Step { + PRFKeyGen, + GenRandomMask, + MultMaskWithPRFInput, + RevealR, + Revealz, +} + +pub async fn compute_match_key_pseudonym( + sh_ctx: C, + prf_key: AdditiveShare, + input_match_keys: Vec>, +) -> Result, Error> + where + C: Context, +{ + let ctx =sh_ctx.set_total_records(input_match_keys.len()); + let futures=input_match_keys.iter().enumerate().map(|(i,x)|eval_dy_prf(ctx.clone(),i.into(),&prf_key,x)); + Ok(seq_try_join_all(sh_ctx.active_work(), futures).await?.iter().map(|&x|u64::from(x)).collect()) +} impl From> for AdditiveShare { @@ -17,7 +41,7 @@ pub fn gen_prf_key (ctx: C) -> AdditiveShare where C: Context, { - ctx.prss().generate_replicated(u128::MAX-100u128) + ctx.narrow(&Step::PRFKeyGen).prss().generate_replicated(u128::MAX-100u128) } @@ -26,7 +50,7 @@ pub fn gen_prf_key (ctx: C) -> AdditiveShare /// PRF key k is generated using keygen /// In 3IPA, x is the match key /// eval_DY outputs a u64 as specified in protocol/prf_sharding/mod.rs, all parties learn the output -pub async fn eval_dy_prf( +pub async fn eval_dy_prf( ctx: C, record_id: RecordId, k: &AdditiveShare, @@ -35,31 +59,111 @@ pub async fn eval_dy_prf( where C: Context, { - // generate random shares using shared randomness, use index max/2 to not clash with multiply - let sh_r: AdditiveShare = ctx.prss().generate_replicated(u128::MAX/2+u128::from(record_id)); + let sh_r: AdditiveShare = ctx.narrow(&Step::GenRandomMask).prss().generate_replicated(record_id); //compute (g^left, g^right) let sh_gr = AdditiveShare::::from(sh_r.clone()); //compute x+k - let y =x+k; + let mut y =x+k; //compute y <- r*y - //Daniel: probably shouldn't use ctx anymore? why doesn't y need to be mutable? - y.multiply(&sh_r, ctx.clone(), record_id).await?; + y = y.multiply(&sh_r, ctx.narrow(&Step::MultMaskWithPRFInput), record_id).await?; //reconstruct (z,R) - let mut gr: RP25519 = sh_gr.reveal(ctx, record_id).await?; - - //invert z - let mut z: Fp25519 = Fp25519::ONE; - z=z.invert(); - //compute R^z - gr=gr.s_mul(z); - Ok(u64::from(gr)) + let gr: RP25519 = sh_gr.reveal(ctx.narrow(&Step::RevealR), record_id).await?; + let z = y.reveal(ctx.narrow(&Step::Revealz), record_id).await?; + + + + //compute R^(1/z) to u64 + Ok(u64::from(gr.s_mul(z.invert()))) } #[cfg(all(test, unit_test))] mod test { + use rand::Rng; + use crate::{ + test_executor::run, + test_fixture::{TestWorld, Reconstruct, Runner}, + ff::{ec_prime_field::Fp25519, curve_points::RP25519}, + secret_sharing::{IntoShares,replicated::semi_honest::AdditiveShare}, + protocol::prf_eval::{compute_match_key_pseudonym}, + }; + + #[derive(Copy, Clone)] + struct ShuffledTestInput { + match_key: Fp25519, + } + + #[derive(Debug, PartialEq)] + struct TestOutput { + match_key_pseudonym: u64, + } + + fn test_input( mk: u64) -> ShuffledTestInput { + ShuffledTestInput { + match_key: Fp25519::from(mk), + } + } + + impl IntoShares> for ShuffledTestInput + { + fn share_with(self, rng: &mut R) -> [AdditiveShare; 3] { + self.match_key.share_with(rng) + } + } + + + impl Reconstruct for [&u64; 3] { + fn reconstruct(&self) -> TestOutput { + TestOutput{ + match_key_pseudonym: if *self[0]==*self[1] && *self[0]==*self[2] {*self[0]} else {0u64}, + } + } + } + + + #[test] + fn semi_honest() { + run(|| async move { + let world = TestWorld::default(); + + //first two need to be identical for test to succeed + let records: Vec = vec![ + test_input(3), + test_input(3), + test_input(23443524523), + test_input(56), + test_input(895764542), + test_input(456764576), + test_input(56), + test_input(3), + test_input(56), + test_input(23443524523), + ]; + + //PRF Key Gen + let u = 3216412445u64; + let k:Fp25519 = Fp25519::from(u); + + let expected: Vec=records.iter().map(|&x| TestOutput{match_key_pseudonym: (RP25519::from((x.match_key+k).invert())).into()} ).collect(); + + let result: Vec<_> = world + .semi_honest((records.into_iter(),k), |ctx, (input_match_keys,prf_key)| async move { + compute_match_key_pseudonym::<_>( + ctx, + prf_key, + input_match_keys, + ) + .await + .unwrap() + }) + .await + .reconstruct(); + assert_eq!(result, expected); + assert_eq!(result[0], result[1]); + }); + } } \ No newline at end of file From e1cb4b73428c48fd22b4a41117e424ddc12de1c5 Mon Sep 17 00:00:00 2001 From: Daniel Masny Date: Mon, 9 Oct 2023 15:03:41 -0700 Subject: [PATCH 45/76] fixed clippy complaints, panics when setting invalid curve points or multiply curve points --- src/error.rs | 2 ++ src/ff/curve_points.rs | 47 +++++++++++++++++++++--------------- src/ff/ec_prime_field.rs | 3 ++- src/protocol/prf_eval/mod.rs | 23 +++++++++++------- 4 files changed, 45 insertions(+), 30 deletions(-) diff --git a/src/error.rs b/src/error.rs index c68b325a8..7d6456c7f 100644 --- a/src/error.rs +++ b/src/error.rs @@ -58,6 +58,8 @@ pub enum Error { InvalidReport(#[from] InvalidReportError), #[error("unsupported: {0}")] Unsupported(String), + #[error("Decompressing invalid elliptic curve point")] + DecompressingInvalidCurvePoint, } impl Default for Error { diff --git a/src/ff/curve_points.rs b/src/ff/curve_points.rs index fad671dd0..d04eec535 100644 --- a/src/ff/curve_points.rs +++ b/src/ff/curve_points.rs @@ -5,7 +5,9 @@ use sha2::Sha256; use hkdf::Hkdf; + use crate::{ + error::Error, ff::{Serializable,ec_prime_field::Fp25519,Field}, secret_sharing::{Block, SharedValue}, }; @@ -91,12 +93,17 @@ fn sub_assign(&mut self, rhs: Self) { ///Scalar Multiplication -///<'a, 'b> std::ops::Mul<&'b Fp25519> for &'a +///<'a, 'b> `std::ops::Mul<&'b"` Fp25519 for &'a impl RP25519 { pub const ONE: Self = Self(constants::RISTRETTO_BASEPOINT_COMPRESSED); -pub fn s_mul(self, rhs: Fp25519) -> RP25519 { - RP25519((self.0.decompress().unwrap() * Scalar::from(rhs)).compress()) + /// # Errors + /// Propagates errors from decompressing invalid curve point +pub fn s_mul(self, rhs: Fp25519) -> Result { + self.0.decompress().map_or( + Err(Error::DecompressingInvalidCurvePoint), + |x| Ok((x * Scalar::from(rhs)).compress().into()) + ) } } @@ -191,7 +198,7 @@ impl Field for RP25519 { u128::from_le_bytes(okm) } - ///PRSS uses truncate_from function, we need to expand the u128 using a PRG (Sha256) to a [u8;32] + ///PRSS uses `truncate_from function`, we need to expand the u128 using a PRG (Sha256) to a [u8;32] fn truncate_from>(v: T) -> Self { let hk = Hkdf::::new(None, &v.into().to_le_bytes()); let mut okm = [0u8; 32]; @@ -247,7 +254,7 @@ mod test { #[test] fn scalar_to_point() { let a = Scalar::ONE; - let b : RP25519 = a.clone().into(); + let b : RP25519 = a.into(); let d : Fp25519 = a.into(); let c : RP25519 = RP25519::from(d); assert_eq!(b,RP25519::ZERO); @@ -257,26 +264,26 @@ mod test { #[test] fn curve_arithmetics() { let mut rng = thread_rng(); - let a = rng.gen::(); - let b = rng.gen::(); - let c = a+b; - let d = RP25519::from(a)+RP25519::from(b); - assert_eq!(d, RP25519::from(c)); - assert_ne!(d, RP25519::ZERO); - let e = rng.gen::(); - let f=rng.gen::(); - let g =e*f; - let h = RP25519::from(e).s_mul(f); - assert_eq!(h,RP25519::from(g)); - assert_ne!(h, RP25519::ZERO); + let fp_a = rng.gen::(); + let fp_b = rng.gen::(); + let fp_c = fp_a+fp_b; + let fp_d = RP25519::from(fp_a)+RP25519::from(fp_b); + assert_eq!(fp_d, RP25519::from(fp_c)); + assert_ne!(fp_d, RP25519::ZERO); + let fp_e = rng.gen::(); + let fp_f=rng.gen::(); + let fp_g =fp_e*fp_f; + let fp_h = RP25519::from(fp_e).s_mul(fp_f).unwrap(); + assert_eq!(fp_h,RP25519::from(fp_g)); + assert_ne!(fp_h, RP25519::ZERO); } #[test] fn curve_point_to_hash() { let mut rng = thread_rng(); - let a = rng.gen::(); - assert_ne!(0u64,u64::from(a)); - assert_ne!(0u32,u32::from(a)); + let fp_a = rng.gen::(); + assert_ne!(0u64,u64::from(fp_a)); + assert_ne!(0u32,u32::from(fp_a)); } } \ No newline at end of file diff --git a/src/ff/ec_prime_field.rs b/src/ff/ec_prime_field.rs index 2f88b07cc..624f91c64 100644 --- a/src/ff/ec_prime_field.rs +++ b/src/ff/ec_prime_field.rs @@ -22,6 +22,7 @@ impl Fp25519 { pub const ONE: Self = Self(Scalar::ONE); //must not use with ZERO + #[must_use] pub fn invert(&self) -> Fp25519 { Fp25519(self.0.invert()) } @@ -179,7 +180,7 @@ impl Field for Fp25519 { u128::from_le_bytes(okm) } - ///PRSS uses truncate_from function, we need to expand the u128 using a PRG (Sha256) to a [u8;32] + ///PRSS uses `truncate_from function`, we need to expand the u128 using a PRG (Sha256) to a [u8;32] fn truncate_from>(v: T) -> Self { let hk = Hkdf::::new(None, &v.into().to_le_bytes()); let mut okm = [0u8; 32]; diff --git a/src/protocol/prf_eval/mod.rs b/src/protocol/prf_eval/mod.rs index e3d0cd6a4..895ad524b 100644 --- a/src/protocol/prf_eval/mod.rs +++ b/src/protocol/prf_eval/mod.rs @@ -16,6 +16,8 @@ pub(crate) enum Step { Revealz, } +/// # Errors +/// Propagates errors from multiplications pub async fn compute_match_key_pseudonym( sh_ctx: C, prf_key: AdditiveShare, @@ -26,7 +28,7 @@ pub async fn compute_match_key_pseudonym( { let ctx =sh_ctx.set_total_records(input_match_keys.len()); let futures=input_match_keys.iter().enumerate().map(|(i,x)|eval_dy_prf(ctx.clone(),i.into(),&prf_key,x)); - Ok(seq_try_join_all(sh_ctx.active_work(), futures).await?.iter().map(|&x|u64::from(x)).collect()) + seq_try_join_all(sh_ctx.active_work(), futures).await } @@ -37,7 +39,7 @@ impl From> for AdditiveShare { } /// generates PRF key k as secret sharing over Fp25519 -pub fn gen_prf_key (ctx: C) -> AdditiveShare +pub fn gen_prf_key (ctx: &C) -> AdditiveShare where C: Context, { @@ -49,7 +51,10 @@ pub fn gen_prf_key (ctx: C) -> AdditiveShare /// the input x and k are secret shared over finite field Fp25519, i.e. the scalar field of curve 25519 /// PRF key k is generated using keygen /// In 3IPA, x is the match key -/// eval_DY outputs a u64 as specified in protocol/prf_sharding/mod.rs, all parties learn the output +/// outputs a u64 as specified in `protocol/prf_sharding/mod.rs`, all parties learn the output +/// # Errors +/// Propagates errors from multiplications, reveal and scalar multiplication + pub async fn eval_dy_prf( ctx: C, record_id: RecordId, @@ -77,7 +82,7 @@ pub async fn eval_dy_prf( //compute R^(1/z) to u64 - Ok(u64::from(gr.s_mul(z.invert()))) + Ok(u64::from(gr.s_mul(z.invert())?)) } #[cfg(all(test, unit_test))] @@ -133,18 +138,18 @@ mod test { let records: Vec = vec![ test_input(3), test_input(3), - test_input(23443524523), + test_input(23_443_524_523), test_input(56), - test_input(895764542), - test_input(456764576), + test_input(895_764_542), + test_input(456_764_576), test_input(56), test_input(3), test_input(56), - test_input(23443524523), + test_input(23_443_524_523), ]; //PRF Key Gen - let u = 3216412445u64; + let u = 3_216_412_445u64; let k:Fp25519 = Fp25519::from(u); let expected: Vec=records.iter().map(|&x| TestOutput{match_key_pseudonym: (RP25519::from((x.match_key+k).invert())).into()} ).collect(); From b2f5c7836c838488a7c959560e10b0f2b9753f6c Mon Sep 17 00:00:00 2001 From: Daniel Masny Date: Mon, 9 Oct 2023 15:49:42 -0700 Subject: [PATCH 46/76] remove comment --- src/ff/curve_points.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/ff/curve_points.rs b/src/ff/curve_points.rs index d04eec535..b8d6a2882 100644 --- a/src/ff/curve_points.rs +++ b/src/ff/curve_points.rs @@ -20,8 +20,6 @@ impl Block for CompressedRistretto { #[derive(Clone, Copy, PartialEq, Debug)] pub struct RP25519(::Storage); -//how to add const ONE: Self = Self(Scalar::ONE); within the struct, do I need to do it via a trait? - /// using compressed ristretto point, Zero is generator of the curve, i.e. g^0 impl SharedValue for RP25519 { type Storage = CompressedRistretto; From 8b0ab7743f1409ed9270b75fc1cae2d04fad6221 Mon Sep 17 00:00:00 2001 From: Daniel Masny Date: Mon, 9 Oct 2023 16:29:30 -0700 Subject: [PATCH 47/76] adding some of Martins suggestions --- src/ff/curve_points.rs | 159 ++++++++++++++----------------- src/ff/ec_prime_field.rs | 176 ++++++++++++++++------------------- src/ff/mod.rs | 4 +- src/protocol/prf_eval/mod.rs | 111 ++++++++++++---------- 4 files changed, 217 insertions(+), 233 deletions(-) diff --git a/src/ff/curve_points.rs b/src/ff/curve_points.rs index b8d6a2882..2b1f60f94 100644 --- a/src/ff/curve_points.rs +++ b/src/ff/curve_points.rs @@ -1,14 +1,16 @@ +use curve25519_dalek::{ + constants, + ristretto::{CompressedRistretto, RistrettoPoint}, + Scalar, +}; use generic_array::GenericArray; -use curve25519_dalek::{ristretto::{CompressedRistretto, RistrettoPoint},constants, Scalar}; -use typenum::U32; -use sha2::Sha256; use hkdf::Hkdf; - - +use sha2::Sha256; +use typenum::U32; use crate::{ error::Error, - ff::{Serializable,ec_prime_field::Fp25519,Field}, + ff::{ec_prime_field::Fp25519, Field, Serializable}, secret_sharing::{Block, SharedValue}, }; @@ -31,7 +33,7 @@ impl Serializable for RP25519 { type Size = <::Storage as Block>::Size; fn serialize(&self, buf: &mut GenericArray) { - let raw = &self.0.as_bytes()[..buf.len()] ; + let raw = &self.0.as_bytes()[..buf.len()]; buf.copy_from_slice(raw); } @@ -40,7 +42,6 @@ impl Serializable for RP25519 { } } - impl rand::distributions::Distribution for rand::distributions::Standard { fn sample(&self, rng: &mut R) -> RP25519 { //Fp25519(Scalar::random(rng: &mut R)) @@ -50,62 +51,59 @@ impl rand::distributions::Distribution for rand::distributions::Standar } } - impl std::ops::Add for RP25519 { -type Output = Self; + type Output = Self; -fn add(self, rhs: Self) -> Self::Output { - Self((self.0.decompress().unwrap()+rhs.0.decompress().unwrap()).compress()) -} + fn add(self, rhs: Self) -> Self::Output { + Self((self.0.decompress().unwrap() + rhs.0.decompress().unwrap()).compress()) + } } impl std::ops::AddAssign for RP25519 { -#[allow(clippy::assign_op_pattern)] -fn add_assign(&mut self, rhs: Self) { - *self = *self + rhs; -} + #[allow(clippy::assign_op_pattern)] + fn add_assign(&mut self, rhs: Self) { + *self = *self + rhs; + } } impl std::ops::Neg for RP25519 { -type Output = Self; + type Output = Self; -fn neg(self) -> Self::Output { - Self(self.0.decompress().unwrap().neg().compress()) -} + fn neg(self) -> Self::Output { + Self(self.0.decompress().unwrap().neg().compress()) + } } impl std::ops::Sub for RP25519 { -type Output = Self; + type Output = Self; -fn sub(self, rhs: Self) -> Self::Output { - Self((self.0.decompress().unwrap()-rhs.0.decompress().unwrap()).compress()) -} + fn sub(self, rhs: Self) -> Self::Output { + Self((self.0.decompress().unwrap() - rhs.0.decompress().unwrap()).compress()) + } } impl std::ops::SubAssign for RP25519 { -#[allow(clippy::assign_op_pattern)] -fn sub_assign(&mut self, rhs: Self) { - *self = *self - rhs; -} + #[allow(clippy::assign_op_pattern)] + fn sub_assign(&mut self, rhs: Self) { + *self = *self - rhs; + } } - ///Scalar Multiplication ///<'a, 'b> `std::ops::Mul<&'b"` Fp25519 for &'a impl RP25519 { - pub const ONE: Self = Self(constants::RISTRETTO_BASEPOINT_COMPRESSED); /// # Errors /// Propagates errors from decompressing invalid curve point -pub fn s_mul(self, rhs: Fp25519) -> Result { - self.0.decompress().map_or( - Err(Error::DecompressingInvalidCurvePoint), - |x| Ok((x * Scalar::from(rhs)).compress().into()) - ) -} + pub fn s_mul(self, rhs: Fp25519) -> Result { + self.0 + .decompress() + .map_or(Err(Error::DecompressingInvalidCurvePoint), |x| { + Ok((x * Scalar::from(rhs)).compress().into()) + }) + } } - ///do not use impl std::ops::Mul for RP25519 { type Output = Self; @@ -117,8 +115,7 @@ impl std::ops::Mul for RP25519 { ///do not use impl std::ops::MulAssign for RP25519 { - - fn mul_assign(& mut self, _rhs: RP25519) { + fn mul_assign(&mut self, _rhs: RP25519) { panic!("Two curve points cannot be multiplied! Do not use *, *= for RP25519 or secret shares of RP25519"); } } @@ -159,7 +156,7 @@ macro_rules! cp_hash_impl { } } - impl From<$u_type> for RP25519 { + impl From<$u_type> for RP25519 { fn from(s: $u_type) -> Self { let hk = Hkdf::::new(None, &s.to_le_bytes()); let mut okm = [0u8; 32]; @@ -168,23 +165,17 @@ macro_rules! cp_hash_impl { RP25519::deserialize(&okm.into()) } } - } + }; } -cp_hash_impl!( - u64, - 8 -); +cp_hash_impl!(u64, 8); -cp_hash_impl!( - u32, - 4 -); +cp_hash_impl!(u32, 4); /// Daniel had to implement this since Reveal wants it, prefer not to, I dont understand why it is /// actually needed there, maybe to upgrade it to malicious? but it still shouldn't be needed impl Field for RP25519 { - const ONE: RP25519= RP25519::ONE; + const ONE: RP25519 = Self(constants::RISTRETTO_BASEPOINT_COMPRESSED); ///both following methods are based on hashing and do not allow to actually convert elements in Fp25519 /// from or into u128. However it is sufficient to generate random elements in Fp25519 @@ -204,7 +195,6 @@ impl Field for RP25519 { hk.expand(&[], &mut okm).unwrap(); RP25519::deserialize(&okm.into()) } - } impl TryFrom for RP25519 { @@ -213,50 +203,46 @@ impl TryFrom for RP25519 { fn try_from(v: u128) -> Result { let mut bits = [0u8; 32]; bits[..].copy_from_slice(&v.to_le_bytes()); - let f: RP25519=RP25519::ONE; + let f: RP25519 = RP25519::ONE; f.serialize((&mut bits).into()); Ok(f) } } - - - #[cfg(all(test, unit_test))] mod test { - use generic_array::GenericArray; - use crate::ff::curve_points::RP25519; - use crate::ff::Serializable; - use typenum::U32; use curve25519_dalek::scalar::Scalar; + use generic_array::GenericArray; use rand::{thread_rng, Rng}; - use crate::ff::ec_prime_field::Fp25519; - use crate::secret_sharing::SharedValue; + use typenum::U32; + + use crate::{ + ff::{curve_points::RP25519, ec_prime_field::Fp25519, Serializable, field::Field}, + }; #[test] fn serde_25519() { - let input:[u8;32] = [ - 0x01, 0xff,0x00, 0xff,0x00, 0xff,0x00, 0xff, - 0x00, 0xff,0x00, 0xff,0x00, 0xff,0x00, 0xff, - 0x00, 0xff,0x00, 0xff,0x00, 0xff,0x00, 0xff, - 0x00, 0xff,0x00, 0xff,0x00, 0x00,0x00, 0x00 + let input: [u8; 32] = [ + 0x01, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, + 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, + 0x00, 0x00, 0x00, 0x00, ]; - let mut output: GenericArray = [0u8;32].into(); + let mut output: GenericArray = [0u8; 32].into(); let a = RP25519::deserialize(&input.into()); - assert_eq!(a.0.as_bytes()[..32],input); + assert_eq!(a.0.as_bytes()[..32], input); a.serialize(&mut output); - assert_eq!(a.0.as_bytes()[..32],output.as_slice()[..32]); - assert_eq!(input,output.as_slice()[..32]); + assert_eq!(a.0.as_bytes()[..32], output.as_slice()[..32]); + assert_eq!(input, output.as_slice()[..32]); } #[test] fn scalar_to_point() { let a = Scalar::ONE; - let b : RP25519 = a.into(); - let d : Fp25519 = a.into(); - let c : RP25519 = RP25519::from(d); - assert_eq!(b,RP25519::ZERO); - assert_eq!(c,RP25519::ZERO); + let b: RP25519 = a.into(); + let d: Fp25519 = a.into(); + let c: RP25519 = RP25519::from(d); + assert_eq!(b, RP25519::ONE); + assert_eq!(c, RP25519::ONE); } #[test] @@ -264,24 +250,23 @@ mod test { let mut rng = thread_rng(); let fp_a = rng.gen::(); let fp_b = rng.gen::(); - let fp_c = fp_a+fp_b; - let fp_d = RP25519::from(fp_a)+RP25519::from(fp_b); + let fp_c = fp_a + fp_b; + let fp_d = RP25519::from(fp_a) + RP25519::from(fp_b); assert_eq!(fp_d, RP25519::from(fp_c)); - assert_ne!(fp_d, RP25519::ZERO); + assert_ne!(fp_d, RP25519::ONE); let fp_e = rng.gen::(); - let fp_f=rng.gen::(); - let fp_g =fp_e*fp_f; + let fp_f = rng.gen::(); + let fp_g = fp_e * fp_f; let fp_h = RP25519::from(fp_e).s_mul(fp_f).unwrap(); - assert_eq!(fp_h,RP25519::from(fp_g)); - assert_ne!(fp_h, RP25519::ZERO); + assert_eq!(fp_h, RP25519::from(fp_g)); + assert_ne!(fp_h, RP25519::ONE); } #[test] fn curve_point_to_hash() { let mut rng = thread_rng(); let fp_a = rng.gen::(); - assert_ne!(0u64,u64::from(fp_a)); - assert_ne!(0u32,u32::from(fp_a)); + assert_ne!(0u64, u64::from(fp_a)); + assert_ne!(0u32, u32::from(fp_a)); } - -} \ No newline at end of file +} diff --git a/src/ff/ec_prime_field.rs b/src/ff/ec_prime_field.rs index 624f91c64..6613116f6 100644 --- a/src/ff/ec_prime_field.rs +++ b/src/ff/ec_prime_field.rs @@ -1,12 +1,12 @@ -use generic_array::GenericArray; use curve25519_dalek::scalar::Scalar; +use generic_array::GenericArray; +use hkdf::Hkdf; +use sha2::Sha256; //use rand_core::RngCore; use typenum::U32; -use sha2::Sha256; -use hkdf::Hkdf; use crate::{ - ff::{Serializable, Field}, + ff::{Field, Serializable}, secret_sharing::{Block, SharedValue}, }; @@ -17,7 +17,6 @@ impl Block for Scalar { #[derive(Clone, Copy, PartialEq, Debug)] pub struct Fp25519(::Storage); - impl Fp25519 { pub const ONE: Self = Self(Scalar::ONE); @@ -26,10 +25,8 @@ impl Fp25519 { pub fn invert(&self) -> Fp25519 { Fp25519(self.0.invert()) } - } - impl SharedValue for Fp25519 { type Storage = Scalar; const BITS: u32 = 256; @@ -46,7 +43,7 @@ impl Serializable for Fp25519 { type Size = <::Storage as Block>::Size; fn serialize(&self, buf: &mut GenericArray) { - let raw = &self.0.as_bytes()[..buf.len()] ; + let raw = &self.0.as_bytes()[..buf.len()]; buf.copy_from_slice(raw); } @@ -58,7 +55,6 @@ impl Serializable for Fp25519 { } } - impl rand::distributions::Distribution for rand::distributions::Standard { fn sample(&self, rng: &mut R) -> Fp25519 { let mut scalar_bytes = [0u8; 32]; @@ -69,61 +65,59 @@ impl rand::distributions::Distribution for rand::distributions::Standar } } - impl std::ops::Add for Fp25519 { -type Output = Self; + type Output = Self; -fn add(self, rhs: Self) -> Self::Output { - Self(self.0+rhs.0) -} + fn add(self, rhs: Self) -> Self::Output { + Self(self.0 + rhs.0) + } } impl std::ops::AddAssign for Fp25519 { -#[allow(clippy::assign_op_pattern)] -fn add_assign(&mut self, rhs: Self) { - *self = *self + rhs; -} + #[allow(clippy::assign_op_pattern)] + fn add_assign(&mut self, rhs: Self) { + *self = *self + rhs; + } } impl std::ops::Neg for Fp25519 { -type Output = Self; + type Output = Self; -fn neg(self) -> Self::Output { - Self(self.0.neg()) -} + fn neg(self) -> Self::Output { + Self(self.0.neg()) + } } impl std::ops::Sub for Fp25519 { -type Output = Self; + type Output = Self; -fn sub(self, rhs: Self) -> Self::Output { - Self(self.0- rhs.0) -} + fn sub(self, rhs: Self) -> Self::Output { + Self(self.0 - rhs.0) + } } impl std::ops::SubAssign for Fp25519 { -#[allow(clippy::assign_op_pattern)] -fn sub_assign(&mut self, rhs: Self) { - *self = *self - rhs; -} + #[allow(clippy::assign_op_pattern)] + fn sub_assign(&mut self, rhs: Self) { + *self = *self - rhs; + } } impl std::ops::Mul for Fp25519 { -type Output = Self; + type Output = Self; -fn mul(self, rhs: Self) -> Self::Output { - Self(self.0 * rhs.0) -} + fn mul(self, rhs: Self) -> Self::Output { + Self(self.0 * rhs.0) + } } impl std::ops::MulAssign for Fp25519 { -#[allow(clippy::assign_op_pattern)] -fn mul_assign(&mut self, rhs: Self) { - *self = *self * rhs; -} + #[allow(clippy::assign_op_pattern)] + fn mul_assign(&mut self, rhs: Self) { + *self = *self * rhs; + } } - impl From for Fp25519 { fn from(s: Scalar) -> Self { Fp25519(s) @@ -142,7 +136,7 @@ macro_rules! sc_hash_impl { } } - impl From<$u_type> for Fp25519 { + impl From<$u_type> for Fp25519 { fn from(s: $u_type) -> Self { let hk = Hkdf::::new(None, &s.to_le_bytes()); let mut okm = [0u8; 32]; @@ -151,24 +145,16 @@ macro_rules! sc_hash_impl { Fp25519::deserialize(&okm.into()) } } - } + }; } +sc_hash_impl!(u64, 8); -sc_hash_impl!( - u64, - 8 -); - -sc_hash_impl!( - u32, - 4 -); - +sc_hash_impl!(u32, 4); /// Daniel had to implement this since PRSS wants it, prefer not to impl Field for Fp25519 { - const ONE: Fp25519= Fp25519::ONE; + const ONE: Fp25519 = Fp25519::ONE; ///both following methods are based on hashing and do not allow to actually convert elements in Fp25519 /// from or into u128. However it is sufficient to generate random elements in Fp25519 @@ -188,7 +174,6 @@ impl Field for Fp25519 { hk.expand(&[], &mut okm).unwrap(); Fp25519::deserialize(&okm.into()) } - } impl TryFrom for Fp25519 { @@ -197,7 +182,7 @@ impl TryFrom for Fp25519 { fn try_from(v: u128) -> Result { let mut bits = [0u8; 32]; bits[..].copy_from_slice(&v.to_le_bytes()); - let f: Fp25519=Fp25519::ONE; + let f: Fp25519 = Fp25519::ONE; f.serialize((&mut bits).into()); Ok(f) } @@ -205,76 +190,73 @@ impl TryFrom for Fp25519 { #[cfg(all(test, unit_test))] mod test { - use generic_array::GenericArray; - use crate::ff::ec_prime_field::Fp25519; - use crate::ff::Serializable; - use typenum::U32; use curve25519_dalek::scalar::Scalar; + use generic_array::GenericArray; use rand::{thread_rng, Rng}; - use crate::secret_sharing::SharedValue; + use typenum::U32; + + use crate::{ + ff::{ec_prime_field::Fp25519, Serializable}, + secret_sharing::SharedValue, + }; #[test] fn serde_25519() { - let input:[u8;32] = [ - 0x01, 0xff,0x00, 0xff,0x00, 0xff,0x00, 0xff, - 0x00, 0xff,0x00, 0xff,0x00, 0xff,0x00, 0xff, - 0x00, 0xff,0x00, 0xff,0x00, 0xff,0x00, 0xff, - 0x00, 0xff,0x00, 0xff,0x00, 0x00,0x00, 0x00 + let input: [u8; 32] = [ + 0x01, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, + 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, + 0x00, 0x00, 0x00, 0x00, ]; - let mut output: GenericArray = [0u8;32].into(); + let mut output: GenericArray = [0u8; 32].into(); let a = Fp25519::deserialize(&input.into()); - assert_eq!(a.0.as_bytes()[..32],input); + assert_eq!(a.0.as_bytes()[..32], input); a.serialize(&mut output); - assert_eq!(a.0.as_bytes()[..32],output.as_slice()[..32]); - assert_eq!(input,output.as_slice()[..32]); + assert_eq!(a.0.as_bytes()[..32], output.as_slice()[..32]); + assert_eq!(input, output.as_slice()[..32]); } // These are just simple arithmetic tests since arithmetics are checked by curve25519_dalek #[test] fn simple_arithmetics_25519() { let a = Fp25519(Scalar::from_bytes_mod_order([ - 0x02, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00, - 0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00, - 0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00, - 0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00 + 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, ])); let b = Fp25519(Scalar::from_bytes_mod_order([ - 0x03, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00, - 0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00, - 0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00, - 0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00 + 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, ])); let d = Fp25519(Scalar::from_bytes_mod_order([ - 0x05, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00, - 0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00, - 0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00, - 0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00 + 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, ])); let e = Fp25519(Scalar::from_bytes_mod_order([ - 0x06, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00, - 0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00, - 0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00, - 0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00 + 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, ])); - let cc = b-a; - let dc = a+b; - let ec = a*b; - assert_eq!(cc,Fp25519::ONE); - assert_eq!(dc,d); - assert_eq!(ec,e); + let cc = b - a; + let dc = a + b; + let ec = a * b; + assert_eq!(cc, Fp25519::ONE); + assert_eq!(dc, d); + assert_eq!(ec, e); } #[test] - fn simple_random_25519(){ + fn simple_random_25519() { let mut rng = thread_rng(); - assert_ne!(Fp25519::ZERO,rng.gen::()); + assert_ne!(Fp25519::ZERO, rng.gen::()); } #[test] - fn invert_25519(){ + fn invert_25519() { let mut rng = thread_rng(); - let a=rng.gen::(); - let ia=a.invert(); - assert_eq!(a*ia, Fp25519(Scalar::ONE)); + let a = rng.gen::(); + let ia = a.invert(); + assert_eq!(a * ia, Fp25519(Scalar::ONE)); } -} \ No newline at end of file +} diff --git a/src/ff/mod.rs b/src/ff/mod.rs index e617359d1..1ced6caf0 100644 --- a/src/ff/mod.rs +++ b/src/ff/mod.rs @@ -2,11 +2,11 @@ // // This is where we store arithmetic shared secret data models. +pub mod curve_points; +pub mod ec_prime_field; mod field; mod galois_field; mod prime_field; -pub mod ec_prime_field; -pub mod curve_points; use std::ops::{Add, AddAssign, Sub, SubAssign}; diff --git a/src/protocol/prf_eval/mod.rs b/src/protocol/prf_eval/mod.rs index 895ad524b..ae43e55a1 100644 --- a/src/protocol/prf_eval/mod.rs +++ b/src/protocol/prf_eval/mod.rs @@ -1,11 +1,17 @@ +use ipa_macros::Step; + use crate::{ error::Error, - ff::{ec_prime_field::Fp25519, curve_points::RP25519}, - protocol::{context::Context, RecordId, prss::SharedRandomness, basics::Reveal, basics::SecureMul}, - secret_sharing::{replicated::{semi_honest::AdditiveShare,ReplicatedSecretSharing}}, + ff::{curve_points::RP25519, ec_prime_field::Fp25519}, + protocol::{ + basics::{Reveal, SecureMul}, + context::Context, + prss::SharedRandomness, + RecordId, + }, + secret_sharing::replicated::{semi_honest::AdditiveShare, ReplicatedSecretSharing}, seq_join::seq_try_join_all, }; -use ipa_macros::Step; #[derive(Step)] pub(crate) enum Step { @@ -23,30 +29,33 @@ pub async fn compute_match_key_pseudonym( prf_key: AdditiveShare, input_match_keys: Vec>, ) -> Result, Error> - where - C: Context, +where + C: Context, { - let ctx =sh_ctx.set_total_records(input_match_keys.len()); - let futures=input_match_keys.iter().enumerate().map(|(i,x)|eval_dy_prf(ctx.clone(),i.into(),&prf_key,x)); + let ctx = sh_ctx.set_total_records(input_match_keys.len()); + let futures = input_match_keys + .iter() + .enumerate() + .map(|(i, x)| eval_dy_prf(ctx.clone(), i.into(), &prf_key, x)); seq_try_join_all(sh_ctx.active_work(), futures).await } - impl From> for AdditiveShare { fn from(s: AdditiveShare) -> Self { - AdditiveShare::new(RP25519::from(s.left()),RP25519::from(s.right())) + AdditiveShare::new(RP25519::from(s.left()), RP25519::from(s.right())) } } /// generates PRF key k as secret sharing over Fp25519 -pub fn gen_prf_key (ctx: &C) -> AdditiveShare - where - C: Context, +pub fn gen_prf_key(ctx: &C) -> AdditiveShare +where + C: Context, { - ctx.narrow(&Step::PRFKeyGen).prss().generate_replicated(u128::MAX-100u128) + ctx.narrow(&Step::PRFKeyGen) + .prss() + .generate_replicated(u128::MAX - 100u128) } - /// evaluates the Dodis-Yampolski PRF g^(1/(k+x)) /// the input x and k are secret shared over finite field Fp25519, i.e. the scalar field of curve 25519 /// PRF key k is generated using keygen @@ -61,26 +70,29 @@ pub async fn eval_dy_prf( k: &AdditiveShare, x: &AdditiveShare, ) -> Result - where - C: Context, +where + C: Context, { - let sh_r: AdditiveShare = ctx.narrow(&Step::GenRandomMask).prss().generate_replicated(record_id); + let sh_r: AdditiveShare = ctx + .narrow(&Step::GenRandomMask) + .prss() + .generate_replicated(record_id); //compute (g^left, g^right) let sh_gr = AdditiveShare::::from(sh_r.clone()); //compute x+k - let mut y =x+k; + let mut y = x + k; //compute y <- r*y - y = y.multiply(&sh_r, ctx.narrow(&Step::MultMaskWithPRFInput), record_id).await?; + y = y + .multiply(&sh_r, ctx.narrow(&Step::MultMaskWithPRFInput), record_id) + .await?; //reconstruct (z,R) let gr: RP25519 = sh_gr.reveal(ctx.narrow(&Step::RevealR), record_id).await?; let z = y.reveal(ctx.narrow(&Step::Revealz), record_id).await?; - - //compute R^(1/z) to u64 Ok(u64::from(gr.s_mul(z.invert())?)) } @@ -88,12 +100,13 @@ pub async fn eval_dy_prf( #[cfg(all(test, unit_test))] mod test { use rand::Rng; + use crate::{ + ff::{curve_points::RP25519, ec_prime_field::Fp25519}, + protocol::prf_eval::compute_match_key_pseudonym, + secret_sharing::{replicated::semi_honest::AdditiveShare, IntoShares}, test_executor::run, - test_fixture::{TestWorld, Reconstruct, Runner}, - ff::{ec_prime_field::Fp25519, curve_points::RP25519}, - secret_sharing::{IntoShares,replicated::semi_honest::AdditiveShare}, - protocol::prf_eval::{compute_match_key_pseudonym}, + test_fixture::{Reconstruct, Runner, TestWorld}, }; #[derive(Copy, Clone)] @@ -106,29 +119,30 @@ mod test { match_key_pseudonym: u64, } - fn test_input( mk: u64) -> ShuffledTestInput { + fn test_input(mk: u64) -> ShuffledTestInput { ShuffledTestInput { match_key: Fp25519::from(mk), } } - impl IntoShares> for ShuffledTestInput - { + impl IntoShares> for ShuffledTestInput { fn share_with(self, rng: &mut R) -> [AdditiveShare; 3] { self.match_key.share_with(rng) } } - impl Reconstruct for [&u64; 3] { fn reconstruct(&self) -> TestOutput { - TestOutput{ - match_key_pseudonym: if *self[0]==*self[1] && *self[0]==*self[2] {*self[0]} else {0u64}, + TestOutput { + match_key_pseudonym: if *self[0] == *self[1] && *self[0] == *self[2] { + *self[0] + } else { + 0u64 + }, } } } - #[test] fn semi_honest() { run(|| async move { @@ -146,29 +160,32 @@ mod test { test_input(3), test_input(56), test_input(23_443_524_523), - ]; + ]; //PRF Key Gen let u = 3_216_412_445u64; - let k:Fp25519 = Fp25519::from(u); + let k: Fp25519 = Fp25519::from(u); - let expected: Vec=records.iter().map(|&x| TestOutput{match_key_pseudonym: (RP25519::from((x.match_key+k).invert())).into()} ).collect(); + let expected: Vec = records + .iter() + .map(|&x| TestOutput { + match_key_pseudonym: (RP25519::from((x.match_key + k).invert())).into(), + }) + .collect(); let result: Vec<_> = world - .semi_honest((records.into_iter(),k), |ctx, (input_match_keys,prf_key)| async move { - compute_match_key_pseudonym::<_>( - ctx, - prf_key, - input_match_keys, - ) - .await - .unwrap() - }) + .semi_honest( + (records.into_iter(), k), + |ctx, (input_match_keys, prf_key)| async move { + compute_match_key_pseudonym::<_>(ctx, prf_key, input_match_keys) + .await + .unwrap() + }, + ) .await .reconstruct(); assert_eq!(result, expected); assert_eq!(result[0], result[1]); }); } - -} \ No newline at end of file +} From 4c175bd80accc0401f86c8d8dd5c2ae4300b7ead Mon Sep 17 00:00:00 2001 From: Daniel Masny Date: Mon, 16 Oct 2023 12:14:20 -0700 Subject: [PATCH 48/76] Alex suggestions, serialize, deserialize --- src/ff/curve_points.rs | 3 +-- src/ff/ec_prime_field.rs | 8 ++------ 2 files changed, 3 insertions(+), 8 deletions(-) diff --git a/src/ff/curve_points.rs b/src/ff/curve_points.rs index 2b1f60f94..38908dadf 100644 --- a/src/ff/curve_points.rs +++ b/src/ff/curve_points.rs @@ -33,8 +33,7 @@ impl Serializable for RP25519 { type Size = <::Storage as Block>::Size; fn serialize(&self, buf: &mut GenericArray) { - let raw = &self.0.as_bytes()[..buf.len()]; - buf.copy_from_slice(raw); + *buf.as_mut() = self.0.to_bytes(); } fn deserialize(buf: &GenericArray) -> Self { diff --git a/src/ff/ec_prime_field.rs b/src/ff/ec_prime_field.rs index 6613116f6..d7348ca1b 100644 --- a/src/ff/ec_prime_field.rs +++ b/src/ff/ec_prime_field.rs @@ -43,15 +43,11 @@ impl Serializable for Fp25519 { type Size = <::Storage as Block>::Size; fn serialize(&self, buf: &mut GenericArray) { - let raw = &self.0.as_bytes()[..buf.len()]; - buf.copy_from_slice(raw); + *buf.as_mut() = self.0.to_bytes() } fn deserialize(buf: &GenericArray) -> Self { - let mut buf_to = [0u8; 32]; - buf_to[..buf.len()].copy_from_slice(buf); - - Fp25519(Scalar::from_bytes_mod_order(buf_to)) + Fp25519(Scalar::from_bytes_mod_order((*buf).into())) } } From 537e7af1f6515e78b6a9496d8478bd27b29a2d50 Mon Sep 17 00:00:00 2001 From: Daniel Masny Date: Mon, 16 Oct 2023 12:29:06 -0700 Subject: [PATCH 49/76] Alex suggestions, simplify u32, u64 macros --- src/ff/curve_points.rs | 8 ++++---- src/ff/ec_prime_field.rs | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/ff/curve_points.rs b/src/ff/curve_points.rs index 38908dadf..0890903a5 100644 --- a/src/ff/curve_points.rs +++ b/src/ff/curve_points.rs @@ -144,11 +144,11 @@ impl From for CompressedRistretto { } macro_rules! cp_hash_impl { - ( $u_type:ty, $byte_size:literal) => { + ( $u_type:ty) => { impl From for $u_type { fn from(s: RP25519) -> Self { let hk = Hkdf::::new(None, s.0.as_bytes()); - let mut okm = [0u8; $byte_size]; + let mut okm = <$u_type>::MIN.to_le_bytes(); //error invalid length from expand only happens when okm is very large hk.expand(&[], &mut okm).unwrap(); <$u_type>::from_le_bytes(okm) @@ -167,9 +167,9 @@ macro_rules! cp_hash_impl { }; } -cp_hash_impl!(u64, 8); +cp_hash_impl!(u64); -cp_hash_impl!(u32, 4); +cp_hash_impl!(u32); /// Daniel had to implement this since Reveal wants it, prefer not to, I dont understand why it is /// actually needed there, maybe to upgrade it to malicious? but it still shouldn't be needed diff --git a/src/ff/ec_prime_field.rs b/src/ff/ec_prime_field.rs index d7348ca1b..9234cb346 100644 --- a/src/ff/ec_prime_field.rs +++ b/src/ff/ec_prime_field.rs @@ -121,11 +121,11 @@ impl From for Fp25519 { } macro_rules! sc_hash_impl { - ( $u_type:ty, $byte_size:literal) => { + ( $u_type:ty) => { impl From for $u_type { fn from(s: Fp25519) -> Self { let hk = Hkdf::::new(None, s.0.as_bytes()); - let mut okm = [0u8; $byte_size]; + let mut okm = <$u_type>::MIN.to_le_bytes(); //error invalid length from expand only happens when okm is very large hk.expand(&[], &mut okm).unwrap(); <$u_type>::from_le_bytes(okm) @@ -144,9 +144,9 @@ macro_rules! sc_hash_impl { }; } -sc_hash_impl!(u64, 8); +sc_hash_impl!(u64); -sc_hash_impl!(u32, 4); +sc_hash_impl!(u32); /// Daniel had to implement this since PRSS wants it, prefer not to impl Field for Fp25519 { From 5325f6dbcc2db7f17305786921a87654bc5e117d Mon Sep 17 00:00:00 2001 From: danielmasny <46358615+danielmasny@users.noreply.github.com> Date: Mon, 16 Oct 2023 12:19:22 -0700 Subject: [PATCH 50/76] Update src/ff/curve_points.rs Co-authored-by: Alex Koshelev --- src/ff/curve_points.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ff/curve_points.rs b/src/ff/curve_points.rs index 0890903a5..fb605205e 100644 --- a/src/ff/curve_points.rs +++ b/src/ff/curve_points.rs @@ -119,7 +119,7 @@ impl std::ops::MulAssign for RP25519 { } } -impl From for RP25519 { +impl From<&Scalar> for RP25519 { fn from(s: Scalar) -> Self { RP25519(RistrettoPoint::mul_base(&s).compress()) } From dd0aac091698520ea37fa28798592dc2c6f639cf Mon Sep 17 00:00:00 2001 From: danielmasny <46358615+danielmasny@users.noreply.github.com> Date: Mon, 16 Oct 2023 13:06:29 -0700 Subject: [PATCH 51/76] Update src/ff/curve_points.rs Co-authored-by: Alex Koshelev --- src/ff/curve_points.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ff/curve_points.rs b/src/ff/curve_points.rs index fb605205e..76657874a 100644 --- a/src/ff/curve_points.rs +++ b/src/ff/curve_points.rs @@ -125,7 +125,7 @@ impl From<&Scalar> for RP25519 { } } -impl From for RP25519 { +impl From<&Fp25519> for RP25519 { fn from(s: Fp25519) -> Self { RP25519(RistrettoPoint::mul_base(&s.into()).compress()) } From 5edee6fdc58f60546c55fe709e9fbb5b5de8d0f2 Mon Sep 17 00:00:00 2001 From: Daniel Masny Date: Mon, 16 Oct 2023 15:17:02 -0700 Subject: [PATCH 52/76] simplify serde test --- src/ff/curve_points.rs | 102 ++++++++++----------------------------- src/ff/ec_prime_field.rs | 23 ++++----- 2 files changed, 34 insertions(+), 91 deletions(-) diff --git a/src/ff/curve_points.rs b/src/ff/curve_points.rs index 76657874a..bf09072ef 100644 --- a/src/ff/curve_points.rs +++ b/src/ff/curve_points.rs @@ -10,7 +10,7 @@ use typenum::U32; use crate::{ error::Error, - ff::{ec_prime_field::Fp25519, Field, Serializable}, + ff::{ec_prime_field::Fp25519, Serializable}, secret_sharing::{Block, SharedValue}, }; @@ -37,16 +37,7 @@ impl Serializable for RP25519 { } fn deserialize(buf: &GenericArray) -> Self { - RP25519(CompressedRistretto::from_slice(buf).unwrap()) - } -} - -impl rand::distributions::Distribution for rand::distributions::Standard { - fn sample(&self, rng: &mut R) -> RP25519 { - //Fp25519(Scalar::random(rng: &mut R)) - let mut scalar_bytes = [0u8; 64]; - rng.fill_bytes(&mut scalar_bytes); - RP25519(RistrettoPoint::from_uniform_bytes(&scalar_bytes).compress()) + RP25519(CompressedRistretto((*buf).into())) } } @@ -91,7 +82,6 @@ impl std::ops::SubAssign for RP25519 { ///Scalar Multiplication ///<'a, 'b> `std::ops::Mul<&'b"` Fp25519 for &'a impl RP25519 { - /// # Errors /// Propagates errors from decompressing invalid curve point pub fn s_mul(self, rhs: Fp25519) -> Result { @@ -119,13 +109,13 @@ impl std::ops::MulAssign for RP25519 { } } -impl From<&Scalar> for RP25519 { +impl From for RP25519 { fn from(s: Scalar) -> Self { RP25519(RistrettoPoint::mul_base(&s).compress()) } } -impl From<&Fp25519> for RP25519 { +impl From for RP25519 { fn from(s: Fp25519) -> Self { RP25519(RistrettoPoint::mul_base(&s.into()).compress()) } @@ -154,84 +144,42 @@ macro_rules! cp_hash_impl { <$u_type>::from_le_bytes(okm) } } - - impl From<$u_type> for RP25519 { - fn from(s: $u_type) -> Self { - let hk = Hkdf::::new(None, &s.to_le_bytes()); - let mut okm = [0u8; 32]; - //error invalid length from expand only happens when okm is very large - hk.expand(&[], &mut okm).unwrap(); - RP25519::deserialize(&okm.into()) - } - } }; } +cp_hash_impl!(u128); + cp_hash_impl!(u64); +#[cfg(test)] cp_hash_impl!(u32); -/// Daniel had to implement this since Reveal wants it, prefer not to, I dont understand why it is -/// actually needed there, maybe to upgrade it to malicious? but it still shouldn't be needed -impl Field for RP25519 { - const ONE: RP25519 = Self(constants::RISTRETTO_BASEPOINT_COMPRESSED); - - ///both following methods are based on hashing and do not allow to actually convert elements in Fp25519 - /// from or into u128. However it is sufficient to generate random elements in Fp25519 - fn as_u128(&self) -> u128 { - let hk = Hkdf::::new(None, self.0.as_bytes()); - let mut okm = [0u8; 16]; - //error invalid length from expand only happens when okm is very large - hk.expand(&[], &mut okm).unwrap(); - u128::from_le_bytes(okm) - } - - ///PRSS uses `truncate_from function`, we need to expand the u128 using a PRG (Sha256) to a [u8;32] - fn truncate_from>(v: T) -> Self { - let hk = Hkdf::::new(None, &v.into().to_le_bytes()); - let mut okm = [0u8; 32]; - //error invalid length from expand only happens when okm is very large - hk.expand(&[], &mut okm).unwrap(); - RP25519::deserialize(&okm.into()) - } -} - -impl TryFrom for RP25519 { - type Error = crate::error::Error; - - fn try_from(v: u128) -> Result { - let mut bits = [0u8; 32]; - bits[..].copy_from_slice(&v.to_le_bytes()); - let f: RP25519 = RP25519::ONE; - f.serialize((&mut bits).into()); - Ok(f) +#[cfg(test)] +impl rand::distributions::Distribution for rand::distributions::Standard { + fn sample(&self, rng: &mut R) -> RP25519 { + let mut scalar_bytes = [0u8; 64]; + rng.fill_bytes(&mut scalar_bytes); + RP25519(RistrettoPoint::from_uniform_bytes(&scalar_bytes).compress()) } } #[cfg(all(test, unit_test))] mod test { - use curve25519_dalek::scalar::Scalar; + use curve25519_dalek::{constants, scalar::Scalar}; use generic_array::GenericArray; use rand::{thread_rng, Rng}; use typenum::U32; - use crate::{ - ff::{curve_points::RP25519, ec_prime_field::Fp25519, Serializable, field::Field}, - }; + use crate::ff::{curve_points::RP25519, ec_prime_field::Fp25519, Serializable}; #[test] fn serde_25519() { - let input: [u8; 32] = [ - 0x01, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, - 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, - 0x00, 0x00, 0x00, 0x00, - ]; - let mut output: GenericArray = [0u8; 32].into(); - let a = RP25519::deserialize(&input.into()); - assert_eq!(a.0.as_bytes()[..32], input); - a.serialize(&mut output); - assert_eq!(a.0.as_bytes()[..32], output.as_slice()[..32]); - assert_eq!(input, output.as_slice()[..32]); + let mut rng = thread_rng(); + let input = rng.gen::(); + let mut a: GenericArray = [0u8; 32].into(); + input.serialize(&mut a); + let output = RP25519::deserialize(&a); + assert_eq!(input, output); } #[test] @@ -240,8 +188,8 @@ mod test { let b: RP25519 = a.into(); let d: Fp25519 = a.into(); let c: RP25519 = RP25519::from(d); - assert_eq!(b, RP25519::ONE); - assert_eq!(c, RP25519::ONE); + assert_eq!(b, RP25519(constants::RISTRETTO_BASEPOINT_COMPRESSED)); + assert_eq!(c, RP25519(constants::RISTRETTO_BASEPOINT_COMPRESSED)); } #[test] @@ -252,13 +200,13 @@ mod test { let fp_c = fp_a + fp_b; let fp_d = RP25519::from(fp_a) + RP25519::from(fp_b); assert_eq!(fp_d, RP25519::from(fp_c)); - assert_ne!(fp_d, RP25519::ONE); + assert_ne!(fp_d, RP25519(constants::RISTRETTO_BASEPOINT_COMPRESSED)); let fp_e = rng.gen::(); let fp_f = rng.gen::(); let fp_g = fp_e * fp_f; let fp_h = RP25519::from(fp_e).s_mul(fp_f).unwrap(); assert_eq!(fp_h, RP25519::from(fp_g)); - assert_ne!(fp_h, RP25519::ONE); + assert_ne!(fp_h, RP25519(constants::RISTRETTO_BASEPOINT_COMPRESSED)); } #[test] diff --git a/src/ff/ec_prime_field.rs b/src/ff/ec_prime_field.rs index 9234cb346..e67ffa235 100644 --- a/src/ff/ec_prime_field.rs +++ b/src/ff/ec_prime_field.rs @@ -2,7 +2,6 @@ use curve25519_dalek::scalar::Scalar; use generic_array::GenericArray; use hkdf::Hkdf; use sha2::Sha256; -//use rand_core::RngCore; use typenum::U32; use crate::{ @@ -23,6 +22,7 @@ impl Fp25519 { //must not use with ZERO #[must_use] pub fn invert(&self) -> Fp25519 { + assert_ne!(*self, Fp25519::ZERO); Fp25519(self.0.invert()) } } @@ -56,8 +56,6 @@ impl rand::distributions::Distribution for rand::distributions::Standar let mut scalar_bytes = [0u8; 32]; rng.fill_bytes(&mut scalar_bytes); Fp25519(Scalar::from_bytes_mod_order(scalar_bytes)) - //not needed since above has sufficiently small bias - //Fp25519(Scalar::from_bytes_mod_order(&scalar_bytes)) } } @@ -144,8 +142,10 @@ macro_rules! sc_hash_impl { }; } +#[cfg(test)] sc_hash_impl!(u64); +#[cfg(test)] sc_hash_impl!(u32); /// Daniel had to implement this since PRSS wants it, prefer not to @@ -198,17 +198,12 @@ mod test { #[test] fn serde_25519() { - let input: [u8; 32] = [ - 0x01, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, - 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, - 0x00, 0x00, 0x00, 0x00, - ]; - let mut output: GenericArray = [0u8; 32].into(); - let a = Fp25519::deserialize(&input.into()); - assert_eq!(a.0.as_bytes()[..32], input); - a.serialize(&mut output); - assert_eq!(a.0.as_bytes()[..32], output.as_slice()[..32]); - assert_eq!(input, output.as_slice()[..32]); + let mut rng = thread_rng(); + let input = rng.gen::(); + let mut a: GenericArray = [0u8; 32].into(); + input.serialize(&mut a); + let output = Fp25519::deserialize(&a); + assert_eq!(input, output); } // These are just simple arithmetic tests since arithmetics are checked by curve25519_dalek From 3fdd719e7de2bc993e7b3c8bb32a1e0522040327 Mon Sep 17 00:00:00 2001 From: Daniel Masny Date: Mon, 16 Oct 2023 15:21:42 -0700 Subject: [PATCH 53/76] simplify serde test --- src/ff/ec_prime_field.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/ff/ec_prime_field.rs b/src/ff/ec_prime_field.rs index e67ffa235..d0ff48b72 100644 --- a/src/ff/ec_prime_field.rs +++ b/src/ff/ec_prime_field.rs @@ -19,7 +19,8 @@ pub struct Fp25519(::Storage); impl Fp25519 { pub const ONE: Self = Self(Scalar::ONE); - //must not use with ZERO + ///# Panics + /// Panics when self is zero #[must_use] pub fn invert(&self) -> Fp25519 { assert_ne!(*self, Fp25519::ZERO); @@ -43,7 +44,7 @@ impl Serializable for Fp25519 { type Size = <::Storage as Block>::Size; fn serialize(&self, buf: &mut GenericArray) { - *buf.as_mut() = self.0.to_bytes() + *buf.as_mut() = self.0.to_bytes(); } fn deserialize(buf: &GenericArray) -> Self { From 5e65826533f91dc203c94d8843a6adba0fedab3a Mon Sep 17 00:00:00 2001 From: Daniel Masny Date: Mon, 16 Oct 2023 17:57:38 -0700 Subject: [PATCH 54/76] error recursion limit --- src/ff/curve_points.rs | 8 ++-- src/secret_sharing/mod.rs | 47 ++++++++++++++++--- src/secret_sharing/replicated/mod.rs | 4 +- .../replicated/semi_honest/additive_share.rs | 43 ++++++++--------- src/secret_sharing/scheme.rs | 4 +- 5 files changed, 70 insertions(+), 36 deletions(-) diff --git a/src/ff/curve_points.rs b/src/ff/curve_points.rs index bf09072ef..cf182fd69 100644 --- a/src/ff/curve_points.rs +++ b/src/ff/curve_points.rs @@ -11,7 +11,7 @@ use typenum::U32; use crate::{ error::Error, ff::{ec_prime_field::Fp25519, Serializable}, - secret_sharing::{Block, SharedValue}, + secret_sharing::{Block, WeakSharedValue}, }; impl Block for CompressedRistretto { @@ -20,17 +20,17 @@ impl Block for CompressedRistretto { ///ristretto point for curve 25519 #[derive(Clone, Copy, PartialEq, Debug)] -pub struct RP25519(::Storage); +pub struct RP25519(::Storage); /// using compressed ristretto point, Zero is generator of the curve, i.e. g^0 -impl SharedValue for RP25519 { +impl WeakSharedValue for RP25519 { type Storage = CompressedRistretto; const BITS: u32 = 256; const ZERO: Self = Self(constants::RISTRETTO_BASEPOINT_COMPRESSED); } impl Serializable for RP25519 { - type Size = <::Storage as Block>::Size; + type Size = <::Storage as Block>::Size; fn serialize(&self, buf: &mut GenericArray) { *buf.as_mut() = self.0.to_bytes(); diff --git a/src/secret_sharing/mod.rs b/src/secret_sharing/mod.rs index f366c870c..110bf74f5 100644 --- a/src/secret_sharing/mod.rs +++ b/src/secret_sharing/mod.rs @@ -23,22 +23,33 @@ pub use scheme::{Bitwise, Linear, LinearRefOps, SecretSharing}; use crate::ff::{AddSub, AddSubAssign, Serializable}; +/// Operations supported for weak shared values. +pub trait Additive: +AddSub ++ AddSubAssign ++ Neg +{ +} + +impl Additive for T where + T: AddSub + + AddSubAssign + + Neg +{ +} + /// Operations supported for shared values. pub trait Arithmetic: - AddSub - + AddSubAssign + Additive + Mul + MulAssign - + Neg { } impl Arithmetic for T where - T: AddSub - + AddSubAssign + T: Additive + Mul + MulAssign - + Neg { } @@ -48,6 +59,16 @@ pub trait Block: Sized + Copy + Debug { type Size: ArrayLength; } +pub trait WeakSharedValue: +Clone + Copy + PartialEq + Debug + Send + Sync + Sized + Additive + Serializable + 'static +{ + type Storage: Block; + + const BITS: u32; + + const ZERO: Self; +} + pub trait SharedValue: Clone + Copy + PartialEq + Debug + Send + Sync + Sized + Arithmetic + Serializable + 'static { @@ -58,10 +79,22 @@ pub trait SharedValue: const ZERO: Self; } +impl WeakSharedValue for T where + T: SharedValue, +{ + type Storage = T::Storage; + + const BITS: u32 = T::BITS; + + const ZERO: Self = T::ZERO; +} + + + #[cfg(any(test, feature = "test-fixture", feature = "cli"))] impl IntoShares> for V where - V: SharedValue, + V: WeakSharedValue, Standard: Distribution, { fn share_with(self, rng: &mut R) -> [AdditiveShare; 3] { diff --git a/src/secret_sharing/replicated/mod.rs b/src/secret_sharing/replicated/mod.rs index dcf51494e..80c8167b0 100644 --- a/src/secret_sharing/replicated/mod.rs +++ b/src/secret_sharing/replicated/mod.rs @@ -1,9 +1,9 @@ pub mod malicious; pub mod semi_honest; -use super::{SecretSharing, SharedValue}; +use super::{SecretSharing, SharedValue, WeakSharedValue}; -pub trait ReplicatedSecretSharing: SecretSharing { +pub trait ReplicatedSecretSharing: SecretSharing { fn new(a: V, b: V) -> Self; fn left(&self) -> V; fn right(&self) -> V; diff --git a/src/secret_sharing/replicated/semi_honest/additive_share.rs b/src/secret_sharing/replicated/semi_honest/additive_share.rs index 10b8b2b39..fb7438c2f 100644 --- a/src/secret_sharing/replicated/semi_honest/additive_share.rs +++ b/src/secret_sharing/replicated/semi_honest/additive_share.rs @@ -11,31 +11,32 @@ use crate::{ secret_sharing::{ replicated::ReplicatedSecretSharing, Linear as LinearSecretSharing, SecretSharing, SharedValue, + WeakSharedValue, }, }; #[derive(Clone, PartialEq, Eq)] -pub struct AdditiveShare(V, V); +pub struct AdditiveShare(V, V); -impl SecretSharing for AdditiveShare { +impl SecretSharing for AdditiveShare { const ZERO: Self = AdditiveShare::ZERO; } impl LinearSecretSharing for AdditiveShare {} -impl Debug for AdditiveShare { +impl Debug for AdditiveShare { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { write!(f, "({:?}, {:?})", self.0, self.1) } } -impl Default for AdditiveShare { +impl Default for AdditiveShare { fn default() -> Self { AdditiveShare::new(V::ZERO, V::ZERO) } } -impl AdditiveShare { +impl AdditiveShare { /// Replicated secret share where both left and right values are `F::ZERO` pub const ZERO: Self = Self(V::ZERO, V::ZERO); @@ -44,7 +45,7 @@ impl AdditiveShare { } } -impl ReplicatedSecretSharing for AdditiveShare { +impl ReplicatedSecretSharing for AdditiveShare { fn new(a: V, b: V) -> Self { Self(a, b) } @@ -58,7 +59,7 @@ impl ReplicatedSecretSharing for AdditiveShare { } } -impl AdditiveShare +impl AdditiveShare where Self: Serializable, { @@ -73,7 +74,7 @@ where } } -impl<'a, 'b, V: SharedValue> Add<&'b AdditiveShare> for &'a AdditiveShare { +impl<'a, 'b, V: WeakSharedValue> Add<&'b AdditiveShare> for &'a AdditiveShare { type Output = AdditiveShare; fn add(self, rhs: &'b AdditiveShare) -> Self::Output { @@ -81,7 +82,7 @@ impl<'a, 'b, V: SharedValue> Add<&'b AdditiveShare> for &'a AdditiveShare } } -impl Add for AdditiveShare { +impl Add for AdditiveShare { type Output = Self; fn add(self, rhs: Self) -> Self::Output { @@ -89,7 +90,7 @@ impl Add for AdditiveShare { } } -impl Add> for &AdditiveShare { +impl Add> for &AdditiveShare { type Output = AdditiveShare; fn add(self, rhs: AdditiveShare) -> Self::Output { @@ -97,7 +98,7 @@ impl Add> for &AdditiveShare { } } -impl Add<&AdditiveShare> for AdditiveShare { +impl Add<&AdditiveShare> for AdditiveShare { type Output = Self; fn add(self, rhs: &Self) -> Self::Output { @@ -105,20 +106,20 @@ impl Add<&AdditiveShare> for AdditiveShare { } } -impl AddAssign<&Self> for AdditiveShare { +impl AddAssign<&Self> for AdditiveShare { fn add_assign(&mut self, rhs: &Self) { self.0 += rhs.0; self.1 += rhs.1; } } -impl AddAssign for AdditiveShare { +impl AddAssign for AdditiveShare { fn add_assign(&mut self, rhs: Self) { AddAssign::add_assign(self, &rhs); } } -impl Neg for &AdditiveShare { +impl Neg for &AdditiveShare { type Output = AdditiveShare; fn neg(self) -> Self::Output { @@ -126,7 +127,7 @@ impl Neg for &AdditiveShare { } } -impl Neg for AdditiveShare { +impl Neg for AdditiveShare { type Output = Self; fn neg(self) -> Self::Output { @@ -134,7 +135,7 @@ impl Neg for AdditiveShare { } } -impl Sub for &AdditiveShare { +impl Sub for &AdditiveShare { type Output = AdditiveShare; fn sub(self, rhs: Self) -> Self::Output { @@ -142,7 +143,7 @@ impl Sub for &AdditiveShare { } } -impl Sub for AdditiveShare { +impl Sub for AdditiveShare { type Output = Self; fn sub(self, rhs: Self) -> Self::Output { @@ -150,7 +151,7 @@ impl Sub for AdditiveShare { } } -impl Sub<&Self> for AdditiveShare { +impl Sub<&Self> for AdditiveShare { type Output = Self; fn sub(self, rhs: &Self) -> Self::Output { @@ -158,7 +159,7 @@ impl Sub<&Self> for AdditiveShare { } } -impl Sub> for &AdditiveShare { +impl Sub> for &AdditiveShare { type Output = AdditiveShare; fn sub(self, rhs: AdditiveShare) -> Self::Output { @@ -166,14 +167,14 @@ impl Sub> for &AdditiveShare { } } -impl SubAssign<&Self> for AdditiveShare { +impl SubAssign<&Self> for AdditiveShare { fn sub_assign(&mut self, rhs: &Self) { self.0 -= rhs.0; self.1 -= rhs.1; } } -impl SubAssign for AdditiveShare { +impl SubAssign for AdditiveShare { fn sub_assign(&mut self, rhs: Self) { SubAssign::sub_assign(self, &rhs); } diff --git a/src/secret_sharing/scheme.rs b/src/secret_sharing/scheme.rs index cd6556211..4d843f4b8 100644 --- a/src/secret_sharing/scheme.rs +++ b/src/secret_sharing/scheme.rs @@ -3,11 +3,11 @@ use std::{ ops::{Mul, Neg}, }; -use super::SharedValue; +use super::{SharedValue,WeakSharedValue}; use crate::ff::{AddSub, AddSubAssign, GaloisField}; /// Secret sharing scheme i.e. Replicated secret sharing -pub trait SecretSharing: Clone + Debug + Sized + Send + Sync { +pub trait SecretSharing: Clone + Debug + Sized + Send + Sync { const ZERO: Self; } From b89d15a50724357955b0c9695543391ed789c05b Mon Sep 17 00:00:00 2001 From: Alex Koshelev Date: Mon, 16 Oct 2023 22:38:49 -0700 Subject: [PATCH 55/76] Fix compiler recursion error --- src/ff/curve_points.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/ff/curve_points.rs b/src/ff/curve_points.rs index cf182fd69..3fc51f896 100644 --- a/src/ff/curve_points.rs +++ b/src/ff/curve_points.rs @@ -13,6 +13,7 @@ use crate::{ ff::{ec_prime_field::Fp25519, Serializable}, secret_sharing::{Block, WeakSharedValue}, }; +use crate::secret_sharing::Additive; impl Block for CompressedRistretto { type Size = U32; @@ -20,7 +21,7 @@ impl Block for CompressedRistretto { ///ristretto point for curve 25519 #[derive(Clone, Copy, PartialEq, Debug)] -pub struct RP25519(::Storage); +pub struct RP25519(CompressedRistretto); /// using compressed ristretto point, Zero is generator of the curve, i.e. g^0 impl WeakSharedValue for RP25519 { From b293fb585c595c235d29b2d1264ffd7d55973e6c Mon Sep 17 00:00:00 2001 From: Daniel Masny Date: Tue, 17 Oct 2023 15:04:59 -0700 Subject: [PATCH 56/76] define WeakSharedValue, adding ipa-prf feature --- Cargo.toml | 4 ++- src/ff/curve_points.rs | 48 +++++++++++++++++------------------ src/helpers/mod.rs | 4 +-- src/protocol/basics/reveal.rs | 4 +-- src/protocol/mod.rs | 1 + src/protocol/prf_eval/mod.rs | 2 +- 6 files changed, 32 insertions(+), 31 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index c3161a216..ce7d91446 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,7 +12,8 @@ default = [ "tracing/max_level_trace", "tracing/release_max_level_info", "descriptive-gate", - "aggregate-circuit" + "aggregate-circuit", + "ipa-prf" ] cli = ["comfy-table", "clap"] enable-serde = ["serde", "serde_json"] @@ -41,6 +42,7 @@ compact-gate = ["ipa-macros/compact-gate"] # Standalone aggregation protocol. We use IPA infra for communication # but it has nothing to do with IPA. aggregate-circuit = [] +ipa-prf = ["descriptive-gate"] [dependencies] aes = "0.8.3" diff --git a/src/ff/curve_points.rs b/src/ff/curve_points.rs index 3fc51f896..1094079d4 100644 --- a/src/ff/curve_points.rs +++ b/src/ff/curve_points.rs @@ -9,11 +9,10 @@ use sha2::Sha256; use typenum::U32; use crate::{ - error::Error, ff::{ec_prime_field::Fp25519, Serializable}, secret_sharing::{Block, WeakSharedValue}, }; -use crate::secret_sharing::Additive; + impl Block for CompressedRistretto { type Size = U32; @@ -23,7 +22,7 @@ impl Block for CompressedRistretto { #[derive(Clone, Copy, PartialEq, Debug)] pub struct RP25519(CompressedRistretto); -/// using compressed ristretto point, Zero is generator of the curve, i.e. g^0 +/// using compressed ristretto point impl WeakSharedValue for RP25519 { type Storage = CompressedRistretto; const BITS: u32 = 256; @@ -42,6 +41,10 @@ impl Serializable for RP25519 { } } + +///## Panics +/// Panics when decompressing invalid curve point. This can happen when deserialize curve point +/// from bit array that does not have a valid representation on the curve impl std::ops::Add for RP25519 { type Output = Self; @@ -57,6 +60,9 @@ impl std::ops::AddAssign for RP25519 { } } +///## Panics +/// Panics when decompressing invalid curve point. This can happen when deserialize curve point +/// from bit array that does not have a valid representation on the curve impl std::ops::Neg for RP25519 { type Output = Self; @@ -65,6 +71,9 @@ impl std::ops::Neg for RP25519 { } } +///## Panics +/// Panics when decompressing invalid curve point. This can happen when deserialize curve point +/// from bit array that does not have a valid representation on the curve impl std::ops::Sub for RP25519 { type Output = Self; @@ -82,34 +91,23 @@ impl std::ops::SubAssign for RP25519 { ///Scalar Multiplication ///<'a, 'b> `std::ops::Mul<&'b"` Fp25519 for &'a -impl RP25519 { - /// # Errors - /// Propagates errors from decompressing invalid curve point - pub fn s_mul(self, rhs: Fp25519) -> Result { - self.0 - .decompress() - .map_or(Err(Error::DecompressingInvalidCurvePoint), |x| { - Ok((x * Scalar::from(rhs)).compress().into()) - }) - } -} - -///do not use -impl std::ops::Mul for RP25519 { +///## Panics +/// Panics when decompressing invalid curve point. This can happen when deserialize curve point +/// from bit array that does not have a valid representation on the curve +impl std::ops::Mul< Fp25519> for RP25519 { type Output = Self; - fn mul(self, _rhs: RP25519) -> Self::Output { - panic!("Two curve points cannot be multiplied! Do not use *, *= for RP25519 or secret shares of RP25519"); + fn mul(self, rhs: Fp25519) -> RP25519 { + (self.0.decompress().unwrap() * Scalar::from(rhs)).compress().into() } } -///do not use -impl std::ops::MulAssign for RP25519 { - fn mul_assign(&mut self, _rhs: RP25519) { - panic!("Two curve points cannot be multiplied! Do not use *, *= for RP25519 or secret shares of RP25519"); - } +impl std::ops::MulAssign< Fp25519> for RP25519 { + #[allow(clippy::assign_op_pattern)] + fn mul_assign(&mut self, rhs: Fp25519) {*self = *self * rhs} } + impl From for RP25519 { fn from(s: Scalar) -> Self { RP25519(RistrettoPoint::mul_base(&s).compress()) @@ -205,7 +203,7 @@ mod test { let fp_e = rng.gen::(); let fp_f = rng.gen::(); let fp_g = fp_e * fp_f; - let fp_h = RP25519::from(fp_e).s_mul(fp_f).unwrap(); + let fp_h = RP25519::from(fp_e) * fp_f; assert_eq!(fp_h, RP25519::from(fp_g)); assert_ne!(fp_h, RP25519(constants::RISTRETTO_BASEPOINT_COMPRESSED)); } diff --git a/src/helpers/mod.rs b/src/helpers/mod.rs index 359bf305f..1c510485e 100644 --- a/src/helpers/mod.rs +++ b/src/helpers/mod.rs @@ -40,7 +40,7 @@ use crate::{ Role::{H1, H2, H3}, }, protocol::{step::Gate, RecordId}, - secret_sharing::SharedValue, + secret_sharing::WeakSharedValue, }; // TODO work with ArrayLength only @@ -409,7 +409,7 @@ impl Debug for ChannelId { pub trait Message: Debug + Send + Serializable + 'static + Sized {} /// Any shared value can be send as a message -impl Message for V {} +impl Message for V {} impl Serializable for PublicKey { type Size = typenum::U32; diff --git a/src/protocol/basics/reveal.rs b/src/protocol/basics/reveal.rs index 672c8a473..9fddb65b8 100644 --- a/src/protocol/basics/reveal.rs +++ b/src/protocol/basics/reveal.rs @@ -18,7 +18,7 @@ use crate::{ malicious::{AdditiveShare as MaliciousReplicated, ExtendableField}, semi_honest::AdditiveShare as Replicated, }, - SecretSharing, SharedValue, + SecretSharing, WeakSharedValue, }, }; @@ -47,7 +47,7 @@ pub trait Reveal: Sized { /// i.e. their own shares and received share. #[async_trait] #[embed_doc_image("reveal", "images/reveal.png")] -impl Reveal for Replicated { +impl Reveal for Replicated { type Output = V; async fn reveal<'fut>(&self, ctx: C, record_id: RecordId) -> Result diff --git a/src/protocol/mod.rs b/src/protocol/mod.rs index d9d1ea382..660fa8eaa 100644 --- a/src/protocol/mod.rs +++ b/src/protocol/mod.rs @@ -6,6 +6,7 @@ pub mod context; pub mod dp; pub mod ipa; pub mod modulus_conversion; +#[cfg(feature = "ipa-prf")] pub mod prf_eval; #[cfg(feature = "descriptive-gate")] pub mod prf_sharding; diff --git a/src/protocol/prf_eval/mod.rs b/src/protocol/prf_eval/mod.rs index ae43e55a1..3a0a99a21 100644 --- a/src/protocol/prf_eval/mod.rs +++ b/src/protocol/prf_eval/mod.rs @@ -94,7 +94,7 @@ where let z = y.reveal(ctx.narrow(&Step::Revealz), record_id).await?; //compute R^(1/z) to u64 - Ok(u64::from(gr.s_mul(z.invert())?)) + Ok(u64::from(gr * (z.invert()))) } #[cfg(all(test, unit_test))] From deeca7d8c72f6afad4d1d284387879dc1cae5eec Mon Sep 17 00:00:00 2001 From: Daniel Masny Date: Tue, 17 Oct 2023 15:15:12 -0700 Subject: [PATCH 57/76] fix zero --- src/ff/curve_points.rs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/ff/curve_points.rs b/src/ff/curve_points.rs index 1094079d4..1d60f934a 100644 --- a/src/ff/curve_points.rs +++ b/src/ff/curve_points.rs @@ -1,5 +1,4 @@ use curve25519_dalek::{ - constants, ristretto::{CompressedRistretto, RistrettoPoint}, Scalar, }; @@ -26,7 +25,7 @@ pub struct RP25519(CompressedRistretto); impl WeakSharedValue for RP25519 { type Storage = CompressedRistretto; const BITS: u32 = 256; - const ZERO: Self = Self(constants::RISTRETTO_BASEPOINT_COMPRESSED); + const ZERO: Self = Self(CompressedRistretto([0_u8;32])); } impl Serializable for RP25519 { @@ -169,7 +168,10 @@ mod test { use rand::{thread_rng, Rng}; use typenum::U32; - use crate::ff::{curve_points::RP25519, ec_prime_field::Fp25519, Serializable}; + use crate::{ + ff::{curve_points::RP25519, ec_prime_field::Fp25519, Serializable}, + secret_sharing::WeakSharedValue, + }; #[test] fn serde_25519() { @@ -206,6 +208,7 @@ mod test { let fp_h = RP25519::from(fp_e) * fp_f; assert_eq!(fp_h, RP25519::from(fp_g)); assert_ne!(fp_h, RP25519(constants::RISTRETTO_BASEPOINT_COMPRESSED)); + assert_eq!(RP25519::ZERO,fp_h*Scalar::ZERO.into()); } #[test] From 729c87f70bd809868b93da2cbc20eae881a5c0ee Mon Sep 17 00:00:00 2001 From: Daniel Masny Date: Tue, 17 Oct 2023 15:16:16 -0700 Subject: [PATCH 58/76] fmt --- src/ff/curve_points.rs | 21 +++++++++-------- src/secret_sharing/mod.rs | 23 ++++++------------- .../replicated/semi_honest/additive_share.rs | 3 +-- src/secret_sharing/scheme.rs | 2 +- 4 files changed, 20 insertions(+), 29 deletions(-) diff --git a/src/ff/curve_points.rs b/src/ff/curve_points.rs index 1d60f934a..99aac7f18 100644 --- a/src/ff/curve_points.rs +++ b/src/ff/curve_points.rs @@ -12,7 +12,6 @@ use crate::{ secret_sharing::{Block, WeakSharedValue}, }; - impl Block for CompressedRistretto { type Size = U32; } @@ -25,7 +24,7 @@ pub struct RP25519(CompressedRistretto); impl WeakSharedValue for RP25519 { type Storage = CompressedRistretto; const BITS: u32 = 256; - const ZERO: Self = Self(CompressedRistretto([0_u8;32])); + const ZERO: Self = Self(CompressedRistretto([0_u8; 32])); } impl Serializable for RP25519 { @@ -40,7 +39,6 @@ impl Serializable for RP25519 { } } - ///## Panics /// Panics when decompressing invalid curve point. This can happen when deserialize curve point /// from bit array that does not have a valid representation on the curve @@ -93,20 +91,23 @@ impl std::ops::SubAssign for RP25519 { ///## Panics /// Panics when decompressing invalid curve point. This can happen when deserialize curve point /// from bit array that does not have a valid representation on the curve -impl std::ops::Mul< Fp25519> for RP25519 { +impl std::ops::Mul for RP25519 { type Output = Self; - fn mul(self, rhs: Fp25519) -> RP25519 { - (self.0.decompress().unwrap() * Scalar::from(rhs)).compress().into() + fn mul(self, rhs: Fp25519) -> RP25519 { + (self.0.decompress().unwrap() * Scalar::from(rhs)) + .compress() + .into() } } -impl std::ops::MulAssign< Fp25519> for RP25519 { +impl std::ops::MulAssign for RP25519 { #[allow(clippy::assign_op_pattern)] - fn mul_assign(&mut self, rhs: Fp25519) {*self = *self * rhs} + fn mul_assign(&mut self, rhs: Fp25519) { + *self = *self * rhs + } } - impl From for RP25519 { fn from(s: Scalar) -> Self { RP25519(RistrettoPoint::mul_base(&s).compress()) @@ -208,7 +209,7 @@ mod test { let fp_h = RP25519::from(fp_e) * fp_f; assert_eq!(fp_h, RP25519::from(fp_g)); assert_ne!(fp_h, RP25519(constants::RISTRETTO_BASEPOINT_COMPRESSED)); - assert_eq!(RP25519::ZERO,fp_h*Scalar::ZERO.into()); + assert_eq!(RP25519::ZERO, fp_h * Scalar::ZERO.into()); } #[test] diff --git a/src/secret_sharing/mod.rs b/src/secret_sharing/mod.rs index 110bf74f5..8564bf4be 100644 --- a/src/secret_sharing/mod.rs +++ b/src/secret_sharing/mod.rs @@ -25,31 +25,23 @@ use crate::ff::{AddSub, AddSubAssign, Serializable}; /// Operations supported for weak shared values. pub trait Additive: -AddSub -+ AddSubAssign -+ Neg + AddSub + AddSubAssign + Neg { } impl Additive for T where - T: AddSub - + AddSubAssign - + Neg + T: AddSub + AddSubAssign + Neg { } /// Operations supported for shared values. pub trait Arithmetic: - Additive - + Mul - + MulAssign + Additive + Mul + MulAssign { } impl Arithmetic for T where - T: Additive - + Mul - + MulAssign + T: Additive + Mul + MulAssign { } @@ -60,7 +52,7 @@ pub trait Block: Sized + Copy + Debug { } pub trait WeakSharedValue: -Clone + Copy + PartialEq + Debug + Send + Sync + Sized + Additive + Serializable + 'static + Clone + Copy + PartialEq + Debug + Send + Sync + Sized + Additive + Serializable + 'static { type Storage: Block; @@ -79,7 +71,8 @@ pub trait SharedValue: const ZERO: Self; } -impl WeakSharedValue for T where +impl WeakSharedValue for T +where T: SharedValue, { type Storage = T::Storage; @@ -89,8 +82,6 @@ impl WeakSharedValue for T where const ZERO: Self = T::ZERO; } - - #[cfg(any(test, feature = "test-fixture", feature = "cli"))] impl IntoShares> for V where diff --git a/src/secret_sharing/replicated/semi_honest/additive_share.rs b/src/secret_sharing/replicated/semi_honest/additive_share.rs index fb7438c2f..0ae455ea9 100644 --- a/src/secret_sharing/replicated/semi_honest/additive_share.rs +++ b/src/secret_sharing/replicated/semi_honest/additive_share.rs @@ -10,8 +10,7 @@ use crate::{ ff::Serializable, secret_sharing::{ replicated::ReplicatedSecretSharing, Linear as LinearSecretSharing, SecretSharing, - SharedValue, - WeakSharedValue, + SharedValue, WeakSharedValue, }, }; diff --git a/src/secret_sharing/scheme.rs b/src/secret_sharing/scheme.rs index 4d843f4b8..0d2131eeb 100644 --- a/src/secret_sharing/scheme.rs +++ b/src/secret_sharing/scheme.rs @@ -3,7 +3,7 @@ use std::{ ops::{Mul, Neg}, }; -use super::{SharedValue,WeakSharedValue}; +use super::{SharedValue, WeakSharedValue}; use crate::ff::{AddSub, AddSubAssign, GaloisField}; /// Secret sharing scheme i.e. Replicated secret sharing From c9dc93193636ae83a6707d645cf3072cfb4e2988 Mon Sep 17 00:00:00 2001 From: Daniel Masny Date: Tue, 17 Oct 2023 15:19:38 -0700 Subject: [PATCH 59/76] fix clippy --- src/ff/curve_points.rs | 2 +- src/ff/ec_prime_field.rs | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/ff/curve_points.rs b/src/ff/curve_points.rs index 99aac7f18..a084b14a0 100644 --- a/src/ff/curve_points.rs +++ b/src/ff/curve_points.rs @@ -104,7 +104,7 @@ impl std::ops::Mul for RP25519 { impl std::ops::MulAssign for RP25519 { #[allow(clippy::assign_op_pattern)] fn mul_assign(&mut self, rhs: Fp25519) { - *self = *self * rhs + *self = *self * rhs; } } diff --git a/src/ff/ec_prime_field.rs b/src/ff/ec_prime_field.rs index d0ff48b72..15d5f33a7 100644 --- a/src/ff/ec_prime_field.rs +++ b/src/ff/ec_prime_field.rs @@ -119,6 +119,7 @@ impl From for Fp25519 { } } +#[cfg(test)] macro_rules! sc_hash_impl { ( $u_type:ty) => { impl From for $u_type { From 3aaeba40695e3c36703226d75f80afb72b807bdb Mon Sep 17 00:00:00 2001 From: Daniel Masny Date: Wed, 18 Oct 2023 11:03:53 -0700 Subject: [PATCH 60/76] refactor prf_ipa in separate module --- src/protocol/ipa_prf/mod.rs | 2 ++ src/protocol/{ => ipa_prf}/prf_eval/mod.rs | 6 +++--- src/protocol/{ => ipa_prf}/prf_sharding/bucket.rs | 2 +- .../{ => ipa_prf}/prf_sharding/feature_label_dot_product.rs | 2 +- src/protocol/{ => ipa_prf}/prf_sharding/mod.rs | 2 +- src/protocol/mod.rs | 4 +--- 6 files changed, 9 insertions(+), 9 deletions(-) create mode 100644 src/protocol/ipa_prf/mod.rs rename src/protocol/{ => ipa_prf}/prf_eval/mod.rs (95%) rename src/protocol/{ => ipa_prf}/prf_sharding/bucket.rs (99%) rename src/protocol/{ => ipa_prf}/prf_sharding/feature_label_dot_product.rs (99%) rename src/protocol/{ => ipa_prf}/prf_sharding/mod.rs (99%) diff --git a/src/protocol/ipa_prf/mod.rs b/src/protocol/ipa_prf/mod.rs new file mode 100644 index 000000000..755ef87a5 --- /dev/null +++ b/src/protocol/ipa_prf/mod.rs @@ -0,0 +1,2 @@ +pub mod prf_eval; +pub mod prf_sharding; diff --git a/src/protocol/prf_eval/mod.rs b/src/protocol/ipa_prf/prf_eval/mod.rs similarity index 95% rename from src/protocol/prf_eval/mod.rs rename to src/protocol/ipa_prf/prf_eval/mod.rs index 3a0a99a21..6d95e40cd 100644 --- a/src/protocol/prf_eval/mod.rs +++ b/src/protocol/ipa_prf/prf_eval/mod.rs @@ -9,7 +9,7 @@ use crate::{ prss::SharedRandomness, RecordId, }, - secret_sharing::replicated::{semi_honest::AdditiveShare, ReplicatedSecretSharing}, + secret_sharing::replicated::{ReplicatedSecretSharing, semi_honest::AdditiveShare}, seq_join::seq_try_join_all, }; @@ -103,11 +103,11 @@ mod test { use crate::{ ff::{curve_points::RP25519, ec_prime_field::Fp25519}, - protocol::prf_eval::compute_match_key_pseudonym, - secret_sharing::{replicated::semi_honest::AdditiveShare, IntoShares}, + secret_sharing::{IntoShares, replicated::semi_honest::AdditiveShare}, test_executor::run, test_fixture::{Reconstruct, Runner, TestWorld}, }; + use crate::protocol::ipa_prf::prf_eval::compute_match_key_pseudonym; #[derive(Copy, Clone)] struct ShuffledTestInput { diff --git a/src/protocol/prf_sharding/bucket.rs b/src/protocol/ipa_prf/prf_sharding/bucket.rs similarity index 99% rename from src/protocol/prf_sharding/bucket.rs rename to src/protocol/ipa_prf/prf_sharding/bucket.rs index d2ad77a11..450ffafa0 100644 --- a/src/protocol/prf_sharding/bucket.rs +++ b/src/protocol/ipa_prf/prf_sharding/bucket.rs @@ -124,7 +124,7 @@ pub mod tests { ff::{Field, Fp32BitPrime, Gf8Bit, Gf9Bit}, protocol::{ context::{Context, UpgradableContext, Validator}, - prf_sharding::bucket::move_single_value_to_bucket, + ipa_prf::prf_sharding::bucket::move_single_value_to_bucket, RecordId, }, rand::Rng, diff --git a/src/protocol/prf_sharding/feature_label_dot_product.rs b/src/protocol/ipa_prf/prf_sharding/feature_label_dot_product.rs similarity index 99% rename from src/protocol/prf_sharding/feature_label_dot_product.rs rename to src/protocol/ipa_prf/prf_sharding/feature_label_dot_product.rs index f87f788d8..bc492b62c 100644 --- a/src/protocol/prf_sharding/feature_label_dot_product.rs +++ b/src/protocol/ipa_prf/prf_sharding/feature_label_dot_product.rs @@ -371,7 +371,7 @@ where pub mod tests { use crate::{ ff::{Field, Fp32BitPrime, GaloisField, Gf2, Gf32Bit}, - protocol::prf_sharding::feature_label_dot_product::{ + protocol::ipa_prf::prf_sharding::feature_label_dot_product::{ compute_feature_label_dot_product, PrfShardedIpaInputRow, }, rand::Rng, diff --git a/src/protocol/prf_sharding/mod.rs b/src/protocol/ipa_prf/prf_sharding/mod.rs similarity index 99% rename from src/protocol/prf_sharding/mod.rs rename to src/protocol/ipa_prf/prf_sharding/mod.rs index fcca9ab97..06c75fdc4 100644 --- a/src/protocol/prf_sharding/mod.rs +++ b/src/protocol/ipa_prf/prf_sharding/mod.rs @@ -843,7 +843,7 @@ pub mod tests { ff::{Field, Fp32BitPrime, GaloisField, Gf2, Gf20Bit, Gf3Bit, Gf5Bit}, protocol::{ context::{UpgradableContext, Validator}, - prf_sharding::{attribution_and_capping_and_aggregation, do_aggregation}, + ipa_prf::prf_sharding::{attribution_and_capping_and_aggregation, do_aggregation}, }, rand::Rng, secret_sharing::{ diff --git a/src/protocol/mod.rs b/src/protocol/mod.rs index 660fa8eaa..fec8d66a4 100644 --- a/src/protocol/mod.rs +++ b/src/protocol/mod.rs @@ -7,9 +7,7 @@ pub mod dp; pub mod ipa; pub mod modulus_conversion; #[cfg(feature = "ipa-prf")] -pub mod prf_eval; -#[cfg(feature = "descriptive-gate")] -pub mod prf_sharding; +pub mod ipa_prf; pub mod prss; pub mod sort; pub mod step; From 04fe4d3e686900235dbe75b4f1e1218de54c3e0f Mon Sep 17 00:00:00 2001 From: Daniel Masny Date: Wed, 18 Oct 2023 11:05:41 -0700 Subject: [PATCH 61/76] fmt --- src/protocol/ipa_prf/prf_eval/mod.rs | 6 +++--- src/protocol/mod.rs | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/protocol/ipa_prf/prf_eval/mod.rs b/src/protocol/ipa_prf/prf_eval/mod.rs index 6d95e40cd..4da81759c 100644 --- a/src/protocol/ipa_prf/prf_eval/mod.rs +++ b/src/protocol/ipa_prf/prf_eval/mod.rs @@ -9,7 +9,7 @@ use crate::{ prss::SharedRandomness, RecordId, }, - secret_sharing::replicated::{ReplicatedSecretSharing, semi_honest::AdditiveShare}, + secret_sharing::replicated::{semi_honest::AdditiveShare, ReplicatedSecretSharing}, seq_join::seq_try_join_all, }; @@ -103,11 +103,11 @@ mod test { use crate::{ ff::{curve_points::RP25519, ec_prime_field::Fp25519}, - secret_sharing::{IntoShares, replicated::semi_honest::AdditiveShare}, + protocol::ipa_prf::prf_eval::compute_match_key_pseudonym, + secret_sharing::{replicated::semi_honest::AdditiveShare, IntoShares}, test_executor::run, test_fixture::{Reconstruct, Runner, TestWorld}, }; - use crate::protocol::ipa_prf::prf_eval::compute_match_key_pseudonym; #[derive(Copy, Clone)] struct ShuffledTestInput { diff --git a/src/protocol/mod.rs b/src/protocol/mod.rs index fec8d66a4..3dac77c62 100644 --- a/src/protocol/mod.rs +++ b/src/protocol/mod.rs @@ -5,9 +5,9 @@ pub mod boolean; pub mod context; pub mod dp; pub mod ipa; -pub mod modulus_conversion; #[cfg(feature = "ipa-prf")] pub mod ipa_prf; +pub mod modulus_conversion; pub mod prss; pub mod sort; pub mod step; From 7db9376853588232a3fc6693d6e866a995e1ffb5 Mon Sep 17 00:00:00 2001 From: Daniel Masny Date: Fri, 20 Oct 2023 15:00:05 -0700 Subject: [PATCH 62/76] adressing Alex's comments --- src/error.rs | 4 ++-- src/ff/curve_points.rs | 10 +++++----- src/ff/ec_prime_field.rs | 10 +++++++--- src/protocol/ipa_prf/prf_eval/mod.rs | 5 ++--- 4 files changed, 16 insertions(+), 13 deletions(-) diff --git a/src/error.rs b/src/error.rs index 7d6456c7f..de41eda4b 100644 --- a/src/error.rs +++ b/src/error.rs @@ -58,8 +58,8 @@ pub enum Error { InvalidReport(#[from] InvalidReportError), #[error("unsupported: {0}")] Unsupported(String), - #[error("Decompressing invalid elliptic curve point")] - DecompressingInvalidCurvePoint, + #[error("Decompressing invalid elliptic curve point: {0}")] + DecompressingInvalidCurvePoint(String), } impl Default for Error { diff --git a/src/ff/curve_points.rs b/src/ff/curve_points.rs index a084b14a0..f4cb50bba 100644 --- a/src/ff/curve_points.rs +++ b/src/ff/curve_points.rs @@ -3,8 +3,6 @@ use curve25519_dalek::{ Scalar, }; use generic_array::GenericArray; -use hkdf::Hkdf; -use sha2::Sha256; use typenum::U32; use crate::{ @@ -35,6 +33,7 @@ impl Serializable for RP25519 { } fn deserialize(buf: &GenericArray) -> Self { + debug_assert!(CompressedRistretto((*buf).into()).decompress().is_some()); RP25519(CompressedRistretto((*buf).into())) } } @@ -87,7 +86,6 @@ impl std::ops::SubAssign for RP25519 { } ///Scalar Multiplication -///<'a, 'b> `std::ops::Mul<&'b"` Fp25519 for &'a ///## Panics /// Panics when decompressing invalid curve point. This can happen when deserialize curve point /// from bit array that does not have a valid representation on the curve @@ -136,6 +134,8 @@ macro_rules! cp_hash_impl { ( $u_type:ty) => { impl From for $u_type { fn from(s: RP25519) -> Self { + use hkdf::Hkdf; + use sha2::Sha256; let hk = Hkdf::::new(None, s.0.as_bytes()); let mut okm = <$u_type>::MIN.to_le_bytes(); //error invalid length from expand only happens when okm is very large @@ -150,8 +150,6 @@ cp_hash_impl!(u128); cp_hash_impl!(u64); -#[cfg(test)] -cp_hash_impl!(u32); #[cfg(test)] impl rand::distributions::Distribution for rand::distributions::Standard { @@ -174,6 +172,8 @@ mod test { secret_sharing::WeakSharedValue, }; + cp_hash_impl!(u32); + #[test] fn serde_25519() { let mut rng = thread_rng(); diff --git a/src/ff/ec_prime_field.rs b/src/ff/ec_prime_field.rs index 15d5f33a7..02f0742df 100644 --- a/src/ff/ec_prime_field.rs +++ b/src/ff/ec_prime_field.rs @@ -124,6 +124,8 @@ macro_rules! sc_hash_impl { ( $u_type:ty) => { impl From for $u_type { fn from(s: Fp25519) -> Self { + use hkdf::Hkdf; + use sha2::Sha256; let hk = Hkdf::::new(None, s.0.as_bytes()); let mut okm = <$u_type>::MIN.to_le_bytes(); //error invalid length from expand only happens when okm is very large @@ -134,6 +136,8 @@ macro_rules! sc_hash_impl { impl From<$u_type> for Fp25519 { fn from(s: $u_type) -> Self { + use hkdf::Hkdf; + use sha2::Sha256; let hk = Hkdf::::new(None, &s.to_le_bytes()); let mut okm = [0u8; 32]; //error invalid length from expand only happens when okm is very large @@ -147,10 +151,7 @@ macro_rules! sc_hash_impl { #[cfg(test)] sc_hash_impl!(u64); -#[cfg(test)] -sc_hash_impl!(u32); -/// Daniel had to implement this since PRSS wants it, prefer not to impl Field for Fp25519 { const ONE: Fp25519 = Fp25519::ONE; @@ -198,6 +199,9 @@ mod test { secret_sharing::SharedValue, }; + + sc_hash_impl!(u32); + #[test] fn serde_25519() { let mut rng = thread_rng(); diff --git a/src/protocol/ipa_prf/prf_eval/mod.rs b/src/protocol/ipa_prf/prf_eval/mod.rs index 4da81759c..fe9b2540e 100644 --- a/src/protocol/ipa_prf/prf_eval/mod.rs +++ b/src/protocol/ipa_prf/prf_eval/mod.rs @@ -10,7 +10,6 @@ use crate::{ RecordId, }, secret_sharing::replicated::{semi_honest::AdditiveShare, ReplicatedSecretSharing}, - seq_join::seq_try_join_all, }; #[derive(Step)] @@ -37,7 +36,7 @@ where .iter() .enumerate() .map(|(i, x)| eval_dy_prf(ctx.clone(), i.into(), &prf_key, x)); - seq_try_join_all(sh_ctx.active_work(), futures).await + ctx.try_join(futures).await } impl From> for AdditiveShare { @@ -53,7 +52,7 @@ where { ctx.narrow(&Step::PRFKeyGen) .prss() - .generate_replicated(u128::MAX - 100u128) + .generate_replicated(RecordId(0)) } /// evaluates the Dodis-Yampolski PRF g^(1/(k+x)) From 7c211b7d0dec9b3e10bc64a6a25958a7953db0a3 Mon Sep 17 00:00:00 2001 From: Daniel Masny Date: Fri, 20 Oct 2023 15:01:26 -0700 Subject: [PATCH 63/76] fmt --- src/ff/curve_points.rs | 1 - src/ff/ec_prime_field.rs | 2 -- 2 files changed, 3 deletions(-) diff --git a/src/ff/curve_points.rs b/src/ff/curve_points.rs index f4cb50bba..2b06f973e 100644 --- a/src/ff/curve_points.rs +++ b/src/ff/curve_points.rs @@ -150,7 +150,6 @@ cp_hash_impl!(u128); cp_hash_impl!(u64); - #[cfg(test)] impl rand::distributions::Distribution for rand::distributions::Standard { fn sample(&self, rng: &mut R) -> RP25519 { diff --git a/src/ff/ec_prime_field.rs b/src/ff/ec_prime_field.rs index 02f0742df..ba753eb40 100644 --- a/src/ff/ec_prime_field.rs +++ b/src/ff/ec_prime_field.rs @@ -151,7 +151,6 @@ macro_rules! sc_hash_impl { #[cfg(test)] sc_hash_impl!(u64); - impl Field for Fp25519 { const ONE: Fp25519 = Fp25519::ONE; @@ -199,7 +198,6 @@ mod test { secret_sharing::SharedValue, }; - sc_hash_impl!(u32); #[test] From 4d5b1050543be557c606229cf3e7848f6ba40c94 Mon Sep 17 00:00:00 2001 From: Daniel Masny Date: Fri, 20 Oct 2023 16:59:31 -0700 Subject: [PATCH 64/76] add comments --- src/ff/curve_points.rs | 22 ++++++++++++++++++++-- src/ff/ec_prime_field.rs | 14 +++++++++++++- src/protocol/ipa_prf/prf_eval/mod.rs | 12 ++++++++++-- src/secret_sharing/mod.rs | 4 ++++ 4 files changed, 47 insertions(+), 5 deletions(-) diff --git a/src/ff/curve_points.rs b/src/ff/curve_points.rs index 2b06f973e..ec42eba76 100644 --- a/src/ff/curve_points.rs +++ b/src/ff/curve_points.rs @@ -14,11 +14,21 @@ impl Block for CompressedRistretto { type Size = U32; } -///ristretto point for curve 25519 +///ristretto point for curve 25519, +/// we store it in compressed format since it is 3 times smaller and we do a limited amount of +/// arithmetic operations on the curve points +/// +/// We use ristretto points such that we have a prime order elliptic curve, +/// This is needed for the Dodis Yampolski PRF +/// +/// decompressing invalid curve points will cause panics, +/// since we always generate curve points from scalars (elements in Fp25519) and +/// only deserialize previously serialized valid points, panics will not occur +/// However, we still added a debug assert to deserialize since values are sent by other servers #[derive(Clone, Copy, PartialEq, Debug)] pub struct RP25519(CompressedRistretto); -/// using compressed ristretto point +/// Implementing trait for secret sharing impl WeakSharedValue for RP25519 { type Storage = CompressedRistretto; const BITS: u32 = 256; @@ -86,6 +96,7 @@ impl std::ops::SubAssign for RP25519 { } ///Scalar Multiplication +/// allows to multiply curve points with scalars from Fp25519 ///## Panics /// Panics when decompressing invalid curve point. This can happen when deserialize curve point /// from bit array that does not have a valid representation on the curve @@ -130,6 +141,7 @@ impl From for CompressedRistretto { } } +///allows to convert curve points into unsigned integers, preserving high entropy macro_rules! cp_hash_impl { ( $u_type:ty) => { impl From for $u_type { @@ -150,6 +162,8 @@ cp_hash_impl!(u128); cp_hash_impl!(u64); +/// implementing random curve point generation for testing purposes, +/// in the actual IPA protocol, we generate them from scalars, i.e. Fp25519 #[cfg(test)] impl rand::distributions::Distribution for rand::distributions::Standard { fn sample(&self, rng: &mut R) -> RP25519 { @@ -173,6 +187,7 @@ mod test { cp_hash_impl!(u32); + ///testing serialize and deserialize #[test] fn serde_25519() { let mut rng = thread_rng(); @@ -183,6 +198,7 @@ mod test { assert_eq!(input, output); } + ///testing conversion from scalar to Fp25519 and curve point, i.e. RP25519 #[test] fn scalar_to_point() { let a = Scalar::ONE; @@ -193,6 +209,7 @@ mod test { assert_eq!(c, RP25519(constants::RISTRETTO_BASEPOINT_COMPRESSED)); } + ///testing simple curve arithmetics to check that curve25519_dalek library is used correctly #[test] fn curve_arithmetics() { let mut rng = thread_rng(); @@ -211,6 +228,7 @@ mod test { assert_eq!(RP25519::ZERO, fp_h * Scalar::ZERO.into()); } + ///testing curve to unsigned integer conversion has entropy (!= 0) #[test] fn curve_point_to_hash() { let mut rng = thread_rng(); diff --git a/src/ff/ec_prime_field.rs b/src/ff/ec_prime_field.rs index ba753eb40..9bd31ddbb 100644 --- a/src/ff/ec_prime_field.rs +++ b/src/ff/ec_prime_field.rs @@ -13,12 +13,15 @@ impl Block for Scalar { type Size = U32; } +///implements the Scalar field for elliptic curve 25519 +/// we use elements in Fp25519 to generate curve points and operate on the curve #[derive(Clone, Copy, PartialEq, Debug)] pub struct Fp25519(::Storage); impl Fp25519 { pub const ONE: Self = Self(Scalar::ONE); + ///allow invert for scalars, i.e. computes 1/a mod p ///# Panics /// Panics when self is zero #[must_use] @@ -28,12 +31,14 @@ impl Fp25519 { } } +///trait for secret sharing impl SharedValue for Fp25519 { type Storage = Scalar; const BITS: u32 = 256; const ZERO: Self = Self(Scalar::ZERO); } +///conversion to Scalar struct of curve25519_dalek impl From for Scalar { fn from(s: Fp25519) -> Self { s.0 @@ -52,6 +57,7 @@ impl Serializable for Fp25519 { } } +///generate random elements in Fp25519 impl rand::distributions::Distribution for rand::distributions::Standard { fn sample(&self, rng: &mut R) -> Fp25519 { let mut scalar_bytes = [0u8; 32]; @@ -119,6 +125,7 @@ impl From for Fp25519 { } } +///conversion from and to unsigned integers, preserving entropy, for testing purposes only #[cfg(test)] macro_rules! sc_hash_impl { ( $u_type:ty) => { @@ -151,6 +158,7 @@ macro_rules! sc_hash_impl { #[cfg(test)] sc_hash_impl!(u64); +///implement Field because required by PRSS impl Field for Fp25519 { const ONE: Fp25519 = Fp25519::ONE; @@ -174,6 +182,7 @@ impl Field for Fp25519 { } } +///implement TryFrom since required by Field impl TryFrom for Fp25519 { type Error = crate::error::Error; @@ -200,6 +209,7 @@ mod test { sc_hash_impl!(u32); + ///test serialize and deserialize #[test] fn serde_25519() { let mut rng = thread_rng(); @@ -210,7 +220,7 @@ mod test { assert_eq!(input, output); } - // These are just simple arithmetic tests since arithmetics are checked by curve25519_dalek + ///test simple arithmetics to check that curve25519_dalek is used correctly #[test] fn simple_arithmetics_25519() { let a = Fp25519(Scalar::from_bytes_mod_order([ @@ -241,12 +251,14 @@ mod test { assert_eq!(ec, e); } + ///test random field element generation (!= 0) #[test] fn simple_random_25519() { let mut rng = thread_rng(); assert_ne!(Fp25519::ZERO, rng.gen::()); } + ///test inversion for field elements #[test] fn invert_25519() { let mut rng = thread_rng(); diff --git a/src/protocol/ipa_prf/prf_eval/mod.rs b/src/protocol/ipa_prf/prf_eval/mod.rs index fe9b2540e..7a65c0191 100644 --- a/src/protocol/ipa_prf/prf_eval/mod.rs +++ b/src/protocol/ipa_prf/prf_eval/mod.rs @@ -21,6 +21,10 @@ pub(crate) enum Step { Revealz, } +/// generates match key pseudonyms from match keys (in Fp25519 format) and PRF key +/// PRF key needs to be generated separately using gen_prf_key +/// +/// gen_prf_key is not included such that compute_match_key_pseudonym can be tested for correctness /// # Errors /// Propagates errors from multiplications pub async fn compute_match_key_pseudonym( @@ -57,8 +61,8 @@ where /// evaluates the Dodis-Yampolski PRF g^(1/(k+x)) /// the input x and k are secret shared over finite field Fp25519, i.e. the scalar field of curve 25519 -/// PRF key k is generated using keygen -/// In 3IPA, x is the match key +/// PRF key k needs to be generated using gen_prf_key +/// x is the match key in Fp25519 format /// outputs a u64 as specified in `protocol/prf_sharding/mod.rs`, all parties learn the output /// # Errors /// Propagates errors from multiplications, reveal and scalar multiplication @@ -108,11 +112,13 @@ mod test { test_fixture::{Reconstruct, Runner, TestWorld}, }; + ///defining test input struct #[derive(Copy, Clone)] struct ShuffledTestInput { match_key: Fp25519, } + ///defining test output struct #[derive(Debug, PartialEq)] struct TestOutput { match_key_pseudonym: u64, @@ -142,6 +148,8 @@ mod test { } } + ///testing correctness of DY PRF evaluation + /// by checking MPC generated pseudonym with pseudonym generated in the clear #[test] fn semi_honest() { run(|| async move { diff --git a/src/secret_sharing/mod.rs b/src/secret_sharing/mod.rs index 8564bf4be..1a7dda8c2 100644 --- a/src/secret_sharing/mod.rs +++ b/src/secret_sharing/mod.rs @@ -51,6 +51,8 @@ pub trait Block: Sized + Copy + Debug { type Size: ArrayLength; } + +///allows basic secret sharing operations pub trait WeakSharedValue: Clone + Copy + PartialEq + Debug + Send + Sync + Sized + Additive + Serializable + 'static { @@ -61,6 +63,7 @@ pub trait WeakSharedValue: const ZERO: Self; } +///allows advanced secret sharing operations, requires multiplication pub trait SharedValue: Clone + Copy + PartialEq + Debug + Send + Sync + Sized + Arithmetic + Serializable + 'static { @@ -71,6 +74,7 @@ pub trait SharedValue: const ZERO: Self; } +///any SharedValue is also a WeakSharedValue impl WeakSharedValue for T where T: SharedValue, From 39c7ced4902fb59eac7d3c9d4bdc29a55c33b8f6 Mon Sep 17 00:00:00 2001 From: Daniel Masny Date: Fri, 20 Oct 2023 17:02:24 -0700 Subject: [PATCH 65/76] fix lint --- src/ff/curve_points.rs | 2 +- src/ff/ec_prime_field.rs | 6 +++--- src/protocol/ipa_prf/prf_eval/mod.rs | 6 +++--- src/secret_sharing/mod.rs | 2 +- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/ff/curve_points.rs b/src/ff/curve_points.rs index ec42eba76..8eaa57623 100644 --- a/src/ff/curve_points.rs +++ b/src/ff/curve_points.rs @@ -209,7 +209,7 @@ mod test { assert_eq!(c, RP25519(constants::RISTRETTO_BASEPOINT_COMPRESSED)); } - ///testing simple curve arithmetics to check that curve25519_dalek library is used correctly + ///testing simple curve arithmetics to check that `curve25519_dalek` library is used correctly #[test] fn curve_arithmetics() { let mut rng = thread_rng(); diff --git a/src/ff/ec_prime_field.rs b/src/ff/ec_prime_field.rs index 9bd31ddbb..3385f10e8 100644 --- a/src/ff/ec_prime_field.rs +++ b/src/ff/ec_prime_field.rs @@ -38,7 +38,7 @@ impl SharedValue for Fp25519 { const ZERO: Self = Self(Scalar::ZERO); } -///conversion to Scalar struct of curve25519_dalek +///conversion to Scalar struct of `curve25519_dalek` impl From for Scalar { fn from(s: Fp25519) -> Self { s.0 @@ -182,7 +182,7 @@ impl Field for Fp25519 { } } -///implement TryFrom since required by Field +///implement `TryFrom` since required by Field impl TryFrom for Fp25519 { type Error = crate::error::Error; @@ -220,7 +220,7 @@ mod test { assert_eq!(input, output); } - ///test simple arithmetics to check that curve25519_dalek is used correctly + ///test simple arithmetics to check that `curve25519_dalek` is used correctly #[test] fn simple_arithmetics_25519() { let a = Fp25519(Scalar::from_bytes_mod_order([ diff --git a/src/protocol/ipa_prf/prf_eval/mod.rs b/src/protocol/ipa_prf/prf_eval/mod.rs index 7a65c0191..ff37e30eb 100644 --- a/src/protocol/ipa_prf/prf_eval/mod.rs +++ b/src/protocol/ipa_prf/prf_eval/mod.rs @@ -22,9 +22,9 @@ pub(crate) enum Step { } /// generates match key pseudonyms from match keys (in Fp25519 format) and PRF key -/// PRF key needs to be generated separately using gen_prf_key +/// PRF key needs to be generated separately using `gen_prf_key` /// -/// gen_prf_key is not included such that compute_match_key_pseudonym can be tested for correctness +/// `gen_prf_key` is not included such that `compute_match_key_pseudonym` can be tested for correctness /// # Errors /// Propagates errors from multiplications pub async fn compute_match_key_pseudonym( @@ -61,7 +61,7 @@ where /// evaluates the Dodis-Yampolski PRF g^(1/(k+x)) /// the input x and k are secret shared over finite field Fp25519, i.e. the scalar field of curve 25519 -/// PRF key k needs to be generated using gen_prf_key +/// PRF key k needs to be generated using `gen_prf_key` /// x is the match key in Fp25519 format /// outputs a u64 as specified in `protocol/prf_sharding/mod.rs`, all parties learn the output /// # Errors diff --git a/src/secret_sharing/mod.rs b/src/secret_sharing/mod.rs index 1a7dda8c2..155b1f609 100644 --- a/src/secret_sharing/mod.rs +++ b/src/secret_sharing/mod.rs @@ -74,7 +74,7 @@ pub trait SharedValue: const ZERO: Self; } -///any SharedValue is also a WeakSharedValue +///any `SharedValue` is also a `WeakSharedValue` impl WeakSharedValue for T where T: SharedValue, From e5db3971ee8e67a403519f1a853279b5c057bb95 Mon Sep 17 00:00:00 2001 From: Daniel Masny Date: Fri, 20 Oct 2023 17:03:06 -0700 Subject: [PATCH 66/76] fmt --- src/secret_sharing/mod.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/secret_sharing/mod.rs b/src/secret_sharing/mod.rs index 155b1f609..441fe1f21 100644 --- a/src/secret_sharing/mod.rs +++ b/src/secret_sharing/mod.rs @@ -51,7 +51,6 @@ pub trait Block: Sized + Copy + Debug { type Size: ArrayLength; } - ///allows basic secret sharing operations pub trait WeakSharedValue: Clone + Copy + PartialEq + Debug + Send + Sync + Sized + Additive + Serializable + 'static From 0efd323824820afa3d886a737b5dd60334af2cf9 Mon Sep 17 00:00:00 2001 From: Daniel Masny Date: Wed, 1 Nov 2023 17:21:47 -0700 Subject: [PATCH 67/76] fix errors after merge --- src/protocol/ipa_prf/prf_sharding/bucket.rs | 5 ++--- src/protocol/ipa_prf/prf_sharding/mod.rs | 3 +-- src/query/runner/oprf_ipa.rs | 2 +- src/test_fixture/ipa.rs | 2 +- 4 files changed, 5 insertions(+), 7 deletions(-) diff --git a/src/protocol/ipa_prf/prf_sharding/bucket.rs b/src/protocol/ipa_prf/prf_sharding/bucket.rs index c45c375dc..32cfd8b56 100644 --- a/src/protocol/ipa_prf/prf_sharding/bucket.rs +++ b/src/protocol/ipa_prf/prf_sharding/bucket.rs @@ -1,12 +1,11 @@ use embed_doc_image::embed_doc_image; +use ipa_macros::Step; use crate::{ error::Error, ff::{GaloisField, PrimeField, Serializable}, protocol::{ - basics::SecureMul, context::UpgradedContext, ipa_prf::prf_sharding::BinaryTreeDepthStep, - step::BitOpStep, RecordId, - basics::SecureMul, context::UpgradedContext, prf_sharding::BinaryTreeDepthStep, RecordId, + basics::SecureMul, context::UpgradedContext, ipa_prf::prf_sharding::BinaryTreeDepthStep, RecordId, }, secret_sharing::{ replicated::malicious::ExtendableField, BitDecomposed, Linear as LinearSecretSharing, diff --git a/src/protocol/ipa_prf/prf_sharding/mod.rs b/src/protocol/ipa_prf/prf_sharding/mod.rs index 06c75fdc4..0f6aa8ed2 100644 --- a/src/protocol/ipa_prf/prf_sharding/mod.rs +++ b/src/protocol/ipa_prf/prf_sharding/mod.rs @@ -10,13 +10,12 @@ use futures_util::{ }; use ipa_macros::Step; -use super::boolean::saturating_sum::SaturatingSum; use crate::{ error::Error, ff::{Field, GaloisField, Gf2, PrimeField, Serializable}, protocol::{ basics::{if_else, SecureMul, ShareKnownValue}, - boolean::{comparison::bitwise_less_than_constant, or::or}, + boolean::{comparison::bitwise_less_than_constant, or::or, saturating_sum::SaturatingSum}, context::{UpgradableContext, UpgradedContext, Validator}, modulus_conversion::convert_bits, step::BitOpStep, diff --git a/src/query/runner/oprf_ipa.rs b/src/query/runner/oprf_ipa.rs index e77a0300e..d2951f0f1 100644 --- a/src/query/runner/oprf_ipa.rs +++ b/src/query/runner/oprf_ipa.rs @@ -12,7 +12,7 @@ use crate::{ protocol::{ basics::ShareKnownValue, context::{UpgradableContext, UpgradedContext}, - prf_sharding::{attribution_and_capping_and_aggregation, PrfShardedIpaInputRow}, + ipa_prf::prf_sharding::{attribution_and_capping_and_aggregation, PrfShardedIpaInputRow}, BreakdownKey, Timestamp, TriggerValue, }, report::{EventType, OprfReport}, diff --git a/src/test_fixture/ipa.rs b/src/test_fixture/ipa.rs index e6f899b79..530084029 100644 --- a/src/test_fixture/ipa.rs +++ b/src/test_fixture/ipa.rs @@ -243,7 +243,7 @@ pub async fn test_oprf_ipa( ff::{Field, Gf2}, protocol::{ basics::ShareKnownValue, - prf_sharding::{attribution_and_capping_and_aggregation, PrfShardedIpaInputRow}, + ipa_prf::prf_sharding::{attribution_and_capping_and_aggregation, PrfShardedIpaInputRow}, }, report::EventType, secret_sharing::SharedValue, From 60d8ab6c65d62a9200427108a2c02f97cd9a34ee Mon Sep 17 00:00:00 2001 From: Daniel Masny Date: Wed, 1 Nov 2023 17:22:14 -0700 Subject: [PATCH 68/76] fmt --- src/protocol/ipa_prf/prf_sharding/bucket.rs | 3 ++- src/test_fixture/ipa.rs | 4 +++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/protocol/ipa_prf/prf_sharding/bucket.rs b/src/protocol/ipa_prf/prf_sharding/bucket.rs index 32cfd8b56..a1e62d1a2 100644 --- a/src/protocol/ipa_prf/prf_sharding/bucket.rs +++ b/src/protocol/ipa_prf/prf_sharding/bucket.rs @@ -5,7 +5,8 @@ use crate::{ error::Error, ff::{GaloisField, PrimeField, Serializable}, protocol::{ - basics::SecureMul, context::UpgradedContext, ipa_prf::prf_sharding::BinaryTreeDepthStep, RecordId, + basics::SecureMul, context::UpgradedContext, ipa_prf::prf_sharding::BinaryTreeDepthStep, + RecordId, }, secret_sharing::{ replicated::malicious::ExtendableField, BitDecomposed, Linear as LinearSecretSharing, diff --git a/src/test_fixture/ipa.rs b/src/test_fixture/ipa.rs index 530084029..7668881c8 100644 --- a/src/test_fixture/ipa.rs +++ b/src/test_fixture/ipa.rs @@ -243,7 +243,9 @@ pub async fn test_oprf_ipa( ff::{Field, Gf2}, protocol::{ basics::ShareKnownValue, - ipa_prf::prf_sharding::{attribution_and_capping_and_aggregation, PrfShardedIpaInputRow}, + ipa_prf::prf_sharding::{ + attribution_and_capping_and_aggregation, PrfShardedIpaInputRow, + }, }, report::EventType, secret_sharing::SharedValue, From a17eaa9dbf72814fd0a9235616cb504daef634f3 Mon Sep 17 00:00:00 2001 From: Daniel Masny Date: Wed, 1 Nov 2023 17:28:46 -0700 Subject: [PATCH 69/76] add flag --- src/query/runner/mod.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/query/runner/mod.rs b/src/query/runner/mod.rs index d9eb28f8f..9875c7ced 100644 --- a/src/query/runner/mod.rs +++ b/src/query/runner/mod.rs @@ -1,5 +1,6 @@ mod aggregate; mod ipa; +#[cfg(feature = "ipa-prf")] mod oprf_ipa; #[cfg(any(test, feature = "cli", feature = "test-fixture"))] From 83d74cb4656e94b1eefdd182b4b457c72a7059d1 Mon Sep 17 00:00:00 2001 From: Daniel Masny Date: Wed, 1 Nov 2023 17:30:10 -0700 Subject: [PATCH 70/76] remove flag --- src/query/runner/mod.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/query/runner/mod.rs b/src/query/runner/mod.rs index 9875c7ced..d9eb28f8f 100644 --- a/src/query/runner/mod.rs +++ b/src/query/runner/mod.rs @@ -1,6 +1,5 @@ mod aggregate; mod ipa; -#[cfg(feature = "ipa-prf")] mod oprf_ipa; #[cfg(any(test, feature = "cli", feature = "test-fixture"))] From f8d26c958488e2dfc4ed0536e69839d02eddef90 Mon Sep 17 00:00:00 2001 From: Daniel Masny Date: Thu, 2 Nov 2023 12:52:25 -0700 Subject: [PATCH 71/76] add flag --- src/query/runner/mod.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/query/runner/mod.rs b/src/query/runner/mod.rs index d9eb28f8f..9875c7ced 100644 --- a/src/query/runner/mod.rs +++ b/src/query/runner/mod.rs @@ -1,5 +1,6 @@ mod aggregate; mod ipa; +#[cfg(feature = "ipa-prf")] mod oprf_ipa; #[cfg(any(test, feature = "cli", feature = "test-fixture"))] From 6c715ffd0eccda6c28cc201a6a0031783dd30869 Mon Sep 17 00:00:00 2001 From: Daniel Masny Date: Thu, 2 Nov 2023 12:55:48 -0700 Subject: [PATCH 72/76] add flag descriptive gate --- src/protocol/mod.rs | 2 +- src/query/runner/mod.rs | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/protocol/mod.rs b/src/protocol/mod.rs index 3dac77c62..cd46abdda 100644 --- a/src/protocol/mod.rs +++ b/src/protocol/mod.rs @@ -5,7 +5,7 @@ pub mod boolean; pub mod context; pub mod dp; pub mod ipa; -#[cfg(feature = "ipa-prf")] +#[cfg(feature = "descriptive-gate")] pub mod ipa_prf; pub mod modulus_conversion; pub mod prss; diff --git a/src/query/runner/mod.rs b/src/query/runner/mod.rs index 9875c7ced..d9eb28f8f 100644 --- a/src/query/runner/mod.rs +++ b/src/query/runner/mod.rs @@ -1,6 +1,5 @@ mod aggregate; mod ipa; -#[cfg(feature = "ipa-prf")] mod oprf_ipa; #[cfg(any(test, feature = "cli", feature = "test-fixture"))] From f640088df9e767c8a8fe24763f6c51495dfc02dd Mon Sep 17 00:00:00 2001 From: Alex Koshelev Date: Fri, 6 Oct 2023 20:19:53 -0700 Subject: [PATCH 73/76] add prf eval protocol + curve points + curve field --- src/protocol/basics/reveal.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/protocol/basics/reveal.rs b/src/protocol/basics/reveal.rs index 28e54a904..672c8a473 100644 --- a/src/protocol/basics/reveal.rs +++ b/src/protocol/basics/reveal.rs @@ -18,7 +18,7 @@ use crate::{ malicious::{AdditiveShare as MaliciousReplicated, ExtendableField}, semi_honest::AdditiveShare as Replicated, }, - SecretSharing, + SecretSharing, SharedValue, }, }; @@ -47,10 +47,10 @@ pub trait Reveal: Sized { /// i.e. their own shares and received share. #[async_trait] #[embed_doc_image("reveal", "images/reveal.png")] -impl Reveal for Replicated { - type Output = F; +impl Reveal for Replicated { + type Output = V; - async fn reveal<'fut>(&self, ctx: C, record_id: RecordId) -> Result + async fn reveal<'fut>(&self, ctx: C, record_id: RecordId) -> Result where C: 'fut, { From 444e67c947c73a909145e7e669a6b75b77bdcc9f Mon Sep 17 00:00:00 2001 From: danielmasny Date: Mon, 6 Nov 2023 09:04:14 -0800 Subject: [PATCH 74/76] fmt --- src/protocol/ipa_prf/prf_sharding/mod.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/protocol/ipa_prf/prf_sharding/mod.rs b/src/protocol/ipa_prf/prf_sharding/mod.rs index c548a2145..db62c95e0 100644 --- a/src/protocol/ipa_prf/prf_sharding/mod.rs +++ b/src/protocol/ipa_prf/prf_sharding/mod.rs @@ -17,12 +17,10 @@ use crate::{ ff::{Field, GaloisField, Gf2, PrimeField, Serializable}, helpers::Role, protocol::{ - boolean::saturating_sum::SaturatingSum, - modulus_conversion::ToBitConversionTriples, basics::{if_else, SecureMul, ShareKnownValue}, - boolean::{comparison::bitwise_less_than_constant, or::or}, + boolean::{comparison::bitwise_less_than_constant, or::or, saturating_sum::SaturatingSum}, context::{Context, UpgradableContext, UpgradedContext, Validator}, - modulus_conversion::{convert_bits, BitConversionTriple}, + modulus_conversion::{convert_bits, BitConversionTriple, ToBitConversionTriples}, step::BitOpStep, RecordId, }, From 164ab6d3812a44a43348aa488414dccbbc589dca Mon Sep 17 00:00:00 2001 From: Alex Koshelev Date: Mon, 6 Nov 2023 09:42:12 -0800 Subject: [PATCH 75/76] Fix compact gate tests --- src/protocol/ipa_prf/mod.rs | 1 + src/protocol/ipa_prf/{prf_eval/mod.rs => prf_eval.rs} | 0 src/protocol/mod.rs | 1 - 3 files changed, 1 insertion(+), 1 deletion(-) rename src/protocol/ipa_prf/{prf_eval/mod.rs => prf_eval.rs} (100%) diff --git a/src/protocol/ipa_prf/mod.rs b/src/protocol/ipa_prf/mod.rs index 755ef87a5..f3ee4a5f9 100644 --- a/src/protocol/ipa_prf/mod.rs +++ b/src/protocol/ipa_prf/mod.rs @@ -1,2 +1,3 @@ +#[cfg(feature = "descriptive-gate")] pub mod prf_eval; pub mod prf_sharding; diff --git a/src/protocol/ipa_prf/prf_eval/mod.rs b/src/protocol/ipa_prf/prf_eval.rs similarity index 100% rename from src/protocol/ipa_prf/prf_eval/mod.rs rename to src/protocol/ipa_prf/prf_eval.rs diff --git a/src/protocol/mod.rs b/src/protocol/mod.rs index 55e205b82..dc8f89fa1 100644 --- a/src/protocol/mod.rs +++ b/src/protocol/mod.rs @@ -5,7 +5,6 @@ pub mod boolean; pub mod context; pub mod dp; pub mod ipa; -#[cfg(feature = "descriptive-gate")] pub mod ipa_prf; pub mod modulus_conversion; pub mod prss; From 0cfa5ddd88dbcd4ca36c0bf98290d56460cfef85 Mon Sep 17 00:00:00 2001 From: Alex Koshelev Date: Mon, 6 Nov 2023 11:11:33 -0800 Subject: [PATCH 76/76] Remove descriptive-gate dependency for OPRF --- Cargo.toml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index ce7d91446..f65c44f08 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -42,7 +42,8 @@ compact-gate = ["ipa-macros/compact-gate"] # Standalone aggregation protocol. We use IPA infra for communication # but it has nothing to do with IPA. aggregate-circuit = [] -ipa-prf = ["descriptive-gate"] +# IPA protocol based on OPRF +ipa-prf = [] [dependencies] aes = "0.8.3"