/// A component of the domain-separation tag, used to bind the VDAF operations to the document /// version. This will be revised with each draft with breaking changes. pub(crate) const VERSION: u8 = 8;
/// Errors emitted by this module. #[derive(Debug, thiserror::Error)] #[non_exhaustive] pubenum VdafError { /// An error occurred. #[error("vdaf error: {0}")]
Uncategorized(String),
/// Field error. #[error("field error: {0}")]
Field(#[from] FieldError),
/// An error occured while parsing a message. #[error("io error: {0}")]
IoError(#[from] std::io::Error),
/// Errors from other VDAFs. #[error(transparent)]
Other(Box<dyn Error + 'static + Send + Sync>),
}
/// An additive share of a vector of field elements. #[derive(Clone, Debug)] pubenum Share<F, const SEED_SIZE: usize> { /// An uncompressed share, typically sent to the leader.
Leader(Vec<F>),
/// A compressed share, typically sent to the helper.
Helper(Seed<SEED_SIZE>),
}
impl<F: ConstantTimeEq, const SEED_SIZE: usize> Eq for Share<F, SEED_SIZE> {}
impl<F: ConstantTimeEq, const SEED_SIZE: usize> ConstantTimeEq for Share<F, SEED_SIZE> { fn ct_eq(&self, other: &Self) -> subtle::Choice { // We allow short-circuiting on the type (Leader vs Helper) of the value, but not the types' // contents. match (self, other) {
(Share::Leader(self_val), Share::Leader(other_val)) => self_val.ct_eq(other_val),
(Share::Helper(self_val), Share::Helper(other_val)) => self_val.ct_eq(other_val),
_ => Choice::from(0),
}
}
}
/// Parameters needed to decode a [`Share`] #[derive(Clone, Debug, PartialEq, Eq)] pub(crate) enum ShareDecodingParameter<const SEED_SIZE: usize> {
Leader(usize),
Helper,
}
impl<F: FieldElement, const SEED_SIZE: usize> Encode for Share<F, SEED_SIZE> { fn encode(&self, bytes: &mut Vec<u8>) -> Result<(), CodecError> { matchself {
Share::Leader(share_data) => { for x in share_data {
x.encode(bytes)?;
}
Ok(())
}
Share::Helper(share_seed) => share_seed.encode(bytes),
}
}
fn encoded_len(&self) -> Option<usize> { matchself {
Share::Leader(share_data) => { // Each element of the data vector has the same size.
Some(share_data.len() * F::ENCODED_SIZE)
}
Share::Helper(share_seed) => share_seed.encoded_len(),
}
}
}
/// The base trait for VDAF schemes. This trait is inherited by traits [`Client`], [`Aggregator`], /// and [`Collector`], which define the roles of the various parties involved in the execution of /// the VDAF. pubtrait Vdaf: Clone + Debug { /// The type of Client measurement to be aggregated. type Measurement: Clone + Debug;
/// The aggregate result of the VDAF execution. type AggregateResult: Clone + Debug;
/// The aggregation parameter, used by the Aggregators to map their input shares to output /// shares. type AggregationParam: Clone + Debug + Decode + Encode;
/// A public share sent by a Client. type PublicShare: Clone + Debug + ParameterizedDecode<Self> + Encode;
/// An input share sent by a Client. type InputShare: Clone + Debug + for<'a> ParameterizedDecode<(&'a Self, usize)> + Encode;
/// An output share recovered from an input share by an Aggregator. type OutputShare: Clone
+ Debug
+ for<'a> ParameterizedDecode<(&'a Self, &'a Self::AggregationParam)>
+ Encode;
/// An Aggregator's share of the aggregate result. type AggregateShare: Aggregatable<OutputShare = Self::OutputShare>
+ for<'a> ParameterizedDecode<(&'a Self, &'a Self::AggregationParam)>
+ Encode;
/// Return the VDAF's algorithm ID. fn algorithm_id(&self) -> u32;
/// The number of Aggregators. The Client generates as many input shares as there are /// Aggregators. fn num_aggregators(&self) -> usize;
/// Generate the domain separation tag for this VDAF. The output is used for domain separation /// by the XOF. fn domain_separation_tag(&self, usage: u16) -> [u8; 8] { letmut dst = [0_u8; 8];
dst[0] = VERSION;
dst[1] = 0; // algorithm class
dst[2..6].copy_from_slice(&(self.algorithm_id()).to_be_bytes());
dst[6..8].copy_from_slice(&usage.to_be_bytes());
dst
}
}
/// The Client's role in the execution of a VDAF. pubtrait Client<const NONCE_SIZE: usize>: Vdaf { /// Shards a measurement into a public share and a sequence of input shares, one for each /// Aggregator. /// /// Implements `Vdaf::shard` from [VDAF]. /// /// [VDAF]: https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-vdaf-08#section-5.1 fn shard(
&self,
measurement: &Self::Measurement,
nonce: &[u8; NONCE_SIZE],
) -> Result<(Self::PublicShare, Vec<Self::InputShare>), VdafError>;
}
/// The Aggregator's role in the execution of a VDAF. pubtrait Aggregator<const VERIFY_KEY_SIZE: usize, const NONCE_SIZE: usize>: Vdaf { /// State of the Aggregator during the Prepare process. type PrepareState: Clone + Debug + PartialEq + Eq;
/// The type of messages sent by each aggregator at each round of the Prepare Process. /// /// Decoding takes a [`Self::PrepareState`] as a parameter; this [`Self::PrepareState`] may be /// associated with any aggregator involved in the execution of the VDAF. type PrepareShare: Clone + Debug + ParameterizedDecode<Self::PrepareState> + Encode;
/// Result of preprocessing a round of preparation shares. This is used by all aggregators as an /// input to the next round of the Prepare Process. /// /// Decoding takes a [`Self::PrepareState`] as a parameter; this [`Self::PrepareState`] may be /// associated with any aggregator involved in the execution of the VDAF. type PrepareMessage: Clone
+ Debug
+ PartialEq
+ Eq
+ ParameterizedDecode<Self::PrepareState>
+ Encode;
/// Begins the Prepare process with the other Aggregators. The [`Self::PrepareState`] returned /// is passed to [`Self::prepare_next`] to get this aggregator's first-round prepare message. /// /// Implements `Vdaf.prep_init` from [VDAF]. /// /// [VDAF]: https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-vdaf-08#section-5.2 fn prepare_init(
&self,
verify_key: &[u8; VERIFY_KEY_SIZE],
agg_id: usize,
agg_param: &Self::AggregationParam,
nonce: &[u8; NONCE_SIZE],
public_share: &Self::PublicShare,
input_share: &Self::InputShare,
) -> Result<(Self::PrepareState, Self::PrepareShare), VdafError>;
/// Preprocess a round of preparation shares into a single input to [`Self::prepare_next`]. /// /// Implements `Vdaf.prep_shares_to_prep` from [VDAF]. /// /// [VDAF]: https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-vdaf-08#section-5.2 fn prepare_shares_to_prepare_message<M: IntoIterator<Item = Self::PrepareShare>>(
&self,
agg_param: &Self::AggregationParam,
inputs: M,
) -> Result<Self::PrepareMessage, VdafError>;
/// Compute the next state transition from the current state and the previous round of input /// messages. If this returns [`PrepareTransition::Continue`], then the returned /// [`Self::PrepareShare`] should be combined with the other Aggregators' `PrepareShare`s from /// this round and passed into another call to this method. This continues until this method /// returns [`PrepareTransition::Finish`], at which point the returned output share may be /// aggregated. If the method returns an error, the aggregator should consider its input share /// invalid and not attempt to process it any further. /// /// Implements `Vdaf.prep_next` from [VDAF]. /// /// [VDAF]: https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-vdaf-08#section-5.2 fn prepare_next(
&self,
state: Self::PrepareState,
input: Self::PrepareMessage,
) -> Result<PrepareTransition<Self, VERIFY_KEY_SIZE, NONCE_SIZE>, VdafError>;
/// Aggregates a sequence of output shares into an aggregate share. fn aggregate<M: IntoIterator<Item = Self::OutputShare>>(
&self,
agg_param: &Self::AggregationParam,
output_shares: M,
) -> Result<Self::AggregateShare, VdafError>;
}
/// Aggregator that implements differential privacy with Aggregator-side noise addition. #[cfg(feature = "experimental")] #[cfg_attr(docsrs, doc(cfg(feature = "experimental")))] pubtrait AggregatorWithNoise< const VERIFY_KEY_SIZE: usize, const NONCE_SIZE: usize,
DPStrategy: DifferentialPrivacyStrategy,
>: Aggregator<VERIFY_KEY_SIZE, NONCE_SIZE>
{ /// Adds noise to an aggregate share such that the aggregate result is differentially private /// as long as one Aggregator is honest. fn add_noise_to_agg_share(
&self,
dp_strategy: &DPStrategy,
agg_param: &Self::AggregationParam,
agg_share: &mutSelf::AggregateShare,
num_measurements: usize,
) -> Result<(), VdafError>;
}
/// The Collector's role in the execution of a VDAF. pubtrait Collector: Vdaf { /// Combines aggregate shares into the aggregate result. fn unshard<M: IntoIterator<Item = Self::AggregateShare>>(
&self,
agg_param: &Self::AggregationParam,
agg_shares: M,
num_measurements: usize,
) -> Result<Self::AggregateResult, VdafError>;
}
/// A state transition of an Aggregator during the Prepare process. #[derive(Clone, Debug)] pubenum PrepareTransition<
V: Aggregator<VERIFY_KEY_SIZE, NONCE_SIZE>, const VERIFY_KEY_SIZE: usize, const NONCE_SIZE: usize,
> { /// Continue processing. Continue(V::PrepareState, V::PrepareShare),
/// Finish processing and return the output share.
Finish(V::OutputShare),
}
/// An aggregate share resulting from aggregating output shares together that /// can merged with aggregate shares of the same type. pubtrait Aggregatable: Clone + Debug + From<Self::OutputShare> { /// Type of output shares that can be accumulated into an aggregate share. type OutputShare;
/// Update an aggregate share by merging it with another (`agg_share`). fn merge(&mutself, agg_share: &Self) -> Result<(), VdafError>;
/// Update an aggregate share by adding `output_share`. fn accumulate(&mutself, output_share: &Self::OutputShare) -> Result<(), VdafError>;
}
/// An output share comprised of a vector of field elements. #[derive(Clone)] pubstruct OutputShare<F>(Vec<F>);
/// An aggregate share comprised of a vector of field elements. /// /// This is suitable for VDAFs where both output shares and aggregate shares are vectors of field /// elements, and output shares need no special transformation to be merged into an aggregate share. #[derive(Clone, Debug, Serialize, Deserialize)]
fn accumulate(&mutself, output_share: &Self::OutputShare) -> Result<(), VdafError> { // For Poplar1, Prio2, and Prio3, no conversion is needed between output shares and // aggregate shares. self.sum(output_share.as_ref())
}
}
letmut out_shares = Vec::new(); loop { letmut outbound = Vec::new(); for state in states.iter_mut() { match vdaf.prepare_next(
state.clone(),
V::PrepareMessage::get_decoded_with_param(state, &inbound)
.expect("failed to decode prep message"),
)? {
PrepareTransition::Continue(new_state, msg) => {
outbound.push(msg.get_encoded().unwrap());
*state = new_state
}
PrepareTransition::Finish(out_share) => {
out_shares.push(out_share);
}
}
}
if outbound.len() == vdaf.num_aggregators() { // Another round is required before output shares are computed.
inbound = vdaf
.prepare_shares_to_prepare_message(
agg_param,
outbound.iter().map(|encoded| {
V::PrepareShare::get_decoded_with_param(&states[0], encoded)
.expect("failed to decode prep share")
}),
)?
.get_encoded()
.unwrap();
} elseif outbound.is_empty() { // Each Aggregator recovered an output share. break;
} else {
panic!("Aggregators did not finish the prepare phase at the same time");
}
}
Ok(out_shares)
}
}
#[cfg(test)] fn fieldvec_roundtrip_test<F, V, T>(vdaf: &V, agg_param: &V::AggregationParam, length: usize) where
F: FieldElement,
V: Vdaf,
T: Encode, for<'a> T: ParameterizedDecode<(&'a V, &'a V::AggregationParam)>,
{ // Generate an arbitrary vector of field elements. let vec: Vec<F> = crate::field::random_vector(length).unwrap();
// Serialize the field element vector into a vector of bytes. letmut bytes = Vec::with_capacity(vec.len() * F::ENCODED_SIZE);
encode_fieldvec(&vec, &mut bytes).unwrap();
// Deserialize the type of interest from those bytes. let value = T::get_decoded_with_param(&(vdaf, agg_param), &bytes).unwrap();
// Round-trip the value back to a vector of bytes. let encoded = value.get_encoded().unwrap();
assert_eq!(encoded, bytes);
}
#[cfg(test)] fn equality_comparison_test<T>(values: &[T]) where
T: Debug + PartialEq,
{ use std::ptr;
// This function expects that every value passed in `values` is distinct, i.e. should not // compare as equal to any other element. We test both (i, j) and (j, i) to gain confidence that // equality implementations are symmetric. for (i, i_val) in values.iter().enumerate() { for (j, j_val) in values.iter().enumerate() { if i == j {
assert!(ptr::eq(i_val, j_val)); // sanity
assert_eq!(
i_val, j_val, "Expected element at index {i} to be equal to itself, but it was not"
);
} else {
assert_ne!(
i_val, j_val, "Expected elements at indices {i} & {j} to not be equal, but they were"
)
}
}
}
}
#[cfg(test)] mod tests { usecrate::vdaf::{equality_comparison_test, xof::Seed, AggregateShare, OutputShare, Share};
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.