diff --git a/src/flp/szk.rs b/src/flp/szk.rs index d353906f..58bf5386 100644 --- a/src/flp/szk.rs +++ b/src/flp/szk.rs @@ -15,15 +15,15 @@ use crate::{ codec::{CodecError, Decode, Encode, ParameterizedDecode}, field::{decode_fieldvec, encode_fieldvec, FieldElement}, flp::{FlpError, Type}, - prng::{Prng, PrngError}, + prng::PrngError, vdaf::{ mastic::{self, USAGE_PROOF_SHARE}, xof::{IntoFieldVec, Seed, Xof, XofTurboShake128}, }, }; use std::borrow::Cow; +use std::io::Cursor; use std::ops::BitAnd; -use std::{io::Cursor, marker::PhantomData}; use subtle::{Choice, ConstantTimeEq}; // Domain separation tags @@ -56,33 +56,33 @@ pub enum SzkError { /// Contains an FLP proof share, and if joint randomness is needed, the blind /// used to derive it and the other party's joint randomness part. #[derive(Debug, Clone)] -pub enum SzkProofShare { +pub enum SzkProofShare { /// Leader's proof share is uncompressed. Leader { /// Share of an FLP proof, as a vector of Field elements. uncompressed_proof_share: Vec, /// Set only if joint randomness is needed. The first Seed is a blind, second /// is the helper's joint randomness part. - leader_blind_and_helper_joint_rand_part_opt: Option<(Seed, Seed)>, + leader_blind_and_helper_joint_rand_part_opt: Option<(Seed<32>, Seed<32>)>, }, /// The Helper uses one seed for both its compressed proof share and as the blind for its joint /// randomness. Helper { /// The Seed that acts both as the compressed proof share and, optionally, as the blind. - proof_share_seed_and_blind: Seed, + proof_share_seed_and_blind: Seed<32>, /// The leader's joint randomness part, if needed. - leader_joint_rand_part_opt: Option>, + leader_joint_rand_part_opt: Option>, }, } -impl PartialEq for SzkProofShare { - fn eq(&self, other: &SzkProofShare) -> bool { +impl PartialEq for SzkProofShare { + fn eq(&self, other: &SzkProofShare) -> bool { bool::from(self.ct_eq(other)) } } -impl ConstantTimeEq for SzkProofShare { - fn ct_eq(&self, other: &SzkProofShare) -> Choice { +impl ConstantTimeEq for SzkProofShare { + fn ct_eq(&self, other: &SzkProofShare) -> Choice { match (self, other) { ( SzkProofShare::Leader { @@ -111,7 +111,7 @@ impl ConstantTimeEq for SzkProofShare Encode for SzkProofShare { +impl Encode for SzkProofShare { fn encode(&self, bytes: &mut Vec) -> Result<(), CodecError> { match self { SzkProofShare::Leader { @@ -169,9 +169,7 @@ impl Encode for SzkProofShare ParameterizedDecode<(bool, usize, bool)> - for SzkProofShare -{ +impl ParameterizedDecode<(bool, usize, bool)> for SzkProofShare { fn decode_with_param( (is_leader, proof_len, requires_joint_rand): &(bool, usize, bool), bytes: &mut Cursor<&[u8]>, @@ -180,19 +178,16 @@ impl ParameterizedDecode<(bool Ok(SzkProofShare::Leader { uncompressed_proof_share: decode_fieldvec::(*proof_len, bytes)?, leader_blind_and_helper_joint_rand_part_opt: if *requires_joint_rand { - Some(( - Seed::::decode(bytes)?, - Seed::::decode(bytes)?, - )) + Some((Seed::decode(bytes)?, Seed::decode(bytes)?)) } else { None }, }) } else { Ok(SzkProofShare::Helper { - proof_share_seed_and_blind: Seed::::decode(bytes)?, + proof_share_seed_and_blind: Seed::decode(bytes)?, leader_joint_rand_part_opt: if *requires_joint_rand { - Some(Seed::::decode(bytes)?) + Some(Seed::decode(bytes)?) } else { None }, @@ -203,12 +198,12 @@ impl ParameterizedDecode<(bool /// A tuple containing the state and messages produced by an SZK query. #[derive(Clone, Debug, PartialEq)] -pub struct SzkQueryShare { - joint_rand_part_opt: Option>, +pub struct SzkQueryShare { + joint_rand_part_opt: Option>, pub(crate) flp_verifier: Vec, } -impl Encode for SzkQueryShare { +impl Encode for SzkQueryShare { fn encode(&self, bytes: &mut Vec) -> Result<(), CodecError> { if let Some(ref part) = self.joint_rand_part_opt { part.encode(bytes)?; @@ -229,16 +224,14 @@ impl Encode for SzkQueryShare ParameterizedDecode<(bool, usize)> - for SzkQueryShare -{ +impl ParameterizedDecode<(bool, usize)> for SzkQueryShare { fn decode_with_param( (requires_joint_rand, verifier_len): &(bool, usize), bytes: &mut Cursor<&[u8]>, ) -> Result { Ok(SzkQueryShare { joint_rand_part_opt: (*requires_joint_rand) - .then(|| Seed::::decode(bytes)) + .then(|| Seed::decode(bytes)) .transpose()?, flp_verifier: decode_fieldvec(*verifier_len, bytes)?, }) @@ -248,22 +241,16 @@ impl ParameterizedDecode<(bool /// Szk query state. /// /// The state that needs to be stored by an Szk verifier between query() and decide(). -pub(crate) type SzkQueryState = Option>; +pub(crate) type SzkQueryState = Option>; /// Joint share type for the SZK proof. /// /// This is produced as the result of combining two query shares. /// It contains the re-computed joint randomness seed, if applicable. It is consumed by [`Szk::decide`]. -#[derive(Clone, Debug, Eq, PartialEq)] -pub struct SzkJointShare(Option>); +#[derive(Clone, Debug, Default, Eq, PartialEq)] +pub struct SzkJointShare(Option>); -impl SzkJointShare { - pub(crate) fn none() -> SzkJointShare { - SzkJointShare(None) - } -} - -impl Encode for SzkJointShare { +impl Encode for SzkJointShare { fn encode(&self, bytes: &mut Vec) -> Result<(), CodecError> { if let Some(ref expected_seed) = self.0 { expected_seed.encode(bytes)?; @@ -279,13 +266,13 @@ impl Encode for SzkJointShare { } } -impl ParameterizedDecode for SzkJointShare { +impl ParameterizedDecode for SzkJointShare { fn decode_with_param( requires_joint_rand: &bool, bytes: &mut Cursor<&[u8]>, ) -> Result { if *requires_joint_rand { - Ok(SzkJointShare(Some(Seed::::decode(bytes)?))) + Ok(SzkJointShare(Some(Seed::decode(bytes)?))) } else { Ok(SzkJointShare(None)) } @@ -296,43 +283,26 @@ impl ParameterizedDecode for SzkJointShare -where - T: Type, - P: Xof, -{ +pub struct Szk { /// The Type representing the specific FLP system used to prove validity of an input. pub(crate) typ: T, id: [u8; 4], - phantom: PhantomData

