//! Backwards-compatible port of the ENPA Prio system to a VDAF.
usecrate::{
codec::{CodecError, Decode, Encode, ParameterizedDecode},
field::{
decode_fieldvec, FftFriendlyFieldElement, FieldElement, FieldElementWithInteger, FieldPrio2,
},
prng::Prng,
vdaf::{
prio2::{
client::{selfas v2_client, proof_length},
server as v2_server,
},
xof::Seed,
Aggregatable, AggregateShare, Aggregator, Client, Collector, OutputShare,
PrepareTransition, Share, ShareDecodingParameter, Vdaf, VdafError,
},
}; use hmac::{Hmac, Mac}; use rand_core::RngCore; use sha2::Sha256; use std::{convert::TryFrom, io::Cursor}; use subtle::{Choice, ConstantTimeEq};
mod client; mod server; #[cfg(test)] mod test_vector;
/// The Prio2 VDAF. It supports the same measurement type as /// [`Prio3SumVec`](crate::vdaf::prio3::Prio3SumVec) with `bits == 1` but uses the proof system and /// finite field deployed in ENPA. #[derive(Clone, Debug)] pubstruct Prio2 {
input_len: usize,
}
impl Prio2 { /// Returns an instance of the VDAF for the given input length. pubfn new(input_len: usize) -> Result<Self, VdafError> { let n = (input_len + 1).next_power_of_two(); iflet Ok(size) = u32::try_from(2 * n) { if size > FieldPrio2::generator_order() { return Err(VdafError::Uncategorized( "input size exceeds field capacity".into(),
));
}
} else { return Err(VdafError::Uncategorized( "input size exceeds memory capacity".into(),
));
}
Ok(Prio2 { input_len })
}
/// Prepare an input share for aggregation using the given field element `query_rand` to /// compute the verifier share. /// /// In the [`Aggregator`] trait implementation for [`Prio2`], the query randomness is computed /// jointly by the Aggregators. This method is designed to be used in applications, like ENPA, /// in which the query randomness is instead chosen by a third-party. pubfn prepare_init_with_query_rand(
&self,
query_rand: FieldPrio2,
input_share: &Share<FieldPrio2, 32>,
is_leader: bool,
) -> Result<(Prio2PrepareState, Prio2PrepareShare), VdafError> { let expanded_data: Option<Vec<FieldPrio2>> = match input_share {
Share::Leader(_) => None,
Share::Helper(ref seed) => { let prng = Prng::from_prio2_seed(seed.as_ref());
Some(prng.take(proof_length(self.input_len)).collect())
}
}; let data = match input_share {
Share::Leader(ref data) => data,
Share::Helper(_) => expanded_data.as_ref().unwrap(),
};
let verifier_share = v2_server::generate_verification_message( self.input_len,
query_rand,
data, // Combined input and proof shares
is_leader,
)
.map_err(|e| VdafError::Uncategorized(e.to_string()))?;
let truncated_share = match input_share {
Share::Leader(data) => Share::Leader(data[..self.input_len].to_vec()),
Share::Helper(seed) => Share::Helper(seed.clone()),
};
/// Choose a random point for polynomial evaluation. /// /// The point returned is not one of the roots used for polynomial interpolation. pub(crate) fn choose_eval_at<S>(&self, prng: &mut Prng<FieldPrio2, S>) -> FieldPrio2 where
S: RngCore,
{ // Make sure the query randomness isn't a root of unity. Evaluating the proof at any of // these points would be a privacy violation, since these points were used by the prover to // construct the wire polynomials. let n = (self.input_len + 1).next_power_of_two(); let proof_length = 2 * n; loop { let eval_at: FieldPrio2 = prng.get(); // Unwrap safety: the constructor checks that this conversion succeeds. if eval_at.pow(u32::try_from(proof_length).unwrap()) != FieldPrio2::one() { return eval_at;
}
}
}
}
impl Vdaf for Prio2 { type Measurement = Vec<u32>; type AggregateResult = Vec<u32>; type AggregationParam = (); type PublicShare = (); type InputShare = Share<FieldPrio2, 32>; type OutputShare = OutputShare<FieldPrio2>; type AggregateShare = AggregateShare<FieldPrio2>;
fn algorithm_id(&self) -> u32 { 0xFFFF0000
}
fn num_aggregators(&self) -> usize { // Prio2 can easily be extended to support more than two Aggregators. 2
}
}
impl Client<16> for Prio2 { fn shard(
&self,
measurement: &Vec<u32>,
_nonce: &[u8; 16],
) -> Result<(Self::PublicShare, Vec<Share<FieldPrio2, 32>>), VdafError> { if measurement.len() != self.input_len { return Err(VdafError::Uncategorized("incorrect input length".into()));
} letmut input: Vec<FieldPrio2> = Vec::with_capacity(measurement.len()); for int in measurement {
input.push((*int).into());
}
letmut mem = v2_client::ClientMemory::new(self.input_len)?; let copy_data = |share_data: &mut [FieldPrio2]| {
share_data[..].clone_from_slice(&input);
}; letmut leader_data = mem.prove_with(self.input_len, copy_data);
let helper_seed = Seed::generate()?; let helper_prng = Prng::from_prio2_seed(helper_seed.as_ref()); for (s1, d) in leader_data.iter_mut().zip(helper_prng.into_iter()) {
*s1 -= d;
}
/// Message emitted by each [`Aggregator`] during the Preparation phase. #[derive(Clone, Debug)] pubstruct Prio2PrepareShare(v2_server::VerificationMessage<FieldPrio2>);
// In the ENPA Prio system, the query randomness is generated by a third party and // distributed to the Aggregators after they receive their input shares. In a VDAF, shared // randomness is derived from a nonce selected by the client. For Prio2 we compute the // query using HMAC-SHA256 evaluated over the nonce. // // Unwrap safety: new_from_slice() is infallible for Hmac. letmut mac = Hmac::<Sha256>::new_from_slice(agg_key).unwrap();
mac.update(nonce); let hmac_tag = mac.finalize(); letmut prng = Prng::from_prio2_seed(&hmac_tag.into_bytes().into()); let query_rand = self.choose_eval_at(&mut prng);
#[cfg(test)] mod tests { usesuper::*; usecrate::vdaf::{
equality_comparison_test, fieldvec_roundtrip_test, prio2::test_vector::Priov2TestVector,
test_utils::run_vdaf,
}; use assert_matches::assert_matches; use rand::prelude::*;
#[test] fn run_prio2() { let prio2 = Prio2::new(6).unwrap();
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.