diff --git a/src/field.rs b/src/field.rs index 9573f6fd..041c9a7e 100644 --- a/src/field.rs +++ b/src/field.rs @@ -867,9 +867,7 @@ pub(crate) fn merge_vector( if accumulator.len() != other_vector.len() { return Err(FieldError::InputSizeMismatch); } - for (a, o) in accumulator.iter_mut().zip(other_vector.iter()) { - *a += *o; - } + add_assign_vector(accumulator, other_vector.iter().copied()); Ok(()) } @@ -886,15 +884,36 @@ pub(crate) fn split_vector(inp: &[F], num_shares: usize) -> Vec for _ in 1..num_shares { let share: Vec = random_vector(inp.len()); - for (x, y) in outp[0].iter_mut().zip(&share) { - *x -= *y; - } + sub_assign_vector(&mut outp[0], share.iter().copied()); outp.push(share); } outp } +pub(crate) fn sub_assign_vector(a: &mut [F], b: impl IntoIterator) { + let mut count = 0; + for (x, y) in a.iter_mut().zip(b) { + *x -= y; + count += 1; + } + assert_eq!(a.len(), count); +} + +pub(crate) fn add_assign_vector(a: &mut [F], b: impl IntoIterator) { + let mut count = 0; + for (x, y) in a.iter_mut().zip(b) { + *x += y; + count += 1; + } + assert_eq!(a.len(), count); +} + +pub(crate) fn add_vector(mut a: Vec, b: Vec) -> Vec { + add_assign_vector(&mut a, b.iter().copied()); + a +} + /// Generate a vector of uniformly distributed random field elements. pub fn random_vector(len: usize) -> Vec { Prng::new().take(len).collect() diff --git a/src/flp.rs b/src/flp.rs index dabd41ab..d9a50e8e 100644 --- a/src/flp.rs +++ b/src/flp.rs @@ -800,7 +800,9 @@ pub(crate) fn gadget_poly_len(gadget_degree: usize, wire_poly_len: usize) -> usi #[cfg_attr(docsrs, doc(cfg(feature = "test-util")))] pub mod test_utils { use super::*; - use crate::field::{random_vector, FieldElement, FieldElementWithInteger}; + use crate::field::{ + add_vector, random_vector, sub_assign_vector, FieldElement, FieldElementWithInteger, + }; /// Various tests for an FLP. #[cfg_attr(docsrs, doc(cfg(feature = "test-util")))] @@ -945,12 +947,7 @@ pub mod test_utils { ) .unwrap() }) - .reduce(|mut left, right| { - for (x, y) in left.iter_mut().zip(right.iter()) { - *x += *y; - } - left - }) + .reduce(add_vector) .unwrap(); let res = self.flp.decide(&verifier).unwrap(); @@ -1000,9 +997,7 @@ pub mod test_utils { for _ in 1..SHARES { let share: Vec = random_vector(inp.len()); - for (x, y) in outp[0].iter_mut().zip(&share) { - *x -= *y; - } + sub_assign_vector(&mut outp[0], share.iter().copied()); outp.push(share); } @@ -1013,7 +1008,7 @@ pub mod test_utils { #[cfg(test)] mod tests { use super::*; - use crate::field::{random_vector, split_vector, Field128}; + use crate::field::{add_vector, random_vector, split_vector, Field128}; use crate::flp::gadgets::{Mul, PolyEval}; use crate::polynomial::poly_range_check; @@ -1054,12 +1049,7 @@ mod tests { ) .unwrap() }) - .reduce(|mut left, right| { - for (x, y) in left.iter_mut().zip(right.iter()) { - *x += *y; - } - left - }) + .reduce(add_vector) .unwrap(); assert_eq!(verifier.len(), typ.verifier_len()); diff --git a/src/flp/gadgets.rs b/src/flp/gadgets.rs index 3783c7e6..bce438d7 100644 --- a/src/flp/gadgets.rs +++ b/src/flp/gadgets.rs @@ -3,7 +3,7 @@ //! A collection of gadgets. use crate::fft::{discrete_fourier_transform, discrete_fourier_transform_inv_finish}; -use crate::field::FftFriendlyFieldElement; +use crate::field::{add_vector, FftFriendlyFieldElement}; use crate::flp::{gadget_poly_len, wire_poly_len, FlpError, Gadget}; use crate::polynomial::{poly_deg, poly_eval, poly_mul}; @@ -380,15 +380,7 @@ where }, ) .map(|state| state.partial_sum) - .reduce( - || vec![F::zero(); outp.len()], - |mut x, y| { - for (xi, yi) in x.iter_mut().zip(y.iter()) { - *xi += *yi; - } - x - }, - ); + .reduce(|| vec![F::zero(); outp.len()], add_vector); outp.copy_from_slice(&res[..]); Ok(()) diff --git a/src/vdaf/mastic/szk.rs b/src/vdaf/mastic/szk.rs index 03613b48..470130ad 100644 --- a/src/vdaf/mastic/szk.rs +++ b/src/vdaf/mastic/szk.rs @@ -13,7 +13,7 @@ use crate::{ codec::{CodecError, Decode, Encode, ParameterizedDecode}, - field::{decode_fieldvec, encode_fieldvec, FieldElement}, + field::{add_assign_vector, decode_fieldvec, encode_fieldvec, sub_assign_vector, FieldElement}, flp::{FlpError, Type}, vdaf::{ mastic::{self, NONCE_SIZE, SEED_SIZE, USAGE_PROOF_SHARE}, @@ -453,12 +453,10 @@ impl Szk { .prove(encoded_measurement, &prove_rand, &joint_rand)?; // Generate the proof shares. - for (x, y) in leader_proof_share - .iter_mut() - .zip(self.derive_helper_proof_share(&helper_seed, ctx)) - { - *x -= y; - } + sub_assign_vector( + &mut leader_proof_share, + self.derive_helper_proof_share(&helper_seed, ctx), + ); // Construct the output messages. let leader_proof_share = SzkProofShare::Leader { @@ -575,13 +573,10 @@ impl Szk { mut leader_share: SzkQueryShare, helper_share: SzkQueryShare, ) -> Result { - for (x, y) in leader_share - .flp_verifier - .iter_mut() - .zip(helper_share.flp_verifier) - { - *x += y; - } + add_assign_vector( + &mut leader_share.flp_verifier, + helper_share.flp_verifier.iter().copied(), + ); if self.typ.decide(&leader_share.flp_verifier)? { match ( leader_share.joint_rand_part_opt, @@ -662,11 +657,12 @@ where mod tests { use super::*; use crate::{ - field::Field128, - field::{random_vector, FieldElementWithInteger}, - flp::gadgets::{Mul, ParallelSum}, - flp::types::{Count, Sum, SumVec}, - flp::Type, + field::{random_vector, sub_assign_vector, Field128, FieldElementWithInteger}, + flp::{ + gadgets::{Mul, ParallelSum}, + types::{Count, Sum, SumVec}, + Type, + }, }; use rand::{thread_rng, Rng}; @@ -683,9 +679,7 @@ mod tests { let leader_seed_opt = szk_typ.requires_joint_rand().then(|| rng.gen()); let helper_input_share: Vec = random_vector(szk_typ.typ.input_len()); let mut leader_input_share = encoded_measurement.to_owned(); - for (x, y) in leader_input_share.iter_mut().zip(&helper_input_share) { - *x -= *y; - } + sub_assign_vector(&mut leader_input_share, helper_input_share.iter().copied()); let proof_shares = szk_typ.prove( ctx, @@ -849,9 +843,7 @@ mod tests { let leader_seed_opt = Some(rng.gen()); let helper_input_share = random_vector(szk_typ.typ.input_len()); let mut leader_input_share = encoded_measurement.clone().to_owned(); - for (x, y) in leader_input_share.iter_mut().zip(&helper_input_share) { - *x -= *y; - } + sub_assign_vector(&mut leader_input_share, helper_input_share.iter().copied()); let [leader_proof_share, _] = szk_typ .prove( @@ -885,9 +877,7 @@ mod tests { let leader_seed_opt = Some(rng.gen()); let helper_input_share = random_vector(szk_typ.typ.input_len()); let mut leader_input_share = encoded_measurement.clone().to_owned(); - for (x, y) in leader_input_share.iter_mut().zip(&helper_input_share) { - *x -= *y; - } + sub_assign_vector(&mut leader_input_share, helper_input_share.iter().copied()); let [l_proof_share, _] = szk_typ .prove( @@ -920,9 +910,7 @@ mod tests { let leader_seed_opt = Some(rng.gen()); let helper_input_share = random_vector(szk_typ.typ.input_len()); let mut leader_input_share = encoded_measurement.clone().to_owned(); - for (x, y) in leader_input_share.iter_mut().zip(&helper_input_share) { - *x -= *y; - } + sub_assign_vector(&mut leader_input_share, helper_input_share.iter().copied()); let [l_proof_share, _] = szk_typ .prove( @@ -956,9 +944,7 @@ mod tests { let leader_seed_opt = None; let helper_input_share = random_vector(szk_typ.typ.input_len()); let mut leader_input_share = encoded_measurement.clone().to_owned(); - for (x, y) in leader_input_share.iter_mut().zip(&helper_input_share) { - *x -= *y; - } + sub_assign_vector(&mut leader_input_share, helper_input_share.iter().copied()); let [l_proof_share, _] = szk_typ .prove( @@ -998,9 +984,7 @@ mod tests { let leader_seed_opt = None; let helper_input_share = random_vector(szk_typ.typ.input_len()); let mut leader_input_share = encoded_measurement.clone().to_owned(); - for (x, y) in leader_input_share.iter_mut().zip(&helper_input_share) { - *x -= *y; - } + sub_assign_vector(&mut leader_input_share, helper_input_share.iter().copied()); let [_, h_proof_share] = szk_typ .prove( @@ -1039,9 +1023,7 @@ mod tests { let leader_seed_opt = None; let helper_input_share = random_vector(szk_typ.typ.input_len()); let mut leader_input_share = encoded_measurement.clone().to_owned(); - for (x, y) in leader_input_share.iter_mut().zip(&helper_input_share) { - *x -= *y; - } + sub_assign_vector(&mut leader_input_share, helper_input_share.iter().copied()); let [l_proof_share, _] = szk_typ .prove( @@ -1080,9 +1062,7 @@ mod tests { let leader_seed_opt = None; let helper_input_share = random_vector(szk_typ.typ.input_len()); let mut leader_input_share = encoded_measurement.clone().to_owned(); - for (x, y) in leader_input_share.iter_mut().zip(&helper_input_share) { - *x -= *y; - } + sub_assign_vector(&mut leader_input_share, helper_input_share.iter().copied()); let [_, h_proof_share] = szk_typ .prove( @@ -1122,9 +1102,7 @@ mod tests { let leader_seed_opt = Some(rng.gen()); let helper_input_share = random_vector(szk_typ.typ.input_len()); let mut leader_input_share = encoded_measurement.clone().to_owned(); - for (x, y) in leader_input_share.iter_mut().zip(&helper_input_share) { - *x -= *y; - } + sub_assign_vector(&mut leader_input_share, helper_input_share.iter().copied()); let [l_proof_share, _] = szk_typ .prove( @@ -1164,9 +1142,7 @@ mod tests { let leader_seed_opt = Some(rng.gen()); let helper_input_share = random_vector(szk_typ.typ.input_len()); let mut leader_input_share = encoded_measurement.clone().to_owned(); - for (x, y) in leader_input_share.iter_mut().zip(&helper_input_share) { - *x -= *y; - } + sub_assign_vector(&mut leader_input_share, helper_input_share.iter().copied()); let [_, h_proof_share] = szk_typ .prove( diff --git a/src/vdaf/prio3.rs b/src/vdaf/prio3.rs index 94edc192..20471c59 100644 --- a/src/vdaf/prio3.rs +++ b/src/vdaf/prio3.rs @@ -34,7 +34,8 @@ use crate::codec::{encode_fixlen_items, CodecError, Decode, Encode, Parameterize #[cfg(feature = "experimental")] use crate::dp::DifferentialPrivacyStrategy; use crate::field::{ - decode_fieldvec, FftFriendlyFieldElement, FieldElement, FieldElementWithInteger, + add_assign_vector, decode_fieldvec, sub_assign_vector, FftFriendlyFieldElement, FieldElement, + FieldElementWithInteger, }; use crate::field::{Field128, Field64}; #[cfg(feature = "multithreaded")] @@ -650,12 +651,7 @@ where Some(joint_rand_blind) } else { - for (x, y) in leader_measurement_share - .iter_mut() - .zip(measurement_share_prng) - { - *x -= y; - } + sub_assign_vector(&mut leader_measurement_share, measurement_share_prng); None }; shares_out.push(Prio3InputShare::Helper { @@ -737,13 +733,10 @@ where u8::try_from(j).unwrap() + 1, ); - for (x, y) in leader_proofs_share - .iter_mut() - .zip(prng) - .take(self.typ.proof_len() * self.num_proofs()) - { - *x -= y; - } + sub_assign_vector( + &mut leader_proofs_share, + prng.take(self.typ.proof_len() * self.num_proofs()), + ); } // Overwrite the placeholder first element with the leader share @@ -1506,9 +1499,7 @@ where joint_rand_parts.push(joint_rand_seed_part); } - for (x, y) in verifiers.iter_mut().zip(share.verifiers) { - *x += y; - } + add_assign_vector(&mut verifiers, share.verifiers.iter().copied()); } if count != self.num_aggregators {