diff --git a/ipa-core/src/ff/boolean_array.rs b/ipa-core/src/ff/boolean_array.rs index e733264f7..972f80fe3 100644 --- a/ipa-core/src/ff/boolean_array.rs +++ b/ipa-core/src/ff/boolean_array.rs @@ -462,6 +462,7 @@ macro_rules! boolean_array_impl { use crate::secret_sharing::replicated::ReplicatedSecretSharing; let bits = AdditiveShare::new(ONE, ONE); let iter = bits.into_iter(); + assert_eq!(iter.len(), $bits); for (i, j) in iter.enumerate() { if i == 0 { assert_eq!(j, AdditiveShare::new(Boolean::ONE, Boolean::ONE)); @@ -471,6 +472,18 @@ macro_rules! boolean_array_impl { } } + #[test] + fn iterate_secret_shared_boolean_array_len() { + use crate::secret_sharing::replicated::ReplicatedSecretSharing; + let bits = AdditiveShare::new(ONE, ONE); + let mut iter = bits.into_iter(); + assert_eq!(iter.len(), $bits); + for b in (0..$bits).rev() { + iter.next().unwrap(); + assert_eq!(iter.len(), b); + } + } + #[test] fn serde() { let ba = thread_rng().gen::<$name>(); diff --git a/ipa-core/src/ff/galois_field.rs b/ipa-core/src/ff/galois_field.rs index 64a345f6f..040d95ec3 100644 --- a/ipa-core/src/ff/galois_field.rs +++ b/ipa-core/src/ff/galois_field.rs @@ -703,31 +703,5 @@ bit_array_impl!( v } } - - impl From for bool { - fn from(value: Gf2) -> Self { - value != Gf2::ZERO - } - } - - impl From for Gf2 { - fn from(value: crate::ff::boolean::Boolean) -> Self { - bool::from(value).into() - } - } - - impl From for crate::ff::boolean::Boolean { - fn from(value: Gf2) -> Self { - bool::from(value).into() - } - } - - impl std::ops::Not for Gf2 { - type Output = Self; - - fn not(self) -> Self { - (!bool::from(self)).into() - } - } } ); diff --git a/ipa-core/src/secret_sharing/array.rs b/ipa-core/src/secret_sharing/array.rs index f05cc30dc..316178be8 100644 --- a/ipa-core/src/secret_sharing/array.rs +++ b/ipa-core/src/secret_sharing/array.rs @@ -313,3 +313,110 @@ where } impl Message for StdArray where Self: Serializable {} + +#[cfg(all(test, unit_test))] +mod test { + use proptest::{ + prelude::{prop, Arbitrary, Strategy}, + proptest, + }; + + use super::*; + + impl Arbitrary for StdArray + where + [V; N]: Arbitrary, + { + type Parameters = <[V; N] as Arbitrary>::Parameters; + type Strategy = prop::strategy::Map<<[V; N] as Arbitrary>::Strategy, fn([V; N]) -> Self>; + + fn arbitrary_with(args: Self::Parameters) -> Self::Strategy { + <[V; N]>::arbitrary_with(args).prop_map(Self) + } + } + + proptest! { + #[test] + fn add(a: StdArray, b: StdArray) { + let expected = StdArray([a.0[0] + b.0[0], a.0[1] + b.0[1]]); + let sum1 = &a + &b; + let sum2 = &a + b.clone(); + let sum3 = a.clone() + &b; + let sum4 = a + b; + assert_eq!(sum1, expected); + assert_eq!(sum2, expected); + assert_eq!(sum3, expected); + assert_eq!(sum4, expected); + } + + #[test] + fn add_assign(a: StdArray, b: StdArray) { + let expected = StdArray([a.0[0] + b.0[0], a.0[1] + b.0[1]]); + let mut sum1 = a.clone(); + let mut sum2 = a.clone(); + sum1 += &b; + sum2 += b; + assert_eq!(sum1, expected); + assert_eq!(sum2, expected); + } + + #[test] + fn sub(a: StdArray, b: StdArray) { + let expected = StdArray([a.0[0] - b.0[0], a.0[1] - b.0[1]]); + let diff1 = &a - &b; + let diff2 = &a - b.clone(); + let diff3 = a.clone() - &b; + let diff4 = a - b; + assert_eq!(diff1, expected); + assert_eq!(diff2, expected); + assert_eq!(diff3, expected); + assert_eq!(diff4, expected); + } + + #[test] + fn sub_assign(a: StdArray, b: StdArray) { + let expected = StdArray([a.0[0] - b.0[0], a.0[1] - b.0[1]]); + let mut diff1 = a.clone(); + let mut diff2 = a.clone(); + diff1 -= &b; + diff2 -= b; + assert_eq!(diff1, expected); + assert_eq!(diff2, expected); + } + + #[test] + fn mul_scalar(a: StdArray, b: Fp32BitPrime) { + let expected = StdArray([a.0[0] * b, a.0[1] * b]); + let b_ref = &b; // clippy complains inline ref to Copy type is needless + let prod1 = &a * b_ref; + let prod2 = &a * b; + let prod3 = a.clone() * b_ref; + let prod4 = a * b; + assert_eq!(prod1, expected); + assert_eq!(prod2, expected); + assert_eq!(prod3, expected); + assert_eq!(prod4, expected); + } + + #[test] + fn into_iter(a: StdArray) { + let expected = a.clone(); + let copy: StdArray = a.into_iter() + .collect::>() + .try_into() + .unwrap(); + assert_eq!(copy, expected); + } + + #[test] + fn get_set(mut a: StdArray, b: Fp32BitPrime, c: Fp32BitPrime) { + assert_eq!(a.get(0), a.0[0]); + a.set(0, b); + assert_eq!(a.get(0), b); + *a.get_mut(0) = c; + assert_eq!(a.get(0), c); + let from_fn = StdArray::::from_fn(|i| a.0[i]); + assert_eq!(from_fn, a); + } + } +} diff --git a/ipa-core/src/secret_sharing/replicated/semi_honest/additive_share.rs b/ipa-core/src/secret_sharing/replicated/semi_honest/additive_share.rs index 319a438c7..b998b67c4 100644 --- a/ipa-core/src/secret_sharing/replicated/semi_honest/additive_share.rs +++ b/ipa-core/src/secret_sharing/replicated/semi_honest/additive_share.rs @@ -419,10 +419,17 @@ where #[cfg(all(test, unit_test))] mod tests { - use super::AdditiveShare; + use proptest::{ + prelude::{prop, Arbitrary, Strategy}, + proptest, + }; + + use super::*; use crate::{ - ff::{Field, Fp31}, - secret_sharing::replicated::ReplicatedSecretSharing, + ff::{Field, Fp31, Fp32BitPrime}, + secret_sharing::{ + replicated::ReplicatedSecretSharing, SharedValue, StdArray, Vectorizable, + }, }; fn secret_share( @@ -565,4 +572,95 @@ mod tests { mult_by_constant_test_case((0, 0, 1), 2, 2); mult_by_constant_test_case((0, 0, 0), 2, 0); } + + impl Arbitrary for AdditiveShare + where + V: Vectorizable>, + StdArray: Arbitrary, + { + type Parameters = <(StdArray, StdArray) as Arbitrary>::Parameters; + type Strategy = prop::strategy::Map< + <(StdArray, StdArray) as Arbitrary>::Strategy, + fn((StdArray, StdArray)) -> Self, + >; + + fn arbitrary_with(args: Self::Parameters) -> Self::Strategy { + <(StdArray, StdArray)>::arbitrary_with(args) + .prop_map(|(l, r)| AdditiveShare::new_arr(l, r)) + } + } + + proptest! { + #[test] + fn vector_add_assign_proptest(a: AdditiveShare, b: AdditiveShare) { + let left_sum = a.left_arr() + b.left_arr(); + let right_sum = a.right_arr() + b.right_arr(); + let expected = AdditiveShare::new_arr(left_sum, right_sum); + let mut sum1 = a.clone(); + let mut sum2 = a; + sum1 += &b; + sum2 += b; + assert_eq!(sum1, expected); + assert_eq!(sum2, expected); + } + + #[test] + fn sub_proptest(a: AdditiveShare, b: AdditiveShare) { + let left_diff = a.left() - b.left(); + let right_diff = a.right() - b.right(); + let expected = AdditiveShare::new(left_diff, right_diff); + let diff1 = &a - &b; + let diff2 = &a - b.clone(); + let diff3 = a.clone() - &b; + let diff4 = a - b; + assert_eq!(diff1, expected); + assert_eq!(diff2, expected); + assert_eq!(diff3, expected); + assert_eq!(diff4, expected); + } + + #[test] + fn vector_sub_proptest(a: AdditiveShare, b: AdditiveShare) { + let left_diff = a.left_arr() - b.left_arr(); + let right_diff = a.right_arr() - b.right_arr(); + let expected = AdditiveShare::new_arr(left_diff, right_diff); + let diff1 = &a - &b; + let diff2 = &a - b.clone(); + let diff3 = a.clone() - &b; + let diff4 = a - b; + assert_eq!(diff1, expected); + assert_eq!(diff2, expected); + assert_eq!(diff3, expected); + assert_eq!(diff4, expected); + } + + #[test] + fn vector_sub_assign_proptest(a: AdditiveShare, b: AdditiveShare) { + let left_diff = a.left_arr() - b.left_arr(); + let right_diff = a.right_arr() - b.right_arr(); + let expected = AdditiveShare::new_arr(left_diff, right_diff); + let mut diff1 = a.clone(); + let mut diff2 = a; + diff1 -= &b; + diff2 -= b; + assert_eq!(diff1, expected); + assert_eq!(diff2, expected); + } + + #[test] + fn vector_mul_scalar_proptest(a: AdditiveShare, b: Fp32BitPrime) { + let left_prod = a.left_arr() * b; + let right_prod = a.right_arr() * b; + let expected = AdditiveShare::new_arr(left_prod, right_prod); + let b_ref = &b; // clippy complains inline ref to Copy type is needless + let prod1 = &a * b_ref; + let prod2 = &a * b; + let prod3 = a.clone() * b_ref; + let prod4 = a * b; + assert_eq!(prod1, expected); + assert_eq!(prod2, expected); + assert_eq!(prod3, expected); + assert_eq!(prod4, expected); + } + } }