// Copyright (c) 2020 Apple Inc. // SPDX-License-Identifier: MPL-2.0
//! Primitives for the Prio2 server. usecrate::{
field::{FftFriendlyFieldElement, FieldError},
polynomial::poly_interpret_eval,
prng::PrngError,
vdaf::prio2::client::{unpack_proof, SerializeError},
}; use serde::{Deserialize, Serialize};
/// Possible errors from server operations #[derive(Debug, thiserror::Error)] pubenum ServerError { /// Unexpected Share Length #[allow(unused)] #[error("unexpected share length")]
ShareLength, /// Finite field operation error #[error("finite field operation error")]
Field(#[from] FieldError), /// Serialization/deserialization error #[error("serialization/deserialization error")]
Serialize(#[from] SerializeError), /// Failure when calling getrandom(). #[error("getrandom: {0}")]
GetRandom(#[from] getrandom::Error), /// PRNG error. #[error("prng error: {0}")]
Prng(#[from] PrngError),
}
/// Verification message for proof validation #[derive(Clone, Debug, Serialize, Deserialize)] pubstruct VerificationMessage<F> { /// f evaluated at random point pub f_r: F, /// g evaluated at random point pub g_r: F, /// h evaluated at random point pub h_r: F,
}
/// Given a proof and evaluation point, this constructs the verification /// message. pub(crate) fn generate_verification_message<F: FftFriendlyFieldElement>(
dimension: usize,
eval_at: F,
proof: &[F],
is_first_server: bool,
) -> Result<VerificationMessage<F>, ServerError> { let unpacked = unpack_proof(proof, dimension)?; let n: usize = (dimension + 1).next_power_of_two(); let proof_length = 2 * n; letmut fft_in = vec![F::zero(); proof_length]; letmut fft_mem = vec![F::zero(); proof_length];
// construct and evaluate polynomial f at the random point
fft_in[0] = *unpacked.f0;
fft_in[1..unpacked.data.len() + 1].copy_from_slice(unpacked.data); let f_r = poly_interpret_eval(&fft_in[..n], eval_at, &mut fft_mem);
// construct and evaluate polynomial g at the random point
fft_in[0] = *unpacked.g0; if is_first_server { for x in fft_in[1..unpacked.data.len() + 1].iter_mut() {
*x -= F::one();
}
} let g_r = poly_interpret_eval(&fft_in[..n], eval_at, &mut fft_mem);
// construct and evaluate polynomial h at the random point
fft_in[0] = *unpacked.h0;
fft_in[1] = unpacked.points_h_packed[0]; for (x, chunk) in unpacked.points_h_packed[1..]
.iter()
.zip(fft_in[2..proof_length].chunks_exact_mut(2))
{
chunk[0] = F::zero();
chunk[1] = *x;
} let h_r = poly_interpret_eval(&fft_in, eval_at, &mut fft_mem);
Ok(VerificationMessage { f_r, g_r, h_r })
}
/// Decides if the distributed proof is valid pub(crate) fn is_valid_share<F: FftFriendlyFieldElement>(
v1: &VerificationMessage<F>,
v2: &VerificationMessage<F>,
) -> bool { // reconstruct f_r, g_r, h_r let f_r = v1.f_r + v2.f_r; let g_r = v1.g_r + v2.g_r; let h_r = v1.h_r + v2.h_r; // validity check
f_r * g_r == h_r
}
/// Main workhorse of the server. #[derive(Debug)] pub(crate) struct Server<F> {
dimension: usize,
is_first_server: bool,
accumulator: Vec<F>,
}
impl<F: FftFriendlyFieldElement> Server<F> { /// Construct a new server instance /// /// Params: /// * `dimension`: the number of elements in the aggregation vector. /// * `is_first_server`: only one of the servers should have this true. pubfn new(dimension: usize, is_first_server: bool) -> Result<Server<F>, ServerError> {
Ok(Server {
dimension,
is_first_server,
accumulator: vec![F::zero(); dimension],
})
}
/// Deserialize fn deserialize_share(&self, share: &[u8]) -> Result<Vec<F>, ServerError> { let len = proof_length(self.dimension); let decoding_parameter = ifself.is_first_server {
ShareDecodingParameter::Leader(len)
} else {
ShareDecodingParameter::Helper
}; let decoded_share = Share::get_decoded_with_param(&decoding_parameter, share)
.map_err(SerializeError::from)?; match decoded_share {
Share::Leader(vec) => Ok(vec),
Share::Helper(seed) => Ok(Prng::from_prio2_seed(&seed.0).take(len).collect()),
}
}
/// Generate verification message from an encrypted share /// /// This decrypts the share of the proof and constructs the /// [`VerificationMessage`](struct.VerificationMessage.html). /// The `eval_at` field should be generate by /// [choose_eval_at](#method.choose_eval_at). pubfn generate_verification_message(
&mutself,
eval_at: F,
share: &[u8],
) -> Result<VerificationMessage<F>, ServerError> { let share_field = self.deserialize_share(share)?;
generate_verification_message( self.dimension,
eval_at,
&share_field, self.is_first_server,
)
}
/// Add the content of the encrypted share into the accumulator /// /// This only changes the accumulator if the verification messages `v1` and /// `v2` indicate that the share passed validation. pubfn aggregate(
&mutself,
share: &[u8],
v1: &VerificationMessage<F>,
v2: &VerificationMessage<F>,
) -> Result<bool, ServerError> { let share_field = self.deserialize_share(share)?; let is_valid = is_valid_share(v1, v2); if is_valid { // Add to the accumulator. share_field also includes the proof // encoding, so we slice off the first dimension fields, which are // the actual data share.
merge_vector(&mutself.accumulator, &share_field[..self.dimension])?;
}
Ok(is_valid)
}
}
}
#[cfg(test)] mod tests { usesuper::*; usecrate::{
codec::{Encode, ParameterizedDecode},
field::{FieldElement, FieldPrio2},
prng::Prng,
vdaf::{
prio2::{
client::{proof_length, unpack_proof_mut},
server::test_util::Server,
Prio2,
},
Client, Share, ShareDecodingParameter,
},
}; use assert_matches::assert_matches; use rand::{random, Rng};
fn secret_share(share: &mut [FieldPrio2]) -> Vec<FieldPrio2> { letmut rng = rand::thread_rng(); letmut share2 = vec![FieldPrio2::zero(); share.len()]; for (f1, f2) in share.iter_mut().zip(share2.iter_mut()) { let f = FieldPrio2::from(rng.gen::<u32>());
*f2 = f;
*f1 -= f;
}
share2
}
letmut proof: Vec<FieldPrio2> = proof_u32.iter().map(|x| FieldPrio2::from(*x)).collect(); let share2 = secret_share(&mut proof); let eval_at = FieldPrio2::from(12313);
let v1 = generate_verification_message(dim, eval_at, &proof, true).unwrap(); let v2 = generate_verification_message(dim, eval_at, &share2, false).unwrap();
// serialize and deserialize the first verification message let serialized = serde_json::to_string(&v1).unwrap(); let deserialized: VerificationMessage<FieldPrio2> =
serde_json::from_str(&serialized).unwrap();
let vdaf = Prio2::new(dim).unwrap(); let (_, shares) = vdaf.shard(&data, &[0; 16]).unwrap(); let share1_original = shares[0].get_encoded().unwrap(); let share2 = shares[1].get_encoded().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.