Skip to content

Commit

Permalink
Coverage improvements
Browse files Browse the repository at this point in the history
  • Loading branch information
andyleiserson committed Jan 26, 2024
1 parent 8943763 commit ed3d9ec
Show file tree
Hide file tree
Showing 4 changed files with 192 additions and 0 deletions.
93 changes: 93 additions & 0 deletions ipa-core/src/ff/boolean_array.rs
Original file line number Diff line number Diff line change
Expand Up @@ -461,6 +461,13 @@ macro_rules! boolean_array_impl {
}
}

impl std::ops::Mul<Boolean> for $name {
type Output = Self;
fn mul(self, rhs: Boolean) -> Self::Output {
std::ops::Mul::mul(self, &rhs)
}
}

impl From<$name> for Store {
fn from(v: $name) -> Self {
v.0
Expand Down Expand Up @@ -619,6 +626,16 @@ macro_rules! boolean_array_impl {
assert_eq!(iter.len(), $bits - 1 - i);
}
}

#[test]
fn owned_iterator(a: $name) {
let mut iter = a.into_iter().enumerate();
assert_eq!(iter.len(), $bits);
while let Some((i, b)) = iter.next() {
assert_eq!(bool::from(b), a.0[i]);
assert_eq!(iter.len(), $bits - 1 - i);
}
}
}

#[test]
Expand Down Expand Up @@ -723,3 +740,79 @@ where
self.array
}
}