, -} - -impl Szk { - /// Create an instance of [`Szk`] using [`XofTurboShake128`]. - pub fn new_turboshake128(typ: T, algorithm_id: u32) -> Self { - Self::new(typ, algorithm_id) - } } -impl Szk -where - T: Type, - P: Xof, -{ +impl Szk { /// Construct an instance of this sharedZK proof system with the underlying /// FLP. pub fn new(typ: T, algorithm_id: u32) -> Self { Self { typ, id: algorithm_id.to_le_bytes(), - phantom: PhantomData, } } /// Derive a vector of random field elements for consumption by the FLP /// prover. - fn derive_prove_rand(&self, prove_rand_seed: &Seed, ctx: &[u8]) -> Vec { - P::seed_stream( + fn derive_prove_rand(&self, prove_rand_seed: &Seed<32>, ctx: &[u8]) -> Vec { + XofTurboShake128::seed_stream( prove_rand_seed, &[&mastic::dst_usage(mastic::USAGE_PROVE_RAND), &self.id, ctx], &[], @@ -342,12 +312,12 @@ where fn derive_joint_rand_part( &self, - aggregator_blind: &Seed, + aggregator_blind: &Seed<32>, measurement_share: &[T::Field], nonce: &[u8; 16], ctx: &[u8], - ) -> Result, SzkError> { - let mut xof = P::init( + ) -> Result, SzkError> { + let mut xof = XofTurboShake128::init( aggregator_blind.as_ref(), &[ &mastic::dst_usage(mastic::USAGE_JOINT_RAND_PART), @@ -369,12 +339,12 @@ where fn derive_joint_rand_seed( &self, - leader_joint_rand_part: &Seed, - helper_joint_rand_part: &Seed, + leader_joint_rand_part: &Seed<32>, + helper_joint_rand_part: &Seed<32>, ctx: &[u8], - ) -> Seed { - let mut xof = P::init( - &[0; SEED_SIZE], + ) -> Seed<32> { + let mut xof = XofTurboShake128::init( + &[0; 32], &[ &mastic::dst_usage(mastic::USAGE_JOINT_RAND_SEED), &self.id, @@ -388,13 +358,13 @@ where fn derive_joint_rand_and_seed( &self, - leader_joint_rand_part: &Seed, - helper_joint_rand_part: &Seed, + leader_joint_rand_part: &Seed<32>, + helper_joint_rand_part: &Seed<32>, ctx: &[u8], - ) -> (Seed, Vec) { + ) -> (Seed<32>, Vec) { let joint_rand_seed = self.derive_joint_rand_seed(leader_joint_rand_part, helper_joint_rand_part, ctx); - let joint_rand = P::seed_stream( + let joint_rand = XofTurboShake128::seed_stream( &joint_rand_seed, &[&mastic::dst_usage(mastic::USAGE_JOINT_RAND), &self.id, ctx], &[], @@ -404,28 +374,23 @@ where (joint_rand_seed, joint_rand) } - fn derive_helper_proof_share( - &self, - proof_share_seed: &Seed, - ctx: &[u8], - ) -> Vec { - Prng::from_seed_stream(P::seed_stream( + fn derive_helper_proof_share(&self, proof_share_seed: &Seed<32>, ctx: &[u8]) -> Vec { + XofTurboShake128::seed_stream( proof_share_seed, &[&mastic::dst_usage(USAGE_PROOF_SHARE), &self.id, ctx], &[], - )) - .take(self.typ.proof_len()) - .collect() + ) + .into_field_vec(self.typ.proof_len()) } fn derive_query_rand( &self, - verify_key: &[u8; SEED_SIZE], + verify_key: &[u8; 32], nonce: &[u8; 16], level: u16, ctx: &[u8], ) -> Vec { - let mut xof = P::init( + let mut xof = XofTurboShake128::init( verify_key, &[&mastic::dst_usage(mastic::USAGE_QUERY_RAND), &self.id, ctx], ); @@ -454,10 +419,10 @@ where leader_input_share: &[T::Field], helper_input_share: &[T::Field], encoded_measurement: &[T::Field], - rand_seeds: [Seed; 2], - leader_seed_opt: Option>, + rand_seeds: [Seed<32>; 2], + leader_seed_opt: Option>, nonce: &[u8; 16], - ) -> Result<[SzkProofShare; 2], SzkError> { + ) -> Result<[SzkProofShare; 2], SzkError> { let [prove_rand_seed, helper_seed] = rand_seeds; // If joint randomness is used, derive it from the two input shares, // the seeds used to blind the derivation, and the nonce. Pass the @@ -514,10 +479,10 @@ where ctx: &[u8], level: u16, // level of the prefix tree input_share: &[T::Field], - proof_share: &SzkProofShare, - verify_key: &[u8; SEED_SIZE], + proof_share: &SzkProofShare, + verify_key: &[u8; 32], nonce: &[u8; 16], - ) -> Result<(SzkQueryShare, SzkQueryState), SzkError> { + ) -> Result<(SzkQueryShare, SzkQueryState), SzkError> { let query_rand = self.derive_query_rand(verify_key, nonce, level, ctx); let flp_proof_share = match proof_share { SzkProofShare::Leader { @@ -609,9 +574,9 @@ where pub(crate) fn merge_query_shares( &self, ctx: &[u8], - mut leader_share: SzkQueryShare, - helper_share: SzkQueryShare, - ) -> Result, SzkError> { + mut leader_share: SzkQueryShare, + helper_share: SzkQueryShare, + ) -> Result { for (x, y) in leader_share .flp_verifier .iter_mut() @@ -641,8 +606,8 @@ where /// was correctly computed from both aggregators' parts. pub fn decide( &self, - query_state: SzkQueryState, - joint_share: SzkJointShare, + query_state: SzkQueryState, + joint_share: SzkJointShare, ) -> Result<(), SzkError> { // Check that joint randomness was properly derived from both // aggregators' parts @@ -711,7 +676,7 @@ mod tests { let ctx = b"some application context"; let mut nonce = [0u8; 16]; let mut verify_key = [0u8; 32]; - let szk_typ = Szk::new_turboshake128(typ.clone(), 0); + let szk_typ = Szk::new(typ.clone(), 0); thread_rng().fill(&mut verify_key[..]); thread_rng().fill(&mut nonce[..]); let prove_rand_seed = Seed::generate().unwrap(); @@ -880,7 +845,7 @@ mod tests { thread_rng().fill(&mut nonce[..]); let sum = Sum::::new(max_measurement).unwrap(); let encoded_measurement = sum.encode_measurement(&9).unwrap(); - let szk_typ = Szk::new_turboshake128(sum, 0); + let szk_typ = Szk::new(sum, 0); let prove_rand_seed = Seed::generate().unwrap(); let helper_seed = Seed::generate().unwrap(); let leader_seed_opt = Some(Seed::generate().unwrap()); @@ -915,7 +880,7 @@ mod tests { let sumvec = SumVec::>>::new(5, 3, 3).unwrap(); let encoded_measurement = sumvec.encode_measurement(&vec![1, 16, 0]).unwrap(); - let szk_typ = Szk::new_turboshake128(sumvec, 0); + let szk_typ = Szk::new(sumvec, 0); let prove_rand_seed = Seed::generate().unwrap(); let helper_seed = Seed::generate().unwrap(); let leader_seed_opt = Some(Seed::generate().unwrap()); @@ -949,7 +914,7 @@ mod tests { thread_rng().fill(&mut nonce[..]); let count = Count::::new(); let encoded_measurement = count.encode_measurement(&true).unwrap(); - let szk_typ = Szk::new_turboshake128(count, 0); + let szk_typ = Szk::new(count, 0); let prove_rand_seed = Seed::generate().unwrap(); let helper_seed = Seed::generate().unwrap(); let leader_seed_opt = Some(Seed::generate().unwrap()); @@ -984,7 +949,7 @@ mod tests { thread_rng().fill(&mut nonce[..]); let sum = Sum::::new(max_measurement).unwrap(); let encoded_measurement = sum.encode_measurement(&9).unwrap(); - let szk_typ = Szk::new_turboshake128(sum, 0); + let szk_typ = Szk::new(sum, 0); let prove_rand_seed = Seed::generate().unwrap(); let helper_seed = Seed::generate().unwrap(); let leader_seed_opt = None; @@ -1025,7 +990,7 @@ mod tests { thread_rng().fill(&mut nonce[..]); let sum = Sum::::new(max_measurement).unwrap(); let encoded_measurement = sum.encode_measurement(&9).unwrap(); - let szk_typ = Szk::new_turboshake128(sum, 0); + let szk_typ = Szk::new(sum, 0); let prove_rand_seed = Seed::generate().unwrap(); let helper_seed = Seed::generate().unwrap(); let leader_seed_opt = None; @@ -1065,7 +1030,7 @@ mod tests { thread_rng().fill(&mut nonce[..]); let count = Count::::new(); let encoded_measurement = count.encode_measurement(&true).unwrap(); - let szk_typ = Szk::new_turboshake128(count, 0); + let szk_typ = Szk::new(count, 0); let prove_rand_seed = Seed::generate().unwrap(); let helper_seed = Seed::generate().unwrap(); let leader_seed_opt = None; @@ -1105,7 +1070,7 @@ mod tests { thread_rng().fill(&mut nonce[..]); let count = Count::::new(); let encoded_measurement = count.encode_measurement(&true).unwrap(); - let szk_typ = Szk::new_turboshake128(count, 0); + let szk_typ = Szk::new(count, 0); let prove_rand_seed = Seed::generate().unwrap(); let helper_seed = Seed::generate().unwrap(); let leader_seed_opt = None; @@ -1146,7 +1111,7 @@ mod tests { let sumvec = SumVec::>>::new(5, 3, 3).unwrap(); let encoded_measurement = sumvec.encode_measurement(&vec![1, 16, 0]).unwrap(); - let szk_typ = Szk::new_turboshake128(sumvec, 0); + let szk_typ = Szk::new(sumvec, 0); let prove_rand_seed = Seed::generate().unwrap(); let helper_seed = Seed::generate().unwrap(); let leader_seed_opt = Some(Seed::generate().unwrap()); @@ -1187,7 +1152,7 @@ mod tests { let sumvec = SumVec::>>::new(5, 3, 3).unwrap(); let encoded_measurement = sumvec.encode_measurement(&vec![1, 16, 0]).unwrap(); - let szk_typ = Szk::new_turboshake128(sumvec, 0); + let szk_typ = Szk::new(sumvec, 0); let prove_rand_seed = Seed::generate().unwrap(); let helper_seed = Seed::generate().unwrap(); let leader_seed_opt = Some(Seed::generate().unwrap()); diff --git a/src/vdaf/mastic.rs b/src/vdaf/mastic.rs index 5ca414ba..9bc95588 100644 --- a/src/vdaf/mastic.rs +++ b/src/vdaf/mastic.rs @@ -20,11 +20,11 @@ use crate::{ }, vidpf::{ xor_proof, Vidpf, VidpfError, VidpfInput, VidpfKey, VidpfProof, VidpfPublicShare, - VidpfServerId, VidpfWeight, + VidpfServerId, VidpfWeight, VIDPF_PROOF_SIZE, }, }; -use rand::RngCore; +use rand::prelude::*; use std::io::{Cursor, Read}; use std::ops::BitAnd; use std::slice::from_ref; @@ -67,23 +67,15 @@ pub(crate) fn dst_usage(usage: u8) -> [u8; 8] { /// Composed of a shared zero knowledge proof system and a verifiable incremental /// distributed point function. #[derive(Clone, Debug)] -pub struct Mastic -where - T: Type, - P: Xof, -{ +pub struct Mastic { id: [u8; 4], - pub(crate) szk: Szk, + pub(crate) szk: Szk, pub(crate) vidpf: Vidpf>, /// The length of the private attribute associated with any input. pub(crate) bits: usize, } -impl Mastic -where - T: Type, - P: Xof, -{ +impl Mastic { /// Creates a new instance of Mastic, with a specific attribute length and weight type. pub fn new(algorithm_id: u32, typ: T, bits: usize) -> Result { let vidpf = Vidpf::new(bits, typ.input_len() + 1)?; @@ -154,14 +146,9 @@ impl Decode for MasticAggregationParam { /// Contains broadcast information shared between parties to support VIDPF correctness. pub type MasticPublicShare = VidpfPublicShare; -impl ParameterizedDecode> - for MasticPublicShare> -where - T: Type, - P: Xof, -{ +impl ParameterizedDecode> for MasticPublicShare> { fn decode_with_param( - mastic: &Mastic, + mastic: &Mastic, bytes: &mut Cursor<&[u8]>, ) -> Result { VidpfPublicShare::decode_with_param(&(mastic.bits, mastic.vidpf.weight_parameter), bytes) @@ -172,15 +159,15 @@ where /// /// Message sent by the [`Client`] to each Aggregator during the Sharding phase. #[derive(Clone, Debug)] -pub struct MasticInputShare { +pub struct MasticInputShare { /// VIDPF key share. vidpf_key: VidpfKey, /// The proof share. - proof_share: SzkProofShare, + proof_share: SzkProofShare, } -impl Encode for MasticInputShare { +impl Encode for MasticInputShare { fn encode(&self, bytes: &mut Vec) -> Result<(), CodecError> { bytes.extend_from_slice(&self.vidpf_key.0[..]); self.proof_share.encode(bytes)?; @@ -192,14 +179,9 @@ impl Encode for MasticInputShare ParameterizedDecode<(&'a Mastic, usize)> - for MasticInputShare -where - T: Type, - P: Xof, -{ +impl<'a, T: Type> ParameterizedDecode<(&'a Mastic, usize)> for MasticInputShare { fn decode_with_param( - (mastic, agg_id): &(&'a Mastic, usize), + (mastic, agg_id): &(&'a Mastic, usize), bytes: &mut Cursor<&[u8]>, ) -> Result { if *agg_id > 1 { @@ -208,7 +190,7 @@ where let mut value = [0; 16]; bytes.read_exact(&mut value)?; let vidpf_key = VidpfKey::from_bytes(value); - let proof_share = SzkProofShare::::decode_with_param( + let proof_share = SzkProofShare::decode_with_param( &( *agg_id == 0, mastic.szk.typ.proof_len(), @@ -223,14 +205,14 @@ where } } -impl PartialEq for MasticInputShare { - fn eq(&self, other: &MasticInputShare) -> bool { +impl PartialEq for MasticInputShare { + fn eq(&self, other: &MasticInputShare) -> bool { self.ct_eq(other).into() } } -impl ConstantTimeEq for MasticInputShare { - fn ct_eq(&self, other: &MasticInputShare) -> Choice { +impl ConstantTimeEq for MasticInputShare { + fn ct_eq(&self, other: &MasticInputShare) -> Choice { self.vidpf_key .ct_eq(&other.vidpf_key) .bitand(self.proof_share.ct_eq(&other.proof_share)) @@ -247,46 +229,34 @@ pub type MasticOutputShare = OutputShare; /// Contains a flattened vector of VIDPF outputs to be aggregated by Mastic aggregators pub type MasticAggregateShare = AggregateShare; -impl<'a, T, P, const SEED_SIZE: usize> - ParameterizedDecode<(&'a Mastic, &'a MasticAggregationParam)> +impl<'a, T: Type> ParameterizedDecode<(&'a Mastic, &'a MasticAggregationParam)> for MasticAggregateShare -where - T: Type, - P: Xof, { fn decode_with_param( - (mastic, agg_param): &(&Mastic, &MasticAggregationParam), + (mastic, agg_param): &(&Mastic, &MasticAggregationParam), bytes: &mut Cursor<&[u8]>, ) -> Result { decode_fieldvec(mastic.agg_share_len(agg_param), bytes).map(AggregateShare) } } -impl<'a, T, P, const SEED_SIZE: usize> - ParameterizedDecode<(&'a Mastic, &'a MasticAggregationParam)> +impl<'a, T: Type> ParameterizedDecode<(&'a Mastic, &'a MasticAggregationParam)> for MasticOutputShare -where - T: Type, - P: Xof, { fn decode_with_param( - (mastic, agg_param): &(&Mastic, &MasticAggregationParam), + (mastic, agg_param): &(&Mastic, &MasticAggregationParam), bytes: &mut Cursor<&[u8]>, ) -> Result { decode_fieldvec(mastic.agg_share_len(agg_param), bytes).map(OutputShare) } } -impl Vdaf for Mastic -where - T: Type, - P: Xof, -{ +impl Vdaf for Mastic { type Measurement = (VidpfInput, T::Measurement); type AggregateResult = Vec; type AggregationParam = MasticAggregationParam; type PublicShare = MasticPublicShare>; - type InputShare = MasticInputShare; + type InputShare = MasticInputShare; type OutputShare = MasticOutputShare; type AggregateShare = MasticAggregateShare; @@ -298,19 +268,15 @@ where 2 } } -impl Mastic -where - T: Type, - P: Xof, -{ +impl Mastic { fn shard_with_random( &self, ctx: &[u8], (alpha, weight): &(VidpfInput, T::Measurement), nonce: &[u8; 16], vidpf_keys: [VidpfKey; 2], - szk_random: [Seed; 2], - joint_random_opt: Option>, + szk_random: [Seed<32>; 2], + joint_random_opt: Option>, ) -> Result<(::PublicShare, Vec<::InputShare>), VdafError> { if alpha.len() != self.bits { return Err(VdafError::Vidpf(VidpfError::InvalidInputLength)); @@ -351,11 +317,11 @@ where nonce, )?; let [leader_vidpf_key, helper_vidpf_key] = vidpf_keys; - let leader_share = MasticInputShare:: { + let leader_share = MasticInputShare { vidpf_key: leader_vidpf_key, proof_share: leader_szk_proof_share, }; - let helper_share = MasticInputShare:: { + let helper_share = MasticInputShare { vidpf_key: helper_vidpf_key, proof_share: helper_szk_proof_share, }; @@ -373,11 +339,7 @@ where } } -impl Client<16> for Mastic -where - T: Type, - P: Xof, -{ +impl Client<16> for Mastic { fn shard( &self, ctx: &[u8], @@ -386,7 +348,7 @@ where ) -> Result<(Self::PublicShare, Vec), VdafError> { let vidpf_keys = [VidpfKey::generate()?, VidpfKey::generate()?]; let joint_random_opt = if self.szk.requires_joint_rand() { - Some(Seed::::generate()?) + Some(Seed::generate()?) } else { None }; @@ -409,15 +371,15 @@ where /// state for [`Szk`] verification, the output shares currently being validated, and /// parameters of Mastic used for encoding. #[derive(Clone, Debug, Eq, PartialEq)] -pub struct MasticPrepareState { +pub struct MasticPrepareState { /// The counter and truncated weight for each candidate prefix. output_shares: MasticOutputShare, /// If [`Szk`]` verification is being performed, we also store the relevant state for that operation. - szk_query_state: SzkQueryState, + szk_query_state: SzkQueryState, verifier_len: Option, } -impl Encode for MasticPrepareState { +impl Encode for MasticPrepareState { fn encode(&self, bytes: &mut Vec) -> Result<(), CodecError> { self.output_shares.encode(bytes)?; if let Some(joint_rand_seed) = &self.szk_query_state { @@ -429,17 +391,16 @@ impl Encode for MasticPrepareState Option { Some( self.output_shares.as_ref().len() * F::ENCODED_SIZE - + self.szk_query_state.as_ref().map_or(0, |_| SEED_SIZE), + + self.szk_query_state.as_ref().map_or(0, |_| 32), ) } } -impl<'a, T: Type, P: Xof, const SEED_SIZE: usize> - ParameterizedDecode<(&'a Mastic, &'a MasticAggregationParam)> - for MasticPrepareState +impl<'a, T: Type> ParameterizedDecode<(&'a Mastic, &'a MasticAggregationParam)> + for MasticPrepareState { fn decode_with_param( - decoder @ (mastic, agg_param): &(&Mastic, &MasticAggregationParam), + decoder @ (mastic, agg_param): &(&Mastic, &MasticAggregationParam), bytes: &mut Cursor<&[u8]>, ) -> Result { let output_shares = MasticOutputShare::decode_with_param(decoder, bytes)?; @@ -465,17 +426,17 @@ impl<'a, T: Type, P: Xof, const SEED_SIZE: usize> /// [`Vidpf`] evaluation proof covering every prefix in the aggregation parameter, and optionally /// the verification message for Szk. #[derive(Clone, Debug, PartialEq)] -pub struct MasticPrepareShare { +pub struct MasticPrepareShare { /// [`Vidpf`] evaluation proof, which guarantees one-hotness and payload consistency. - eval_proof: Seed, + eval_proof: [u8; VIDPF_PROOF_SIZE], /// If [`Szk`]` verification of the root weight is needed, a verification message. - szk_query_share_opt: Option>, + szk_query_share_opt: Option>, } -impl Encode for MasticPrepareShare { +impl Encode for MasticPrepareShare { fn encode(&self, bytes: &mut Vec) -> Result<(), CodecError> { - self.eval_proof.encode(bytes)?; + bytes.extend_from_slice(&self.eval_proof); match &self.szk_query_share_opt { Some(query_share) => query_share.encode(bytes), None => Ok(()), @@ -484,7 +445,7 @@ impl Encode for MasticPrepareShare Option { Some( - self.eval_proof.encoded_len()? + VIDPF_PROOF_SIZE + match &self.szk_query_share_opt { Some(query_share) => query_share.encoded_len()?, None => 0, @@ -493,22 +454,18 @@ impl Encode for MasticPrepareShare ParameterizedDecode> - for MasticPrepareShare -{ +impl ParameterizedDecode> for MasticPrepareShare { fn decode_with_param( - prep_state: &MasticPrepareState, + prep_state: &MasticPrepareState, bytes: &mut Cursor<&[u8]>, ) -> Result { - let eval_proof = Seed::decode(bytes)?; + let mut eval_proof = [0; VIDPF_PROOF_SIZE]; + bytes.read_exact(&mut eval_proof[..])?; let requires_joint_rand = prep_state.szk_query_state.is_some(); let szk_query_share_opt = prep_state .verifier_len .map(|verifier_len| { - SzkQueryShare::::decode_with_param( - &(requires_joint_rand, verifier_len), - bytes, - ) + SzkQueryShare::decode_with_param(&(requires_joint_rand, verifier_len), bytes) }) .transpose()?; Ok(Self { @@ -522,30 +479,24 @@ impl ParameterizedDecode = SzkJointShare; +pub type MasticPrepareMessage = SzkJointShare; -impl ParameterizedDecode> - for MasticPrepareMessage -{ +impl ParameterizedDecode> for MasticPrepareMessage { fn decode_with_param( - prep_state: &MasticPrepareState, + prep_state: &MasticPrepareState, bytes: &mut Cursor<&[u8]>, ) -> Result { match prep_state.szk_query_state { - Some(_) => SzkJointShare::::decode_with_param(&true, bytes), - None => SzkJointShare::::decode_with_param(&false, bytes), + Some(_) => SzkJointShare::decode_with_param(&true, bytes), + None => SzkJointShare::decode_with_param(&false, bytes), } } } -impl Aggregator for Mastic -where - T: Type, - P: Xof, -{ - type PrepareState = MasticPrepareState; - type PrepareShare = MasticPrepareShare; - type PrepareMessage = MasticPrepareMessage; +impl Aggregator<32, NONCE_SIZE> for Mastic { + type PrepareState = MasticPrepareState; + type PrepareShare = MasticPrepareShare; + type PrepareMessage = MasticPrepareMessage; fn is_agg_param_valid(cur: &MasticAggregationParam, prev: &[MasticAggregationParam]) -> bool { // First agg param should be the only one that requires weight check. @@ -559,25 +510,22 @@ where // Unpack this agg param and the last one in the list let cur_poplar_agg_param = &cur.level_and_prefixes; let prev_poplar_agg_param = from_ref(&prev.last().as_ref().unwrap().level_and_prefixes); - Poplar1::::is_agg_param_valid(cur_poplar_agg_param, prev_poplar_agg_param) + Poplar1::::is_agg_param_valid( + cur_poplar_agg_param, + prev_poplar_agg_param, + ) } fn prepare_init( &self, - verify_key: &[u8; SEED_SIZE], + verify_key: &[u8; 32], ctx: &[u8], agg_id: usize, agg_param: &MasticAggregationParam, nonce: &[u8; NONCE_SIZE], public_share: &MasticPublicShare>, - input_share: &MasticInputShare, - ) -> Result< - ( - MasticPrepareState, - MasticPrepareShare, - ), - VdafError, - > { + input_share: &MasticInputShare, + ) -> Result<(MasticPrepareState, MasticPrepareShare), VdafError> { let id = match agg_id { 0 => Ok(VidpfServerId::S0), 1 => Ok(VidpfServerId::S1), @@ -602,10 +550,8 @@ where // Onehot and payload checks let (payload_check, onehot_proof) = { - let mut payload_check_xof = P::init( - &[0; SEED_SIZE], - &[&dst_usage(USAGE_PAYLOAD_CHECK), &self.id, ctx], - ); + let mut payload_check_xof = + XofTurboShake128::init(&[0; 32], &[&dst_usage(USAGE_PAYLOAD_CHECK), &self.id, ctx]); let mut payload_check_buf = Vec::with_capacity(T::Field::ENCODED_SIZE); let mut onehot_proof = ONEHOT_PROOF_INIT; @@ -658,14 +604,12 @@ where }; let eval_proof = { - let mut eval_proof_xof = P::init( - &[0; SEED_SIZE], - &[&dst_usage(USAGE_EVAL_PROOF), &self.id, ctx], - ); + let mut eval_proof_xof = + XofTurboShake128::init(&[0; 32], &[&dst_usage(USAGE_EVAL_PROOF), &self.id, ctx]); eval_proof_xof.update(&onehot_proof); eval_proof_xof.update(&counter_check); eval_proof_xof.update(&payload_check); - eval_proof_xof.into_seed() + eval_proof_xof.into_seed().0 }; let mut truncated_out_shares = @@ -721,14 +665,12 @@ where }) } - fn prepare_shares_to_prepare_message< - M: IntoIterator>, - >( + fn prepare_shares_to_prepare_message>>( &self, ctx: &[u8], _agg_param: &MasticAggregationParam, inputs: M, - ) -> Result, VdafError> { + ) -> Result { let mut inputs_iter = inputs.into_iter(); let leader_share = inputs_iter.next().ok_or(VdafError::Uncategorized( "No leader share received".to_string(), @@ -754,7 +696,7 @@ where (Some(leader_query_share), Some(helper_query_share)) => Ok(self .szk .merge_query_shares(ctx, leader_query_share, helper_query_share)?), - (None, None) => Ok(SzkJointShare::none()), + (None, None) => Ok(SzkJointShare::default()), (_, _) => Err(VdafError::Uncategorized( "Only one of leader and helper query shares is present".to_string(), )), @@ -764,9 +706,9 @@ where fn prepare_next( &self, _ctx: &[u8], - state: MasticPrepareState, - input: MasticPrepareMessage, - ) -> Result, VdafError> { + state: MasticPrepareState, + input: MasticPrepareMessage, + ) -> Result, VdafError> { let MasticPrepareState { output_shares, szk_query_state, @@ -801,11 +743,7 @@ where } } -impl Collector for Mastic -where - T: Type, - P: Xof, -{ +impl Collector for Mastic { fn unshard>( &self, agg_param: &MasticAggregationParam, @@ -854,7 +792,6 @@ mod tests { use crate::flp::gadgets::{Mul, ParallelSum}; use crate::flp::types::{Count, Histogram, Sum, SumVec}; use crate::vdaf::test_utils::run_vdaf; - use crate::vdaf::xof::XofTurboShake128; use rand::{thread_rng, Rng}; const CTX_STR: &[u8] = b"mastic ctx"; @@ -864,7 +801,7 @@ mod tests { let algorithm_id = 6; let max_measurement = 29; let sum_typ = Sum::::new(max_measurement).unwrap(); - let mastic = Mastic::<_, XofTurboShake128, 32>::new(algorithm_id, sum_typ, 32).unwrap(); + let mastic = Mastic::new(algorithm_id, sum_typ, 32).unwrap(); let mut nonce = [0u8; 16]; thread_rng().fill(&mut nonce[..]); @@ -943,7 +880,7 @@ mod tests { let algorithm_id = 6; let max_measurement = 29; let sum_typ = Sum::::new(max_measurement).unwrap(); - let mastic = Mastic::<_, XofTurboShake128, 32>::new(algorithm_id, sum_typ, 32).unwrap(); + let mastic = Mastic::new(algorithm_id, sum_typ, 32).unwrap(); let mut nonce = [0u8; 16]; thread_rng().fill(&mut nonce[..]); @@ -994,7 +931,7 @@ mod tests { let algorithm_id = 6; let max_measurement = 29; let sum_typ = Sum::::new(max_measurement).unwrap(); - let mastic = Mastic::<_, XofTurboShake128, 32>::new(algorithm_id, sum_typ, 32).unwrap(); + let mastic = Mastic::new(algorithm_id, sum_typ, 32).unwrap(); let mut nonce = [0u8; 16]; thread_rng().fill(&mut nonce[..]); @@ -1015,7 +952,7 @@ mod tests { fn test_mastic_count() { let algorithm_id = 6; let count = Count::::new(); - let mastic = Mastic::<_, XofTurboShake128, 32>::new(algorithm_id, count, 32).unwrap(); + let mastic = Mastic::new(algorithm_id, count, 32).unwrap(); let mut nonce = [0u8; 16]; thread_rng().fill(&mut nonce[..]); @@ -1092,7 +1029,7 @@ mod tests { fn test_public_share_encoded_len() { let algorithm_id = 6; let count = Count::::new(); - let mastic = Mastic::<_, XofTurboShake128, 32>::new(algorithm_id, count, 32).unwrap(); + let mastic = Mastic::new(algorithm_id, count, 32).unwrap(); let mut nonce = [0u8; 16]; thread_rng().fill(&mut nonce[..]); @@ -1110,7 +1047,7 @@ mod tests { fn test_public_share_roundtrip_count() { let algorithm_id = 6; let count = Count::::new(); - let mastic = Mastic::<_, XofTurboShake128, 32>::new(algorithm_id, count, 32).unwrap(); + let mastic = Mastic::new(algorithm_id, count, 32).unwrap(); let mut nonce = [0u8; 16]; thread_rng().fill(&mut nonce[..]); @@ -1130,7 +1067,7 @@ mod tests { let algorithm_id = 6; let sumvec = SumVec::>>::new(5, 3, 3).unwrap(); - let mastic = Mastic::<_, XofTurboShake128, 32>::new(algorithm_id, sumvec, 32).unwrap(); + let mastic = Mastic::new(algorithm_id, sumvec, 32).unwrap(); let mut nonce = [0u8; 16]; thread_rng().fill(&mut nonce[..]); @@ -1218,7 +1155,7 @@ mod tests { let sumvec = SumVec::>>::new(5, 3, 3).unwrap(); let measurement = vec![1, 16, 0]; - let mastic = Mastic::<_, XofTurboShake128, 32>::new(algorithm_id, sumvec, 32).unwrap(); + let mastic = Mastic::new(algorithm_id, sumvec, 32).unwrap(); let mut nonce = [0u8; 16]; thread_rng().fill(&mut nonce[..]); @@ -1247,7 +1184,7 @@ mod tests { let sumvec = SumVec::>>::new(5, 3, 3).unwrap(); let measurement = vec![1, 16, 0]; - let mastic = Mastic::<_, XofTurboShake128, 32>::new(algorithm_id, sumvec, 32).unwrap(); + let mastic = Mastic::new(algorithm_id, sumvec, 32).unwrap(); let mut nonce = [0u8; 16]; thread_rng().fill(&mut nonce[..]); @@ -1278,7 +1215,7 @@ mod tests { let sumvec = SumVec::>>::new(5, 3, 3).unwrap(); let measurement = vec![1, 16, 0]; - let mastic = Mastic::<_, XofTurboShake128, 32>::new(algorithm_id, sumvec, 32).unwrap(); + let mastic = Mastic::new(algorithm_id, sumvec, 32).unwrap(); let mut nonce = [0u8; 16]; thread_rng().fill(&mut nonce[..]); @@ -1301,7 +1238,7 @@ mod tests { let sumvec = SumVec::>>::new(5, 3, 3).unwrap(); let measurement = vec![1, 16, 0]; - let mastic = Mastic::<_, XofTurboShake128, 32>::new(algorithm_id, sumvec, 32).unwrap(); + let mastic = Mastic::new(algorithm_id, sumvec, 32).unwrap(); let mut nonce = [0u8; 16]; thread_rng().fill(&mut nonce[..]); @@ -1326,7 +1263,7 @@ mod tests { weight: T::Measurement, require_weight_check: bool, ) { - let mastic: Mastic = Mastic::new(0, typ, 256).unwrap(); + let mastic = Mastic::new(0, typ, 256).unwrap(); let ctx = b"some application"; let verify_key = [0u8; 32]; let nonce = [0u8; 16]; @@ -1443,7 +1380,7 @@ mod tests { let test_vec: TestVector = serde_json::from_str(test_vec_str).unwrap(); - let mastic = Mastic::<_, XofTurboShake128, 32>::new( + let mastic = Mastic::new( algorithm_id, new_typ(&test_vec.type_params), test_vec.vidpf_bits, diff --git a/src/vidpf.rs b/src/vidpf.rs index d7c68b2a..aa8500cf 100644 --- a/src/vidpf.rs +++ b/src/vidpf.rs @@ -627,7 +627,7 @@ pub(crate) struct VidpfEvalResult { pub(crate) share: W, } -const VIDPF_PROOF_SIZE: usize = 32; +pub(crate) const VIDPF_PROOF_SIZE: usize = 32; const VIDPF_SEED_SIZE: usize = 16; /// Allows to validate user input and shares after evaluation.