#[cfg(all(test, unit_test))]
mod tests {
use rand::{thread_rng, Rng};

use super::*;

// It does not seem worth running these tests for every BA type, although
// it would be worth writing a version for the largest BA type (which
// requires replacing truncate_from).

#[test]
#[allow(clippy::clone_on_copy, clippy::op_ref)]
pub fn add_sub() {
let mut rng = thread_rng();
let a = rng.gen::<u128>();
let b = rng.gen::<u128>();

let xor = BA8::truncate_from(a ^ b);

let a = BA8::truncate_from(a);
let b = BA8::truncate_from(b);

assert_eq!(&a + &b, xor);
assert_eq!(&a + b.clone(), xor);
assert_eq!(a.clone() + &b, xor);
assert_eq!(a.clone() + b.clone(), xor);

let mut tmp = a.clone();
tmp += &b;
assert_eq!(tmp, xor);

let mut tmp = a.clone();
tmp += b;
assert_eq!(tmp, xor);

// Sub not implemented yet for &BA
//assert_eq!(&a - &b, xor);
//assert_eq!(&a - b.clone(), xor);
assert_eq!(a.clone() - &b, xor);
assert_eq!(a.clone() - b.clone(), xor);

let mut tmp = a.clone();
tmp -= &b;
assert_eq!(tmp, xor);

let mut tmp = a.clone();
tmp -= b;
assert_eq!(tmp, xor);

assert_eq!(-a, a);
assert_eq!(a + (-a), BA8::ZERO);
}

#[test]
#[allow(clippy::clone_on_copy, clippy::op_ref)]
pub fn mul() {
let mut rng = thread_rng();
let a = rng.gen::<u128>();
let b = rng.gen::<u128>();
let c = rng.gen::<Boolean>();

let prod = BA8::truncate_from(a & b);

let mut a = BA8::truncate_from(a);
let b = BA8::truncate_from(b);

a *= b;
assert_eq!(a, prod);

assert_eq!(a * Boolean::from(false), BA8::ZERO);
assert_eq!(a * Boolean::from(true), a);
assert_eq!(a * c, if bool::from(c) { a } else { BA8::ZERO });
assert_eq!(a * &c, if bool::from(c) { a } else { BA8::ZERO });
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -394,6 +394,7 @@ mod test {

#[test]
#[ignore] // benchmark
#[cfg(not(coverage))]
fn semi_honest_compare_gt_novec() {
run(|| async move {
let world = TestWorld::default();
Expand Down Expand Up @@ -440,6 +441,7 @@ mod test {

#[test]
#[ignore] // benchmark
#[cfg(not(coverage))]
fn semi_honest_compare_gt_vec() {
run(|| async move {
const N: usize = 256;
Expand Down
96 changes: 96 additions & 0 deletions ipa-core/src/secret_sharing/decomposed.rs
Original file line number Diff line number Diff line change
Expand Up @@ -177,3 +177,99 @@ impl<S: Clone + Send + Sync> ArrayAccessRef for BitDecomposed<S> {
src
}
}

#[cfg(all(test, unit_test))]
mod tests {
use proptest::prelude::*;

use super::*;

const MAX_TEST_SIZE: usize = 1024;

impl<S> Arbitrary for BitDecomposed<S>
where
S: Debug,
Vec<S>: Arbitrary,
{
type Parameters = <Vec<S> as Arbitrary>::Parameters;
type Strategy = prop::strategy::Map<<Vec<S> as Arbitrary>::Strategy, fn(Vec<S>) -> Self>;

fn arbitrary_with(args: Self::Parameters) -> Self::Strategy {
Vec::<S>::arbitrary_with(args).prop_map(|bits| Self { bits })
}
}

prop_compose! {
fn val_and_index()
(vec in prop::collection::vec(any::<u8>(), 2..MAX_TEST_SIZE))
(index in 0..vec.len(), vec in Just(vec))
-> (BitDecomposed<u8>, usize) {
(BitDecomposed { bits: vec }, index)
}
}

proptest! {
#[test]
fn arrayaccess_get_set(
(mut a, ix) in val_and_index(),
b: u8,
c: u8,
d: u8,
) {
prop_assert_eq!(a.get(0), Some(&a.bits[0]));
a.set(0, &b);
prop_assert_eq!(a.get(0), Some(&b));
prop_assert_eq!(a.get(ix), Some(&a.bits[ix]));
a.set(ix, &c);
prop_assert_eq!(a.get(ix), Some(&c));
prop_assert_eq!(a.get(a.len() - 1), Some(&a.bits[a.len() - 1]));
a.set(a.len() - 1, &d);
prop_assert_eq!(a.get(a.len() - 1), Some(&d));
prop_assert_eq!(a.get(a.len()), None);
let BitDecomposed {
bits: mut a_mod,
} = a.clone();
a_mod[0] = b;
a_mod[ix] = c;
a_mod[a.len() - 1] = d;
prop_assert_eq!(a.bits, a_mod);
}

#[test]
fn arrayaccess_iter(val in any::<BitDecomposed<u8>>()) {
let mut iter = val.iter().enumerate();
prop_assert_eq!(iter.len(), val.len());
while let Some((i, v)) = iter.next() {
prop_assert_eq!(v, &val.bits[i]);
prop_assert_eq!(iter.len(), val.len() - 1 - i);
}
}

#[test]
fn arrayaccess_make_ref(val in any::<u8>()) {
prop_assert_eq!(<BitDecomposed<u8> as ArrayAccessRef>::make_ref(&val), &val);
}
}

#[test]
fn arraybuild() {
let mut b = BitDecomposed::<u8>::builder();
b.push(1);
b.push(2);
b.push(3);
assert_eq!(
b.build(),
BitDecomposed {
bits: vec![1, 2, 3]
}
);
}

proptest! {
#[test]
fn arraybuild_with_capacity(capacity in 0..MAX_TEST_SIZE) {
let b = BitDecomposed::<u8>::builder().with_capacity(capacity);
prop_assert!(b.bits.capacity() >= capacity);
}
}
}
1 change: 1 addition & 0 deletions ipa-core/src/secret_sharing/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -253,6 +253,7 @@ pub trait SharedValueArray<V>:
pub trait FieldArray<F: SharedValue>:
SharedValueArray<F>
+ FromRandom
+ for<'a> Mul<F, Output = Self>
+ for<'a> Mul<&'a F, Output = Self>
+ for<'a> Mul<&'a Self, Output = Self>
{
Expand Down

0 comments on commit ed3d9ec

Please sign in to comment.