summaryrefslogtreecommitdiffstats
path: root/third_party/rust/prio/src
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--third_party/rust/prio/src/codec.rs210
-rw-r--r--third_party/rust/prio/src/dp.rs1
-rw-r--r--third_party/rust/prio/src/dp/distributions.rs22
-rw-r--r--third_party/rust/prio/src/fft.rs1
-rw-r--r--third_party/rust/prio/src/field.rs379
-rw-r--r--third_party/rust/prio/src/field/field255.rs31
-rw-r--r--third_party/rust/prio/src/flp.rs241
-rw-r--r--third_party/rust/prio/src/flp/types.rs460
-rw-r--r--third_party/rust/prio/src/flp/types/fixedpoint_l2.rs131
-rw-r--r--third_party/rust/prio/src/idpf.rs152
-rw-r--r--third_party/rust/prio/src/lib.rs7
-rw-r--r--third_party/rust/prio/src/polynomial.rs4
-rw-r--r--third_party/rust/prio/src/prng.rs71
-rw-r--r--third_party/rust/prio/src/topology/ping_pong.rs125
-rw-r--r--third_party/rust/prio/src/vdaf.rs437
-rw-r--r--third_party/rust/prio/src/vdaf/dummy.rs147
-rw-r--r--third_party/rust/prio/src/vdaf/poplar1.rs306
-rw-r--r--third_party/rust/prio/src/vdaf/prio2.rs30
-rw-r--r--third_party/rust/prio/src/vdaf/prio2/client.rs16
-rw-r--r--third_party/rust/prio/src/vdaf/prio2/server.rs50
-rw-r--r--third_party/rust/prio/src/vdaf/prio2/test_vector.rs32
-rw-r--r--third_party/rust/prio/src/vdaf/prio3.rs630
-rw-r--r--third_party/rust/prio/src/vdaf/prio3_test.rs162
-rw-r--r--third_party/rust/prio/src/vdaf/test_vec/07/IdpfPoplar_0.json52
-rw-r--r--third_party/rust/prio/src/vdaf/test_vec/07/Poplar1_0.json56
-rw-r--r--third_party/rust/prio/src/vdaf/test_vec/07/Poplar1_1.json64
-rw-r--r--third_party/rust/prio/src/vdaf/test_vec/07/Poplar1_2.json64
-rw-r--r--third_party/rust/prio/src/vdaf/test_vec/07/Poplar1_3.json76
-rw-r--r--third_party/rust/prio/src/vdaf/test_vec/07/Prio3Count_0.json39
-rw-r--r--third_party/rust/prio/src/vdaf/test_vec/07/Prio3Count_1.json45
-rw-r--r--third_party/rust/prio/src/vdaf/test_vec/07/Prio3Histogram_0.json52
-rw-r--r--third_party/rust/prio/src/vdaf/test_vec/07/Prio3Histogram_1.json89
-rw-r--r--third_party/rust/prio/src/vdaf/test_vec/07/Prio3SumVec_0.json194
-rw-r--r--third_party/rust/prio/src/vdaf/test_vec/07/Prio3SumVec_1.json146
-rw-r--r--third_party/rust/prio/src/vdaf/test_vec/07/Prio3Sum_0.json40
-rw-r--r--third_party/rust/prio/src/vdaf/test_vec/07/Prio3Sum_1.json46
-rw-r--r--third_party/rust/prio/src/vdaf/test_vec/07/XofFixedKeyAes128.json8
-rw-r--r--third_party/rust/prio/src/vdaf/test_vec/07/XofShake128.json8
-rw-r--r--third_party/rust/prio/src/vdaf/test_vec/08/IdpfPoplar_0.json52
-rw-r--r--third_party/rust/prio/src/vdaf/test_vec/08/Poplar1_0.json56
-rw-r--r--third_party/rust/prio/src/vdaf/test_vec/08/Poplar1_1.json64
-rw-r--r--third_party/rust/prio/src/vdaf/test_vec/08/Poplar1_2.json64
-rw-r--r--third_party/rust/prio/src/vdaf/test_vec/08/Poplar1_3.json76
-rw-r--r--third_party/rust/prio/src/vdaf/test_vec/08/Prio3Count_0.json39
-rw-r--r--third_party/rust/prio/src/vdaf/test_vec/08/Prio3Count_1.json45
-rw-r--r--third_party/rust/prio/src/vdaf/test_vec/08/Prio3Histogram_0.json52
-rw-r--r--third_party/rust/prio/src/vdaf/test_vec/08/Prio3Histogram_1.json89
-rw-r--r--third_party/rust/prio/src/vdaf/test_vec/08/Prio3SumVec_0.json194
-rw-r--r--third_party/rust/prio/src/vdaf/test_vec/08/Prio3SumVec_1.json146
-rw-r--r--third_party/rust/prio/src/vdaf/test_vec/08/Prio3Sum_0.json40
-rw-r--r--third_party/rust/prio/src/vdaf/test_vec/08/Prio3Sum_1.json46
-rw-r--r--third_party/rust/prio/src/vdaf/test_vec/08/XofFixedKeyAes128.json8
-rw-r--r--third_party/rust/prio/src/vdaf/test_vec/08/XofTurboShake128.json8
-rw-r--r--third_party/rust/prio/src/vdaf/test_vec/XofHmacSha256Aes128.json8
-rw-r--r--third_party/rust/prio/src/vdaf/xof.rs148
-rw-r--r--third_party/rust/prio/src/vidpf.rs827
56 files changed, 3990 insertions, 2596 deletions
diff --git a/third_party/rust/prio/src/codec.rs b/third_party/rust/prio/src/codec.rs
index 71f4f8ce5f..98e6299abd 100644
--- a/third_party/rust/prio/src/codec.rs
+++ b/third_party/rust/prio/src/codec.rs
@@ -20,6 +20,7 @@ use std::{
/// An error that occurred during decoding.
#[derive(Debug, thiserror::Error)]
+#[non_exhaustive]
pub enum CodecError {
/// An I/O error.
#[error("I/O error")]
@@ -33,6 +34,10 @@ pub enum CodecError {
#[error("length prefix of encoded vector overflows buffer: {0}")]
LengthPrefixTooBig(usize),
+ /// The byte length of a vector exceeded the range of its length prefix.
+ #[error("vector length exceeded range of length prefix")]
+ LengthPrefixOverflow,
+
/// Custom errors from [`Decode`] implementations.
#[error("other error: {0}")]
Other(#[source] Box<dyn Error + 'static + Send + Sync>),
@@ -97,10 +102,10 @@ impl<D: Decode + ?Sized, T> ParameterizedDecode<T> for D {
/// Describes how to encode objects into a byte sequence.
pub trait Encode {
/// Append the encoded form of this object to the end of `bytes`, growing the vector as needed.
- fn encode(&self, bytes: &mut Vec<u8>);
+ fn encode(&self, bytes: &mut Vec<u8>) -> Result<(), CodecError>;
/// Convenience method to encode a value into a new `Vec<u8>`.
- fn get_encoded(&self) -> Vec<u8> {
+ fn get_encoded(&self) -> Result<Vec<u8>, CodecError> {
self.get_encoded_with_param(&())
}
@@ -116,17 +121,21 @@ pub trait ParameterizedEncode<P> {
/// Append the encoded form of this object to the end of `bytes`, growing the vector as needed.
/// `encoding_parameter` provides details of the wire encoding, used to control how the value
/// is encoded.
- fn encode_with_param(&self, encoding_parameter: &P, bytes: &mut Vec<u8>);
+ fn encode_with_param(
+ &self,
+ encoding_parameter: &P,
+ bytes: &mut Vec<u8>,
+ ) -> Result<(), CodecError>;
/// Convenience method to encode a value into a new `Vec<u8>`.
- fn get_encoded_with_param(&self, encoding_parameter: &P) -> Vec<u8> {
+ fn get_encoded_with_param(&self, encoding_parameter: &P) -> Result<Vec<u8>, CodecError> {
let mut ret = if let Some(length) = self.encoded_len_with_param(encoding_parameter) {
Vec::with_capacity(length)
} else {
Vec::new()
};
- self.encode_with_param(encoding_parameter, &mut ret);
- ret
+ self.encode_with_param(encoding_parameter, &mut ret)?;
+ Ok(ret)
}
/// Returns an optional hint indicating how many bytes will be required to encode this value, or
@@ -139,7 +148,11 @@ pub trait ParameterizedEncode<P> {
/// Provide a blanket implementation so that any [`Encode`] can be used as a
/// `ParameterizedEncode<T>` for any `T`.
impl<E: Encode + ?Sized, T> ParameterizedEncode<T> for E {
- fn encode_with_param(&self, _encoding_parameter: &T, bytes: &mut Vec<u8>) {
+ fn encode_with_param(
+ &self,
+ _encoding_parameter: &T,
+ bytes: &mut Vec<u8>,
+ ) -> Result<(), CodecError> {
self.encode(bytes)
}
@@ -155,7 +168,9 @@ impl Decode for () {
}
impl Encode for () {
- fn encode(&self, _bytes: &mut Vec<u8>) {}
+ fn encode(&self, _bytes: &mut Vec<u8>) -> Result<(), CodecError> {
+ Ok(())
+ }
fn encoded_len(&self) -> Option<usize> {
Some(0)
@@ -171,8 +186,9 @@ impl Decode for u8 {
}
impl Encode for u8 {
- fn encode(&self, bytes: &mut Vec<u8>) {
+ fn encode(&self, bytes: &mut Vec<u8>) -> Result<(), CodecError> {
bytes.push(*self);
+ Ok(())
}
fn encoded_len(&self) -> Option<usize> {
@@ -187,8 +203,9 @@ impl Decode for u16 {
}
impl Encode for u16 {
- fn encode(&self, bytes: &mut Vec<u8>) {
+ fn encode(&self, bytes: &mut Vec<u8>) -> Result<(), CodecError> {
bytes.extend_from_slice(&u16::to_be_bytes(*self));
+ Ok(())
}
fn encoded_len(&self) -> Option<usize> {
@@ -208,9 +225,10 @@ impl Decode for U24 {
}
impl Encode for U24 {
- fn encode(&self, bytes: &mut Vec<u8>) {
+ fn encode(&self, bytes: &mut Vec<u8>) -> Result<(), CodecError> {
// Encode lower three bytes of the u32 as u24
bytes.extend_from_slice(&u32::to_be_bytes(self.0)[1..]);
+ Ok(())
}
fn encoded_len(&self) -> Option<usize> {
@@ -225,8 +243,9 @@ impl Decode for u32 {
}
impl Encode for u32 {
- fn encode(&self, bytes: &mut Vec<u8>) {
+ fn encode(&self, bytes: &mut Vec<u8>) -> Result<(), CodecError> {
bytes.extend_from_slice(&u32::to_be_bytes(*self));
+ Ok(())
}
fn encoded_len(&self) -> Option<usize> {
@@ -241,8 +260,9 @@ impl Decode for u64 {
}
impl Encode for u64 {
- fn encode(&self, bytes: &mut Vec<u8>) {
+ fn encode(&self, bytes: &mut Vec<u8>) -> Result<(), CodecError> {
bytes.extend_from_slice(&u64::to_be_bytes(*self));
+ Ok(())
}
fn encoded_len(&self) -> Option<usize> {
@@ -257,18 +277,19 @@ pub fn encode_u8_items<P, E: ParameterizedEncode<P>>(
bytes: &mut Vec<u8>,
encoding_parameter: &P,
items: &[E],
-) {
+) -> Result<(), CodecError> {
// Reserve space to later write length
let len_offset = bytes.len();
bytes.push(0);
for item in items {
- item.encode_with_param(encoding_parameter, bytes);
+ item.encode_with_param(encoding_parameter, bytes)?;
}
- let len = bytes.len() - len_offset - 1;
- assert!(len <= usize::from(u8::MAX));
- bytes[len_offset] = len as u8;
+ let len =
+ u8::try_from(bytes.len() - len_offset - 1).map_err(|_| CodecError::LengthPrefixOverflow)?;
+ bytes[len_offset] = len;
+ Ok(())
}
/// Decode `bytes` into a vector of `D` values, treating `bytes` as a [variable-length vector][1] of
@@ -292,20 +313,19 @@ pub fn encode_u16_items<P, E: ParameterizedEncode<P>>(
bytes: &mut Vec<u8>,
encoding_parameter: &P,
items: &[E],
-) {
+) -> Result<(), CodecError> {
// Reserve space to later write length
let len_offset = bytes.len();
- 0u16.encode(bytes);
+ 0u16.encode(bytes)?;
for item in items {
- item.encode_with_param(encoding_parameter, bytes);
+ item.encode_with_param(encoding_parameter, bytes)?;
}
- let len = bytes.len() - len_offset - 2;
- assert!(len <= usize::from(u16::MAX));
- for (offset, byte) in u16::to_be_bytes(len as u16).iter().enumerate() {
- bytes[len_offset + offset] = *byte;
- }
+ let len = u16::try_from(bytes.len() - len_offset - 2)
+ .map_err(|_| CodecError::LengthPrefixOverflow)?;
+ bytes[len_offset..len_offset + 2].copy_from_slice(&len.to_be_bytes());
+ Ok(())
}
/// Decode `bytes` into a vector of `D` values, treating `bytes` as a [variable-length vector][1] of
@@ -330,20 +350,22 @@ pub fn encode_u24_items<P, E: ParameterizedEncode<P>>(
bytes: &mut Vec<u8>,
encoding_parameter: &P,
items: &[E],
-) {
+) -> Result<(), CodecError> {
// Reserve space to later write length
let len_offset = bytes.len();
- U24(0).encode(bytes);
+ U24(0).encode(bytes)?;
for item in items {
- item.encode_with_param(encoding_parameter, bytes);
+ item.encode_with_param(encoding_parameter, bytes)?;
}
- let len = bytes.len() - len_offset - 3;
- assert!(len <= 0xffffff);
- for (offset, byte) in u32::to_be_bytes(len as u32)[1..].iter().enumerate() {
- bytes[len_offset + offset] = *byte;
+ let len = u32::try_from(bytes.len() - len_offset - 3)
+ .map_err(|_| CodecError::LengthPrefixOverflow)?;
+ if len > 0xffffff {
+ return Err(CodecError::LengthPrefixOverflow);
}
+ bytes[len_offset..len_offset + 3].copy_from_slice(&len.to_be_bytes()[1..]);
+ Ok(())
}
/// Decode `bytes` into a vector of `D` values, treating `bytes` as a [variable-length vector][1] of
@@ -368,20 +390,19 @@ pub fn encode_u32_items<P, E: ParameterizedEncode<P>>(
bytes: &mut Vec<u8>,
encoding_parameter: &P,
items: &[E],
-) {
+) -> Result<(), CodecError> {
// Reserve space to later write length
let len_offset = bytes.len();
- 0u32.encode(bytes);
+ 0u32.encode(bytes)?;
for item in items {
- item.encode_with_param(encoding_parameter, bytes);
+ item.encode_with_param(encoding_parameter, bytes)?;
}
- let len = bytes.len() - len_offset - 4;
- let len: u32 = len.try_into().expect("Length too large");
- for (offset, byte) in len.to_be_bytes().iter().enumerate() {
- bytes[len_offset + offset] = *byte;
- }
+ let len = u32::try_from(bytes.len() - len_offset - 4)
+ .map_err(|_| CodecError::LengthPrefixOverflow)?;
+ bytes[len_offset..len_offset + 4].copy_from_slice(&len.to_be_bytes());
+ Ok(())
}
/// Decode `bytes` into a vector of `D` values, treating `bytes` as a [variable-length vector][1] of
@@ -432,6 +453,7 @@ fn decode_items<P, D: ParameterizedDecode<P>>(
#[cfg(test)]
mod tests {
+ use std::io::ErrorKind;
use super::*;
use assert_matches::assert_matches;
@@ -439,7 +461,7 @@ mod tests {
#[test]
fn encode_nothing() {
let mut bytes = vec![];
- ().encode(&mut bytes);
+ ().encode(&mut bytes).unwrap();
assert_eq!(bytes.len(), 0);
}
@@ -448,7 +470,7 @@ mod tests {
let value = 100u8;
let mut bytes = vec![];
- value.encode(&mut bytes);
+ value.encode(&mut bytes).unwrap();
assert_eq!(bytes.len(), 1);
let decoded = u8::decode(&mut Cursor::new(&bytes)).unwrap();
@@ -460,7 +482,7 @@ mod tests {
let value = 1000u16;
let mut bytes = vec![];
- value.encode(&mut bytes);
+ value.encode(&mut bytes).unwrap();
assert_eq!(bytes.len(), 2);
// Check endianness of encoding
assert_eq!(bytes, vec![3, 232]);
@@ -474,7 +496,7 @@ mod tests {
let value = U24(1_000_000u32);
let mut bytes = vec![];
- value.encode(&mut bytes);
+ value.encode(&mut bytes).unwrap();
assert_eq!(bytes.len(), 3);
// Check endianness of encoding
assert_eq!(bytes, vec![15, 66, 64]);
@@ -488,7 +510,7 @@ mod tests {
let value = 134_217_728u32;
let mut bytes = vec![];
- value.encode(&mut bytes);
+ value.encode(&mut bytes).unwrap();
assert_eq!(bytes.len(), 4);
// Check endianness of encoding
assert_eq!(bytes, vec![8, 0, 0, 0]);
@@ -502,7 +524,7 @@ mod tests {
let value = 137_438_953_472u64;
let mut bytes = vec![];
- value.encode(&mut bytes);
+ value.encode(&mut bytes).unwrap();
assert_eq!(bytes.len(), 8);
// Check endianness of encoding
assert_eq!(bytes, vec![0, 0, 0, 32, 0, 0, 0, 0]);
@@ -521,12 +543,12 @@ mod tests {
}
impl Encode for TestMessage {
- fn encode(&self, bytes: &mut Vec<u8>) {
- self.field_u8.encode(bytes);
- self.field_u16.encode(bytes);
- self.field_u24.encode(bytes);
- self.field_u32.encode(bytes);
- self.field_u64.encode(bytes);
+ fn encode(&self, bytes: &mut Vec<u8>) -> Result<(), CodecError> {
+ self.field_u8.encode(bytes)?;
+ self.field_u16.encode(bytes)?;
+ self.field_u24.encode(bytes)?;
+ self.field_u32.encode(bytes)?;
+ self.field_u64.encode(bytes)
}
fn encoded_len(&self) -> Option<usize> {
@@ -584,7 +606,7 @@ mod tests {
};
let mut bytes = vec![];
- value.encode(&mut bytes);
+ value.encode(&mut bytes).unwrap();
assert_eq!(bytes.len(), TestMessage::encoded_length());
assert_eq!(value.encoded_len().unwrap(), TestMessage::encoded_length());
@@ -622,7 +644,7 @@ mod tests {
fn roundtrip_variable_length_u8() {
let values = messages_vec();
let mut bytes = vec![];
- encode_u8_items(&mut bytes, &(), &values);
+ encode_u8_items(&mut bytes, &(), &values).unwrap();
assert_eq!(
bytes.len(),
@@ -640,7 +662,7 @@ mod tests {
fn roundtrip_variable_length_u16() {
let values = messages_vec();
let mut bytes = vec![];
- encode_u16_items(&mut bytes, &(), &values);
+ encode_u16_items(&mut bytes, &(), &values).unwrap();
assert_eq!(
bytes.len(),
@@ -661,7 +683,7 @@ mod tests {
fn roundtrip_variable_length_u24() {
let values = messages_vec();
let mut bytes = vec![];
- encode_u24_items(&mut bytes, &(), &values);
+ encode_u24_items(&mut bytes, &(), &values).unwrap();
assert_eq!(
bytes.len(),
@@ -682,7 +704,7 @@ mod tests {
fn roundtrip_variable_length_u32() {
let values = messages_vec();
let mut bytes = Vec::new();
- encode_u32_items(&mut bytes, &(), &values);
+ encode_u32_items(&mut bytes, &(), &values).unwrap();
assert_eq!(bytes.len(), 4 + 3 * TestMessage::encoded_length());
@@ -697,6 +719,21 @@ mod tests {
}
#[test]
+ fn decode_too_short() {
+ let values = messages_vec();
+ let mut bytes = Vec::new();
+ encode_u32_items(&mut bytes, &(), &values).unwrap();
+
+ let error =
+ decode_u32_items::<_, TestMessage>(&(), &mut Cursor::new(&bytes[..3])).unwrap_err();
+ assert_matches!(error, CodecError::Io(e) => assert_eq!(e.kind(), ErrorKind::UnexpectedEof));
+
+ let error =
+ decode_u32_items::<_, TestMessage>(&(), &mut Cursor::new(&bytes[..4])).unwrap_err();
+ assert_matches!(error, CodecError::LengthPrefixTooBig(_));
+ }
+
+ #[test]
fn decode_items_overflow() {
let encoded = vec![1u8];
@@ -724,11 +761,56 @@ mod tests {
#[test]
fn length_hint_correctness() {
- assert_eq!(().encoded_len().unwrap(), ().get_encoded().len());
- assert_eq!(0u8.encoded_len().unwrap(), 0u8.get_encoded().len());
- assert_eq!(0u16.encoded_len().unwrap(), 0u16.get_encoded().len());
- assert_eq!(U24(0).encoded_len().unwrap(), U24(0).get_encoded().len());
- assert_eq!(0u32.encoded_len().unwrap(), 0u32.get_encoded().len());
- assert_eq!(0u64.encoded_len().unwrap(), 0u64.get_encoded().len());
+ assert_eq!(().encoded_len().unwrap(), ().get_encoded().unwrap().len());
+ assert_eq!(0u8.encoded_len().unwrap(), 0u8.get_encoded().unwrap().len());
+ assert_eq!(
+ 0u16.encoded_len().unwrap(),
+ 0u16.get_encoded().unwrap().len()
+ );
+ assert_eq!(
+ U24(0).encoded_len().unwrap(),
+ U24(0).get_encoded().unwrap().len()
+ );
+ assert_eq!(
+ 0u32.encoded_len().unwrap(),
+ 0u32.get_encoded().unwrap().len()
+ );
+ assert_eq!(
+ 0u64.encoded_len().unwrap(),
+ 0u64.get_encoded().unwrap().len()
+ );
+ }
+
+ #[test]
+ fn get_decoded_leftover() {
+ let encoded_good = [1, 2, 3, 4];
+ assert_matches!(u32::get_decoded(&encoded_good).unwrap(), 0x01020304u32);
+
+ let encoded_bad = [1, 2, 3, 4, 5];
+ let error = u32::get_decoded(&encoded_bad).unwrap_err();
+ assert_matches!(error, CodecError::BytesLeftOver(1));
+ }
+
+ #[test]
+ fn encoded_len_backwards_compatibility() {
+ struct MyMessage;
+
+ impl Encode for MyMessage {
+ fn encode(&self, bytes: &mut Vec<u8>) -> Result<(), CodecError> {
+ bytes.extend_from_slice(b"Hello, world");
+ Ok(())
+ }
+ }
+
+ assert_eq!(MyMessage.encoded_len(), None);
+
+ assert_eq!(MyMessage.get_encoded().unwrap(), b"Hello, world");
+ }
+
+ #[test]
+ fn encode_length_prefix_overflow() {
+ let mut bytes = Vec::new();
+ let error = encode_u8_items(&mut bytes, &(), &[1u8; u8::MAX as usize + 1]).unwrap_err();
+ assert_matches!(error, CodecError::LengthPrefixOverflow);
}
}
diff --git a/third_party/rust/prio/src/dp.rs b/third_party/rust/prio/src/dp.rs
index 506676dbb9..6ed4f2afdf 100644
--- a/third_party/rust/prio/src/dp.rs
+++ b/third_party/rust/prio/src/dp.rs
@@ -20,6 +20,7 @@ use serde::{Deserialize, Serialize};
/// Errors propagated by methods in this module.
#[derive(Debug, thiserror::Error)]
+#[non_exhaustive]
pub enum DpError {
/// Tried to use an invalid float as privacy parameter.
#[error(
diff --git a/third_party/rust/prio/src/dp/distributions.rs b/third_party/rust/prio/src/dp/distributions.rs
index ba0270df9c..5fc42f96ec 100644
--- a/third_party/rust/prio/src/dp/distributions.rs
+++ b/third_party/rust/prio/src/dp/distributions.rs
@@ -292,7 +292,7 @@ mod tests {
use super::*;
use crate::dp::Rational;
- use crate::vdaf::xof::SeedStreamSha3;
+ use crate::vdaf::xof::SeedStreamTurboShake128;
use num_bigint::{BigUint, Sign, ToBigInt, ToBigUint};
use num_traits::{One, Signed, ToPrimitive};
@@ -306,15 +306,15 @@ mod tests {
DiscreteGaussian::new(Ratio::<BigUint>::from_integer(BigUint::from(5u8))).unwrap();
// check samples are consistent
- let mut rng = SeedStreamSha3::from_seed([0u8; 16]);
+ let mut rng = SeedStreamTurboShake128::from_seed([0u8; 16]);
let samples: Vec<i8> = (0..10)
.map(|_| i8::try_from(sampler.sample(&mut rng)).unwrap())
.collect();
let samples1: Vec<i8> = (0..10)
.map(|_| i8::try_from(sampler.sample(&mut rng)).unwrap())
.collect();
- assert_eq!(samples, vec![-3, -11, -3, 5, 1, 5, 2, 2, 1, 18]);
- assert_eq!(samples1, vec![4, -4, -5, -2, 0, -5, -3, 1, 1, -2]);
+ assert_eq!(samples, vec![0, -3, -2, 3, 2, -1, -5, 4, -7, -5]);
+ assert_eq!(samples1, vec![2, 7, -8, -3, 1, -3, -3, 6, -3, -1]);
}
#[test]
@@ -325,7 +325,7 @@ mod tests {
// sample from a manually created distribution
let sampler1 =
DiscreteGaussian::new(Ratio::<BigUint>::from_integer(BigUint::from(4u8))).unwrap();
- let mut rng = SeedStreamSha3::from_seed([0u8; 16]);
+ let mut rng = SeedStreamTurboShake128::from_seed([0u8; 16]);
let samples1: Vec<i8> = (0..10)
.map(|_| i8::try_from(sampler1.sample(&mut rng)).unwrap())
.collect();
@@ -337,7 +337,7 @@ mod tests {
let sampler2 = zcdp
.create_distribution(Ratio::<BigUint>::from_integer(1u8.into()))
.unwrap();
- let mut rng2 = SeedStreamSha3::from_seed([0u8; 16]);
+ let mut rng2 = SeedStreamTurboShake128::from_seed([0u8; 16]);
let samples2: Vec<i8> = (0..10)
.map(|_| i8::try_from(sampler2.sample(&mut rng2)).unwrap())
.collect();
@@ -485,7 +485,7 @@ mod tests {
.unwrap();
// collect that number of samples
- let mut rng = SeedStreamSha3::from_seed([0u8; 16]);
+ let mut rng = SeedStreamTurboShake128::from_seed([0u8; 16]);
let samples: Vec<BigInt> = (1..n_samples)
.map(|_| {
sample_discrete_gaussian(&Ratio::<BigUint>::from_integer(sigma.clone()), &mut rng)
@@ -519,7 +519,7 @@ mod tests {
#[test]
fn empirical_test_gauss() {
[100, 2000, 20000].iter().for_each(|p| {
- let mut rng = SeedStreamSha3::from_seed([0u8; 16]);
+ let mut rng = SeedStreamTurboShake128::from_seed([0u8; 16]);
let sampler = || {
sample_discrete_gaussian(
&Ratio::<BigUint>::from_integer((*p).to_biguint().unwrap()),
@@ -541,7 +541,7 @@ mod tests {
#[test]
fn empirical_test_bernoulli_mean() {
[2u8, 5u8, 7u8, 9u8].iter().for_each(|p| {
- let mut rng = SeedStreamSha3::from_seed([0u8; 16]);
+ let mut rng = SeedStreamTurboShake128::from_seed([0u8; 16]);
let sampler = || {
if sample_bernoulli(
&Ratio::<BigUint>::new(BigUint::one(), (*p).into()),
@@ -565,7 +565,7 @@ mod tests {
#[test]
fn empirical_test_geometric_mean() {
[2u8, 5u8, 7u8, 9u8].iter().for_each(|p| {
- let mut rng = SeedStreamSha3::from_seed([0u8; 16]);
+ let mut rng = SeedStreamTurboShake128::from_seed([0u8; 16]);
let sampler = || {
sample_geometric_exp(
&Ratio::<BigUint>::new(BigUint::one(), (*p).into()),
@@ -588,7 +588,7 @@ mod tests {
#[test]
fn empirical_test_laplace_mean() {
[2u8, 5u8, 7u8, 9u8].iter().for_each(|p| {
- let mut rng = SeedStreamSha3::from_seed([0u8; 16]);
+ let mut rng = SeedStreamTurboShake128::from_seed([0u8; 16]);
let sampler = || {
sample_discrete_laplace(
&Ratio::<BigUint>::new(BigUint::one(), (*p).into()),
diff --git a/third_party/rust/prio/src/fft.rs b/third_party/rust/prio/src/fft.rs
index cac59a89ea..612013eb45 100644
--- a/third_party/rust/prio/src/fft.rs
+++ b/third_party/rust/prio/src/fft.rs
@@ -10,6 +10,7 @@ use std::convert::TryFrom;
/// An error returned by an FFT operation.
#[derive(Debug, PartialEq, Eq, thiserror::Error)]
+#[non_exhaustive]
pub enum FftError {
/// The output is too small.
#[error("output slice is smaller than specified size")]
diff --git a/third_party/rust/prio/src/field.rs b/third_party/rust/prio/src/field.rs
index fb931de2d3..e6cd5c105d 100644
--- a/third_party/rust/prio/src/field.rs
+++ b/third_party/rust/prio/src/field.rs
@@ -7,7 +7,6 @@
//! [`FftFriendlyFieldElement`], and have an associated element called the "generator" that
//! generates a multiplicative subgroup of order `2^n` for some `n`.
-#[cfg(feature = "crypto-dependencies")]
use crate::prng::{Prng, PrngError};
use crate::{
codec::{CodecError, Decode, Encode},
@@ -25,8 +24,8 @@ use std::{
io::{Cursor, Read},
marker::PhantomData,
ops::{
- Add, AddAssign, BitAnd, ControlFlow, Div, DivAssign, Mul, MulAssign, Neg, Shl, Shr, Sub,
- SubAssign,
+ Add, AddAssign, BitAnd, ControlFlow, Div, DivAssign, Mul, MulAssign, Neg, Range, Shl, Shr,
+ Sub, SubAssign,
},
};
use subtle::{Choice, ConditionallyNegatable, ConditionallySelectable, ConstantTimeEq};
@@ -39,6 +38,7 @@ pub use field255::Field255;
/// Possible errors from finite field operations.
#[derive(Debug, thiserror::Error)]
+#[non_exhaustive]
pub enum FieldError {
/// Input sizes do not match.
#[error("input sizes do not match")]
@@ -46,19 +46,24 @@ pub enum FieldError {
/// Returned when decoding a [`FieldElement`] from a too-short byte string.
#[error("short read from bytes")]
ShortRead,
- /// Returned when decoding a [`FieldElement`] from a byte string that encodes an integer greater
- /// than or equal to the field modulus.
- #[error("read from byte slice exceeds modulus")]
+ /// Returned when converting an integer to a [`FieldElement`] if the integer is greater than or
+ /// equal to the field modulus.
+ #[error("input value exceeds modulus")]
ModulusOverflow,
/// Error while performing I/O.
#[error("I/O error")]
Io(#[from] std::io::Error),
/// Error encoding or decoding a field.
#[error("Codec error")]
- Codec(#[from] CodecError),
+ #[deprecated]
+ Codec(CodecError),
/// Error converting to [`FieldElementWithInteger::Integer`].
#[error("Integer TryFrom error")]
IntegerTryFrom,
+ /// Returned when encoding an integer to "bitvector representation", or decoding from the same,
+ /// if the number of bits is larger than the bit length of the field's modulus.
+ #[error("bit vector length exceeds modulus bit length")]
+ BitVectorTooLong,
}
/// Objects with this trait represent an element of `GF(p)` for some prime `p`.
@@ -100,8 +105,8 @@ pub trait FieldElement:
fn inv(&self) -> Self;
/// Interprets the next [`Self::ENCODED_SIZE`] bytes from the input slice as an element of the
- /// field. The `m` most significant bits are cleared, where `m` is equal to the length of
- /// [`Self::Integer`] in bits minus the length of the modulus in bits.
+ /// field. Any of the most significant bits beyond the bit length of the modulus will be
+ /// cleared, in order to minimize the amount of rejection sampling needed.
///
/// # Errors
///
@@ -110,9 +115,9 @@ pub trait FieldElement:
///
/// # Warnings
///
- /// This function should only be used within [`prng::Prng`] to convert a random byte string into
- /// a field element. Use [`Self::decode`] to deserialize field elements. Use
- /// [`field::rand`] or [`prng::Prng`] to randomly generate field elements.
+ /// This function should only be used internally to convert a random byte string into
+ /// a field element. Use [`Decode::decode`] to deserialize field elements. Use
+ /// [`random_vector`] to randomly generate field elements.
#[doc(hidden)]
fn try_from_random(bytes: &[u8]) -> Result<Self, FieldError>;
@@ -129,9 +134,10 @@ pub trait FieldElement:
/// Ideally we would implement `From<&[F: FieldElement]> for Vec<u8>` or the corresponding
/// `Into`, but the orphan rule and the stdlib's blanket implementations of `Into` make this
/// impossible.
+ #[deprecated]
fn slice_into_byte_vec(values: &[Self]) -> Vec<u8> {
let mut vec = Vec::with_capacity(values.len() * Self::ENCODED_SIZE);
- encode_fieldvec(values, &mut vec);
+ encode_fieldvec(values, &mut vec).unwrap();
vec
}
@@ -149,18 +155,49 @@ pub trait FieldElement:
/// Ideally we would implement `From<&[u8]> for Vec<F: FieldElement>` or the corresponding
/// `Into`, but the orphan rule and the stdlib's blanket implementations of `Into` make this
/// impossible.
+ #[deprecated]
fn byte_slice_into_vec(bytes: &[u8]) -> Result<Vec<Self>, FieldError> {
if bytes.len() % Self::ENCODED_SIZE != 0 {
return Err(FieldError::ShortRead);
}
let mut vec = Vec::with_capacity(bytes.len() / Self::ENCODED_SIZE);
for chunk in bytes.chunks_exact(Self::ENCODED_SIZE) {
- vec.push(Self::get_decoded(chunk)?);
+ #[allow(deprecated)]
+ vec.push(Self::get_decoded(chunk).map_err(FieldError::Codec)?);
}
Ok(vec)
}
}
+/// An integer type that accompanies a finite field. Integers and field elements may be converted
+/// back and forth via the natural map between residue classes modulo 'p' and integers between 0
+/// and p - 1.
+pub trait Integer:
+ Debug
+ + Eq
+ + Ord
+ + BitAnd<Output = Self>
+ + Div<Output = Self>
+ + Shl<usize, Output = Self>
+ + Shr<usize, Output = Self>
+ + Add<Output = Self>
+ + Sub<Output = Self>
+ + TryFrom<usize, Error = Self::TryFromUsizeError>
+ + TryInto<u64, Error = Self::TryIntoU64Error>
+{
+ /// The error returned if converting `usize` to this integer type fails.
+ type TryFromUsizeError: std::error::Error;
+
+ /// The error returned if converting this integer type to a `u64` fails.
+ type TryIntoU64Error: std::error::Error;
+
+ /// Returns zero.
+ fn zero() -> Self;
+
+ /// Returns one.
+ fn one() -> Self;
+}
+
/// Extension trait for field elements that can be converted back and forth to an integer type.
///
/// The `Integer` associated type is an integer (primitive or otherwise) that supports various
@@ -168,104 +205,95 @@ pub trait FieldElement:
/// integer type. This trait also defines methods on field elements, `pow` and `modulus`, that make
/// use of the associated integer type.
pub trait FieldElementWithInteger: FieldElement + From<Self::Integer> {
- /// The error returned if converting `usize` to an `Integer` fails.
- type IntegerTryFromError: std::error::Error;
-
- /// The error returned if converting an `Integer` to a `u64` fails.
- type TryIntoU64Error: std::error::Error;
-
/// The integer representation of a field element.
- type Integer: Copy
- + Debug
- + Eq
- + Ord
- + BitAnd<Output = Self::Integer>
- + Div<Output = Self::Integer>
- + Shl<usize, Output = Self::Integer>
- + Shr<usize, Output = Self::Integer>
- + Add<Output = Self::Integer>
- + Sub<Output = Self::Integer>
- + From<Self>
- + TryFrom<usize, Error = Self::IntegerTryFromError>
- + TryInto<u64, Error = Self::TryIntoU64Error>;
+ type Integer: Integer + From<Self> + Copy;
/// Modular exponentation, i.e., `self^exp (mod p)`.
fn pow(&self, exp: Self::Integer) -> Self;
/// Returns the prime modulus `p`.
fn modulus() -> Self::Integer;
-}
-
-/// Methods common to all `FieldElementWithInteger` implementations that are private to the crate.
-pub(crate) trait FieldElementWithIntegerExt: FieldElementWithInteger {
- /// Encode `input` as bitvector of elements of `Self`. Output is written into the `output` slice.
- /// If `output.len()` is smaller than the number of bits required to respresent `input`,
- /// an error is returned.
- ///
- /// # Arguments
+ /// Encode the integer `input` as a sequence of bits in two's complement representation, least
+ /// significant bit first, and then map each bit to a field element.
///
- /// * `input` - The field element to encode
- /// * `output` - The slice to write the encoded bits into. Least signicant bit comes first
- fn fill_with_bitvector_representation(
- input: &Self::Integer,
- output: &mut [Self],
- ) -> Result<(), FieldError> {
- // Create a mutable copy of `input`. In each iteration of the following loop we take the
- // least significant bit, and shift input to the right by one bit.
- let mut i = *input;
-
- let one = Self::Integer::from(Self::one());
- for bit in output.iter_mut() {
- let w = Self::from(i & one);
- *bit = w;
- i = i >> 1;
+ /// Returns an error if `input` cannot be represented with `bits` many bits, or if `bits`
+ /// is larger than the bit width of the field's modulus.
+ fn encode_as_bitvector(
+ input: Self::Integer,
+ bits: usize,
+ ) -> Result<BitvectorRepresentationIter<Self>, FieldError> {
+ // Check if `bits` is too large for this field.
+ if !Self::valid_integer_bitlength(bits) {
+ return Err(FieldError::BitVectorTooLong);
}
- // If `i` is still not zero, this means that it cannot be encoded by `bits` bits.
- if i != Self::Integer::from(Self::zero()) {
+ // Check if the input value can be represented in the requested number of bits by shifting
+ // it. The above check on `bits` ensures this shift won't panic due to the shift width
+ // being too large.
+ if input >> bits != Self::Integer::zero() {
return Err(FieldError::InputSizeMismatch);
}
- Ok(())
+ Ok(BitvectorRepresentationIter {
+ inner: 0..bits,
+ input,
+ })
}
- /// Encode `input` as `bits`-bit vector of elements of `Self` if it's small enough
- /// to be represented with that many bits.
- ///
- /// # Arguments
+ /// Inverts the encoding done by [`Self::encode_as_bitvector`], and returns a single field
+ /// element.
///
- /// * `input` - The field element to encode
- /// * `bits` - The number of bits to use for the encoding
- fn encode_into_bitvector_representation(
- input: &Self::Integer,
- bits: usize,
- ) -> Result<Vec<Self>, FieldError> {
- let mut result = vec![Self::zero(); bits];
- Self::fill_with_bitvector_representation(input, &mut result)?;
- Ok(result)
- }
-
- /// Decode the bitvector-represented value `input` into a simple representation as a single
- /// field element.
+ /// This performs an inner product between the input vector of field elements and successive
+ /// powers of two (starting with 2^0 = 1). If the input came from [`Self::encode_as_bitvector`],
+ /// then the result will be equal to the originally encoded integer, projected into the field.
///
- /// # Errors
+ /// Note that this decoding operation is linear, so it can be applied to secret shares of an
+ /// encoded integer, and if the results are summed up, it will be equal to the encoded integer.
///
- /// This function errors if `2^input.len() - 1` does not fit into the field `Self`.
- fn decode_from_bitvector_representation(input: &[Self]) -> Result<Self, FieldError> {
- let fi_one = Self::Integer::from(Self::one());
-
+ /// Returns an error if the length of the input is larger than the bit width of the field's
+ /// modulus.
+ fn decode_bitvector(input: &[Self]) -> Result<Self, FieldError> {
if !Self::valid_integer_bitlength(input.len()) {
- return Err(FieldError::ModulusOverflow);
+ return Err(FieldError::BitVectorTooLong);
}
let mut decoded = Self::zero();
- for (l, bit) in input.iter().enumerate() {
- let w = fi_one << l;
- decoded += Self::from(w) * *bit;
+ let one = Self::one();
+ let two = one + one;
+ let mut power_of_two = one;
+ for value in input.iter() {
+ decoded += *value * power_of_two;
+ power_of_two *= two;
}
Ok(decoded)
}
+}
+
+/// This iterator returns a sequence of field elements that are equal to zero or one, representing
+/// some integer in two's complement form. See [`FieldElementWithInteger::encode_as_bitvector`].
+// Note that this is implemented with a separate struct, instead of using the map combinator,
+// because return_position_impl_trait_in_trait is not yet stable.
+#[derive(Debug, Clone)]
+pub struct BitvectorRepresentationIter<F: FieldElementWithInteger> {
+ inner: Range<usize>,
+ input: F::Integer,
+}
+
+impl<F> Iterator for BitvectorRepresentationIter<F>
+where
+ F: FieldElementWithInteger,
+{
+ type Item = F;
+
+ #[inline]
+ fn next(&mut self) -> Option<Self::Item> {
+ let bit_offset = self.inner.next()?;
+ Some(F::from((self.input >> bit_offset) & F::Integer::one()))
+ }
+}
+/// Methods common to all `FieldElementWithInteger` implementations that are private to the crate.
+pub(crate) trait FieldElementWithIntegerExt: FieldElementWithInteger {
/// Interpret `i` as [`Self::Integer`] if it's representable in that type and smaller than the
/// field modulus.
fn valid_integer_try_from<N>(i: N) -> Result<Self::Integer, FieldError>
@@ -285,7 +313,7 @@ pub(crate) trait FieldElementWithIntegerExt: FieldElementWithInteger {
if bits >= 8 * Self::ENCODED_SIZE {
return false;
}
- if Self::modulus() >> bits != Self::Integer::from(Self::zero()) {
+ if Self::modulus() >> bits != Self::Integer::zero() {
return true;
}
false
@@ -382,7 +410,7 @@ macro_rules! make_field {
///
/// As an invariant, this integer representing the field element in the Montgomery domain
/// must be less than the field modulus, `p`.
- #[derive(Clone, Copy, PartialOrd, Ord, Default)]
+ #[derive(Clone, Copy, Default)]
pub struct $elem(u128);
impl $elem {
@@ -640,9 +668,10 @@ macro_rules! make_field {
}
impl Encode for $elem {
- fn encode(&self, bytes: &mut Vec<u8>) {
+ fn encode(&self, bytes: &mut Vec<u8>) -> Result<(), CodecError> {
let slice = <[u8; $elem::ENCODED_SIZE]>::from(*self);
bytes.extend_from_slice(&slice);
+ Ok(())
}
fn encoded_len(&self) -> Option<usize> {
@@ -683,8 +712,6 @@ macro_rules! make_field {
impl FieldElementWithInteger for $elem {
type Integer = $int;
- type IntegerTryFromError = <Self::Integer as TryFrom<usize>>::Error;
- type TryIntoU64Error = <Self::Integer as TryInto<u64>>::Error;
fn pow(&self, exp: Self::Integer) -> Self {
// FieldParameters::pow() relies on mul(), and will always return a value less
@@ -717,6 +744,45 @@ macro_rules! make_field {
};
}
+impl Integer for u32 {
+ type TryFromUsizeError = <Self as TryFrom<usize>>::Error;
+ type TryIntoU64Error = <Self as TryInto<u64>>::Error;
+
+ fn zero() -> Self {
+ 0
+ }
+
+ fn one() -> Self {
+ 1
+ }
+}
+
+impl Integer for u64 {
+ type TryFromUsizeError = <Self as TryFrom<usize>>::Error;
+ type TryIntoU64Error = <Self as TryInto<u64>>::Error;
+
+ fn zero() -> Self {
+ 0
+ }
+
+ fn one() -> Self {
+ 1
+ }
+}
+
+impl Integer for u128 {
+ type TryFromUsizeError = <Self as TryFrom<usize>>::Error;
+ type TryIntoU64Error = <Self as TryInto<u64>>::Error;
+
+ fn zero() -> Self {
+ 0
+ }
+
+ fn one() -> Self {
+ 1
+ }
+}
+
make_field!(
/// Same as Field32, but encoded in little endian for compatibility with Prio v2.
FieldPrio2,
@@ -761,7 +827,7 @@ pub(crate) fn merge_vector<F: FieldElement>(
}
/// Outputs an additive secret sharing of the input.
-#[cfg(all(feature = "crypto-dependencies", test))]
+#[cfg(test)]
pub(crate) fn split_vector<F: FieldElement>(
inp: &[F],
num_shares: usize,
@@ -785,18 +851,20 @@ pub(crate) fn split_vector<F: FieldElement>(
}
/// Generate a vector of uniformly distributed random field elements.
-#[cfg(feature = "crypto-dependencies")]
-#[cfg_attr(docsrs, doc(cfg(feature = "crypto-dependencies")))]
pub fn random_vector<F: FieldElement>(len: usize) -> Result<Vec<F>, PrngError> {
Ok(Prng::new()?.take(len).collect())
}
/// `encode_fieldvec` serializes a type that is equivalent to a vector of field elements.
#[inline(always)]
-pub(crate) fn encode_fieldvec<F: FieldElement, T: AsRef<[F]>>(val: T, bytes: &mut Vec<u8>) {
+pub(crate) fn encode_fieldvec<F: FieldElement, T: AsRef<[F]>>(
+ val: T,
+ bytes: &mut Vec<u8>,
+) -> Result<(), CodecError> {
for elem in val.as_ref() {
- elem.encode(bytes);
+ elem.encode(bytes)?;
}
+ Ok(())
}
/// `decode_fieldvec` deserializes some number of field elements from a cursor, and advances the
@@ -822,16 +890,14 @@ pub(crate) fn decode_fieldvec<F: FieldElement>(
#[cfg(test)]
pub(crate) mod test_utils {
- use super::{FieldElement, FieldElementWithInteger};
+ use super::{FieldElement, FieldElementWithInteger, Integer};
use crate::{codec::CodecError, field::FieldError, prng::Prng};
use assert_matches::assert_matches;
use std::{
collections::hash_map::DefaultHasher,
- convert::{TryFrom, TryInto},
- fmt::Debug,
+ convert::TryFrom,
hash::{Hash, Hasher},
io::Cursor,
- ops::{Add, BitAnd, Div, Shl, Shr, Sub},
};
/// A test-only copy of `FieldElementWithInteger`.
@@ -842,42 +908,30 @@ pub(crate) mod test_utils {
/// requires the `Integer` associated type satisfy `Clone`, not `Copy`, so that it may be used
/// with arbitrary precision integer implementations.
pub(crate) trait TestFieldElementWithInteger:
- FieldElement + From<Self::Integer>
+ FieldElement + From<Self::TestInteger>
{
type IntegerTryFromError: std::error::Error;
type TryIntoU64Error: std::error::Error;
- type Integer: Clone
- + Debug
- + Eq
- + Ord
- + BitAnd<Output = Self::Integer>
- + Div<Output = Self::Integer>
- + Shl<usize, Output = Self::Integer>
- + Shr<usize, Output = Self::Integer>
- + Add<Output = Self::Integer>
- + Sub<Output = Self::Integer>
- + From<Self>
- + TryFrom<usize, Error = Self::IntegerTryFromError>
- + TryInto<u64, Error = Self::TryIntoU64Error>;
-
- fn pow(&self, exp: Self::Integer) -> Self;
-
- fn modulus() -> Self::Integer;
+ type TestInteger: Integer + From<Self> + Clone;
+
+ fn pow(&self, exp: Self::TestInteger) -> Self;
+
+ fn modulus() -> Self::TestInteger;
}
impl<F> TestFieldElementWithInteger for F
where
F: FieldElementWithInteger,
{
- type IntegerTryFromError = <F as FieldElementWithInteger>::IntegerTryFromError;
- type TryIntoU64Error = <F as FieldElementWithInteger>::TryIntoU64Error;
- type Integer = <F as FieldElementWithInteger>::Integer;
+ type IntegerTryFromError = <F::Integer as Integer>::TryFromUsizeError;
+ type TryIntoU64Error = <F::Integer as Integer>::TryIntoU64Error;
+ type TestInteger = F::Integer;
- fn pow(&self, exp: Self::Integer) -> Self {
+ fn pow(&self, exp: Self::TestInteger) -> Self {
<F as FieldElementWithInteger>::pow(self, exp)
}
- fn modulus() -> Self::Integer {
+ fn modulus() -> Self::TestInteger {
<F as FieldElementWithInteger>::modulus()
}
}
@@ -885,11 +939,11 @@ pub(crate) mod test_utils {
pub(crate) fn field_element_test_common<F: TestFieldElementWithInteger>() {
let mut prng: Prng<F, _> = Prng::new().unwrap();
let int_modulus = F::modulus();
- let int_one = F::Integer::try_from(1).unwrap();
+ let int_one = F::TestInteger::try_from(1).unwrap();
let zero = F::zero();
let one = F::one();
- let two = F::from(F::Integer::try_from(2).unwrap());
- let four = F::from(F::Integer::try_from(4).unwrap());
+ let two = F::from(F::TestInteger::try_from(2).unwrap());
+ let four = F::from(F::TestInteger::try_from(4).unwrap());
// add
assert_eq!(F::from(int_modulus.clone() - int_one.clone()) + one, zero);
@@ -943,10 +997,22 @@ pub(crate) mod test_utils {
assert_eq!(a, c);
// integer conversion
- assert_eq!(F::Integer::from(zero), F::Integer::try_from(0).unwrap());
- assert_eq!(F::Integer::from(one), F::Integer::try_from(1).unwrap());
- assert_eq!(F::Integer::from(two), F::Integer::try_from(2).unwrap());
- assert_eq!(F::Integer::from(four), F::Integer::try_from(4).unwrap());
+ assert_eq!(
+ F::TestInteger::from(zero),
+ F::TestInteger::try_from(0).unwrap()
+ );
+ assert_eq!(
+ F::TestInteger::from(one),
+ F::TestInteger::try_from(1).unwrap()
+ );
+ assert_eq!(
+ F::TestInteger::from(two),
+ F::TestInteger::try_from(2).unwrap()
+ );
+ assert_eq!(
+ F::TestInteger::from(four),
+ F::TestInteger::try_from(4).unwrap()
+ );
// serialization
let test_inputs = vec![
@@ -957,7 +1023,7 @@ pub(crate) mod test_utils {
];
for want in test_inputs.iter() {
let mut bytes = vec![];
- want.encode(&mut bytes);
+ want.encode(&mut bytes).unwrap();
assert_eq!(bytes.len(), F::ENCODED_SIZE);
assert_eq!(want.encoded_len().unwrap(), F::ENCODED_SIZE);
@@ -966,9 +1032,12 @@ pub(crate) mod test_utils {
assert_eq!(got, *want);
}
- let serialized_vec = F::slice_into_byte_vec(&test_inputs);
- let deserialized = F::byte_slice_into_vec(&serialized_vec).unwrap();
- assert_eq!(deserialized, test_inputs);
+ #[allow(deprecated)]
+ {
+ let serialized_vec = F::slice_into_byte_vec(&test_inputs);
+ let deserialized = F::byte_slice_into_vec(&serialized_vec).unwrap();
+ assert_eq!(deserialized, test_inputs);
+ }
let test_input = prng.get();
let json = serde_json::to_string(&test_input).unwrap();
@@ -981,13 +1050,16 @@ pub(crate) mod test_utils {
element.as_u64().unwrap();
}
- let err = F::byte_slice_into_vec(&[0]).unwrap_err();
- assert_matches!(err, FieldError::ShortRead);
+ #[allow(deprecated)]
+ {
+ let err = F::byte_slice_into_vec(&[0]).unwrap_err();
+ assert_matches!(err, FieldError::ShortRead);
- let err = F::byte_slice_into_vec(&vec![0xffu8; F::ENCODED_SIZE]).unwrap_err();
- assert_matches!(err, FieldError::Codec(CodecError::Other(err)) => {
- assert_matches!(err.downcast_ref::<FieldError>(), Some(FieldError::ModulusOverflow));
- });
+ let err = F::byte_slice_into_vec(&vec![0xffu8; F::ENCODED_SIZE]).unwrap_err();
+ assert_matches!(err, FieldError::Codec(CodecError::Other(err)) => {
+ assert_matches!(err.downcast_ref::<FieldError>(), Some(FieldError::ModulusOverflow));
+ });
+ }
let insufficient = vec![0u8; F::ENCODED_SIZE - 1];
let err = F::try_from(insufficient.as_ref()).unwrap_err();
@@ -1004,7 +1076,7 @@ pub(crate) mod test_utils {
// various products that should be equal have the same hash. Three is chosen as a generator
// here because it happens to generate fairly large subgroups of (Z/pZ)* for all four
// primes.
- let three = F::from(F::Integer::try_from(3).unwrap());
+ let three = F::from(F::TestInteger::try_from(3).unwrap());
let mut powers_of_three = Vec::with_capacity(500);
let mut power = one;
for _ in 0..500 {
@@ -1169,22 +1241,19 @@ mod tests {
fn test_encode_into_bitvector() {
let zero = Field128::zero();
let one = Field128::one();
- let zero_enc = Field128::encode_into_bitvector_representation(&0, 4).unwrap();
- let one_enc = Field128::encode_into_bitvector_representation(&1, 4).unwrap();
- let fifteen_enc = Field128::encode_into_bitvector_representation(&15, 4).unwrap();
+ let zero_enc = Field128::encode_as_bitvector(0, 4)
+ .unwrap()
+ .collect::<Vec<_>>();
+ let one_enc = Field128::encode_as_bitvector(1, 4)
+ .unwrap()
+ .collect::<Vec<_>>();
+ let fifteen_enc = Field128::encode_as_bitvector(15, 4)
+ .unwrap()
+ .collect::<Vec<_>>();
assert_eq!(zero_enc, [zero; 4]);
assert_eq!(one_enc, [one, zero, zero, zero]);
assert_eq!(fifteen_enc, [one; 4]);
- Field128::encode_into_bitvector_representation(&16, 4).unwrap_err();
- }
-
- #[test]
- fn test_fill_bitvector() {
- let zero = Field128::zero();
- let one = Field128::one();
- let mut output: Vec<Field128> = vec![zero; 6];
- Field128::fill_with_bitvector_representation(&9, &mut output[1..5]).unwrap();
- assert_eq!(output, [zero, one, zero, zero, one, zero]);
- Field128::fill_with_bitvector_representation(&16, &mut output[1..5]).unwrap_err();
+ Field128::encode_as_bitvector(16, 4).unwrap_err();
+ Field128::encode_as_bitvector(0, 129).unwrap_err();
}
}
diff --git a/third_party/rust/prio/src/field/field255.rs b/third_party/rust/prio/src/field/field255.rs
index fd06a6334a..15a53f8b09 100644
--- a/third_party/rust/prio/src/field/field255.rs
+++ b/third_party/rust/prio/src/field/field255.rs
@@ -271,8 +271,9 @@ impl<'de> Deserialize<'de> for Field255 {
}
impl Encode for Field255 {
- fn encode(&self, bytes: &mut Vec<u8>) {
+ fn encode(&self, bytes: &mut Vec<u8>) -> Result<(), CodecError> {
bytes.extend_from_slice(&<[u8; Self::ENCODED_SIZE]>::from(*self));
+ Ok(())
}
fn encoded_len(&self) -> Option<usize> {
@@ -341,7 +342,7 @@ mod tests {
codec::Encode,
field::{
test_utils::{field_element_test_common, TestFieldElementWithInteger},
- FieldElement, FieldError,
+ FieldElement, FieldError, Integer,
},
};
use assert_matches::assert_matches;
@@ -375,16 +376,30 @@ mod tests {
}
}
+ impl Integer for BigUint {
+ type TryFromUsizeError = <Self as TryFrom<usize>>::Error;
+
+ type TryIntoU64Error = <Self as TryInto<u64>>::Error;
+
+ fn zero() -> Self {
+ Self::new(Vec::new())
+ }
+
+ fn one() -> Self {
+ Self::new(Vec::from([1]))
+ }
+ }
+
impl TestFieldElementWithInteger for Field255 {
- type Integer = BigUint;
- type IntegerTryFromError = <Self::Integer as TryFrom<usize>>::Error;
- type TryIntoU64Error = <Self::Integer as TryInto<u64>>::Error;
+ type TestInteger = BigUint;
+ type IntegerTryFromError = <Self::TestInteger as TryFrom<usize>>::Error;
+ type TryIntoU64Error = <Self::TestInteger as TryInto<u64>>::Error;
- fn pow(&self, _exp: Self::Integer) -> Self {
+ fn pow(&self, _exp: Self::TestInteger) -> Self {
unimplemented!("Field255::pow() is not implemented because it's not needed yet")
}
- fn modulus() -> Self::Integer {
+ fn modulus() -> Self::TestInteger {
MODULUS.clone()
}
}
@@ -415,7 +430,7 @@ mod tests {
#[test]
fn encode_endianness() {
let mut one_encoded = Vec::new();
- Field255::one().encode(&mut one_encoded);
+ Field255::one().encode(&mut one_encoded).unwrap();
assert_eq!(
one_encoded,
[
diff --git a/third_party/rust/prio/src/flp.rs b/third_party/rust/prio/src/flp.rs
index 1912ebab14..5fd956155a 100644
--- a/third_party/rust/prio/src/flp.rs
+++ b/third_party/rust/prio/src/flp.rs
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: MPL-2.0
//! Implementation of the generic Fully Linear Proof (FLP) system specified in
-//! [[draft-irtf-cfrg-vdaf-07]]. This is the main building block of [`Prio3`](crate::vdaf::prio3).
+//! [[draft-irtf-cfrg-vdaf-08]]. This is the main building block of [`Prio3`](crate::vdaf::prio3).
//!
//! The FLP is derived for any implementation of the [`Type`] trait. Such an implementation
//! specifies a validity circuit that defines the set of valid measurements, as well as the finite
@@ -24,7 +24,7 @@
//!
//! // The prover chooses a measurement.
//! let count = Count::new();
-//! let input: Vec<Field64> = count.encode_measurement(&0).unwrap();
+//! let input: Vec<Field64> = count.encode_measurement(&false).unwrap();
//!
//! // The prover and verifier agree on "joint randomness" used to generate and
//! // check the proof. The application needs to ensure that the prover
@@ -44,7 +44,7 @@
//! assert!(count.decide(&verifier).unwrap());
//! ```
//!
-//! [draft-irtf-cfrg-vdaf-07]: https://datatracker.ietf.org/doc/draft-irtf-cfrg-vdaf/07/
+//! [draft-irtf-cfrg-vdaf-08]: https://datatracker.ietf.org/doc/draft-irtf-cfrg-vdaf/08/
#[cfg(feature = "experimental")]
use crate::dp::DifferentialPrivacyStrategy;
@@ -61,6 +61,7 @@ pub mod types;
/// Errors propagated by methods in this module.
#[derive(Debug, thiserror::Error)]
+#[non_exhaustive]
pub enum FlpError {
/// Calling [`Type::prove`] returned an error.
#[error("prove error: {0}")]
@@ -110,20 +111,12 @@ pub enum FlpError {
/// An error happened during noising.
#[error("differential privacy error: {0}")]
DifferentialPrivacy(#[from] crate::dp::DpError),
-
- /// Unit test error.
- #[cfg(test)]
- #[error("test failed: {0}")]
- Test(String),
}
/// A type. Implementations of this trait specify how a particular kind of measurement is encoded
/// as a vector of field elements and how validity of the encoded measurement is determined.
/// Validity is determined via an arithmetic circuit evaluated over the encoded measurement.
pub trait Type: Sized + Eq + Clone + Debug {
- /// The Prio3 VDAF identifier corresponding to this type.
- const ID: u32;
-
/// The type of raw measurement to be encoded.
type Measurement: Clone + Debug;
@@ -178,7 +171,7 @@ pub trait Type: Sized + Eq + Clone + Debug {
/// use prio::field::{random_vector, FieldElement, Field64};
///
/// let count = Count::new();
- /// let input: Vec<Field64> = count.encode_measurement(&1).unwrap();
+ /// let input: Vec<Field64> = count.encode_measurement(&true).unwrap();
/// let joint_rand = random_vector(count.joint_rand_len()).unwrap();
/// let v = count.valid(&mut count.gadget(), &input, &joint_rand, 1).unwrap();
/// assert_eq!(v, Field64::zero());
@@ -552,6 +545,7 @@ pub trait Type: Sized + Eq + Clone + Debug {
/// A type which supports adding noise to aggregate shares for Server Differential Privacy.
#[cfg(feature = "experimental")]
+#[cfg_attr(docsrs, doc(cfg(feature = "experimental")))]
pub trait TypeWithNoise<S>: Type
where
S: DifferentialPrivacyStrategy,
@@ -754,6 +748,227 @@ pub(crate) fn gadget_poly_len(gadget_degree: usize, wire_poly_len: usize) -> usi
gadget_degree * (wire_poly_len - 1) + 1
}
+/// Utilities for testing FLPs.
+#[cfg(feature = "test-util")]
+#[cfg_attr(docsrs, doc(cfg(feature = "test-util")))]
+pub mod test_utils {
+ use super::*;
+ use crate::field::{random_vector, FieldElement, FieldElementWithInteger};
+
+ /// Various tests for an FLP.
+ #[cfg_attr(docsrs, doc(cfg(feature = "test-util")))]
+ pub struct FlpTest<'a, T: Type> {
+ /// The FLP.
+ pub flp: &'a T,
+
+ /// Optional test name.
+ pub name: Option<&'a str>,
+
+ /// The input to use for the tests.
+ pub input: &'a [T::Field],
+
+ /// If set, the expected result of truncating the input.
+ pub expected_output: Option<&'a [T::Field]>,
+
+ /// Whether the input is expected to be valid.
+ pub expect_valid: bool,
+ }
+
+ impl<T: Type> FlpTest<'_, T> {
+ /// Construct a test and run it. Expect the input to be valid and compare the truncated
+ /// output to the provided value.
+ pub fn expect_valid<const SHARES: usize>(
+ flp: &T,
+ input: &[T::Field],
+ expected_output: &[T::Field],
+ ) {
+ FlpTest {
+ flp,
+ name: None,
+ input,
+ expected_output: Some(expected_output),
+ expect_valid: true,
+ }
+ .run::<SHARES>()
+ }
+
+ /// Construct a test and run it. Expect the input to be invalid.
+ pub fn expect_invalid<const SHARES: usize>(flp: &T, input: &[T::Field]) {
+ FlpTest {
+ flp,
+ name: None,
+ input,
+ expect_valid: false,
+ expected_output: None,
+ }
+ .run::<SHARES>()
+ }
+
+ /// Construct a test and run it. Expect the input to be valid.
+ pub fn expect_valid_no_output<const SHARES: usize>(flp: &T, input: &[T::Field]) {
+ FlpTest {
+ flp,
+ name: None,
+ input,
+ expect_valid: true,
+ expected_output: None,
+ }
+ .run::<SHARES>()
+ }
+
+ /// Run the tests.
+ pub fn run<const SHARES: usize>(&self) {
+ let name = self.name.unwrap_or("unnamed test");
+
+ assert_eq!(
+ self.input.len(),
+ self.flp.input_len(),
+ "{name}: unexpected input length"
+ );
+
+ let mut gadgets = self.flp.gadget();
+ let joint_rand = random_vector(self.flp.joint_rand_len()).unwrap();
+ let prove_rand = random_vector(self.flp.prove_rand_len()).unwrap();
+ let query_rand = random_vector(self.flp.query_rand_len()).unwrap();
+ assert_eq!(
+ self.flp.query_rand_len(),
+ gadgets.len(),
+ "{name}: unexpected number of gadgets"
+ );
+ assert_eq!(
+ self.flp.joint_rand_len(),
+ joint_rand.len(),
+ "{name}: unexpected joint rand length"
+ );
+ assert_eq!(
+ self.flp.prove_rand_len(),
+ prove_rand.len(),
+ "{name}: unexpected prove rand length",
+ );
+ assert_eq!(
+ self.flp.query_rand_len(),
+ query_rand.len(),
+ "{name}: unexpected query rand length",
+ );
+
+ // Run the validity circuit.
+ let v = self
+ .flp
+ .valid(&mut gadgets, self.input, &joint_rand, 1)
+ .unwrap();
+ assert_eq!(
+ v == T::Field::zero(),
+ self.expect_valid,
+ "{name}: unexpected output of valid() returned {v}",
+ );
+
+ // Generate the proof.
+ let proof = self
+ .flp
+ .prove(self.input, &prove_rand, &joint_rand)
+ .unwrap();
+ assert_eq!(
+ proof.len(),
+ self.flp.proof_len(),
+ "{name}: unexpected proof length"
+ );
+
+ // Query the proof.
+ let verifier = self
+ .flp
+ .query(self.input, &proof, &query_rand, &joint_rand, 1)
+ .unwrap();
+ assert_eq!(
+ verifier.len(),
+ self.flp.verifier_len(),
+ "{name}: unexpected verifier length"
+ );
+
+ // Decide if the input is valid.
+ let res = self.flp.decide(&verifier).unwrap();
+ assert_eq!(res, self.expect_valid, "{name}: unexpected decision");
+
+ // Run distributed FLP.
+ let input_shares = split_vector::<_, SHARES>(self.input);
+ let proof_shares = split_vector::<_, SHARES>(&proof);
+ let verifier: Vec<T::Field> = (0..SHARES)
+ .map(|i| {
+ self.flp
+ .query(
+ &input_shares[i],
+ &proof_shares[i],
+ &query_rand,
+ &joint_rand,
+ SHARES,
+ )
+ .unwrap()
+ })
+ .reduce(|mut left, right| {
+ for (x, y) in left.iter_mut().zip(right.iter()) {
+ *x += *y;
+ }
+ left
+ })
+ .unwrap();
+
+ let res = self.flp.decide(&verifier).unwrap();
+ assert_eq!(
+ res, self.expect_valid,
+ "{name}: unexpected distributed decision"
+ );
+
+ // Try verifying various proof mutants.
+ for i in 0..std::cmp::min(proof.len(), 10) {
+ let mut mutated_proof = proof.clone();
+ mutated_proof[i] *= T::Field::from(
+ <T::Field as FieldElementWithInteger>::Integer::try_from(23).unwrap(),
+ );
+ let verifier = self
+ .flp
+ .query(self.input, &mutated_proof, &query_rand, &joint_rand, 1)
+ .unwrap();
+ assert!(
+ !self.flp.decide(&verifier).unwrap(),
+ "{name}: proof mutant {} deemed valid",
+ i
+ );
+ }
+
+ // Try truncating the input.
+ if let Some(ref expected_output) = self.expected_output {
+ let output = self.flp.truncate(self.input.to_vec()).unwrap();
+
+ assert_eq!(
+ output.len(),
+ self.flp.output_len(),
+ "{name}: unexpected output length of truncate()"
+ );
+
+ assert_eq!(
+ &output, expected_output,
+ "{name}: unexpected output of truncate()"
+ );
+ }
+ }
+ }
+
+ fn split_vector<F: FieldElement, const SHARES: usize>(inp: &[F]) -> [Vec<F>; SHARES] {
+ let mut outp = Vec::with_capacity(SHARES);
+ outp.push(inp.to_vec());
+
+ for _ in 1..SHARES {
+ let share: Vec<F> =
+ random_vector(inp.len()).expect("failed to generate a random vector");
+ for (x, y) in outp[0].iter_mut().zip(&share) {
+ *x -= *y;
+ }
+ outp.push(share);
+ }
+
+ outp.try_into().unwrap()
+ }
+}
+
#[cfg(test)]
mod tests {
use super::*;
@@ -825,7 +1040,6 @@ mod tests {
}
impl<F: FftFriendlyFieldElement> Type for TestType<F> {
- const ID: u32 = 0xFFFF0000;
type Measurement = F::Integer;
type AggregateResult = F::Integer;
type Field = F;
@@ -960,7 +1174,6 @@ mod tests {
}
impl<F: FftFriendlyFieldElement> Type for Issue254Type<F> {
- const ID: u32 = 0xFFFF0000;
type Measurement = F::Integer;
type AggregateResult = F::Integer;
type Field = F;
diff --git a/third_party/rust/prio/src/flp/types.rs b/third_party/rust/prio/src/flp/types.rs
index 18c290355c..bca88a36cd 100644
--- a/third_party/rust/prio/src/flp/types.rs
+++ b/third_party/rust/prio/src/flp/types.rs
@@ -9,6 +9,7 @@ use crate::polynomial::poly_range_check;
use std::convert::TryInto;
use std::fmt::{self, Debug};
use std::marker::PhantomData;
+use subtle::Choice;
/// The counter data type. Each measurement is `0` or `1` and the aggregate result is the sum of the measurements (i.e., the total number of `1s`).
#[derive(Clone, PartialEq, Eq)]
pub struct Count<F> {
@@ -37,18 +38,16 @@ impl<F: FftFriendlyFieldElement> Default for Count<F> {
}
impl<F: FftFriendlyFieldElement> Type for Count<F> {
- const ID: u32 = 0x00000000;
- type Measurement = F::Integer;
+ type Measurement = bool;
type AggregateResult = F::Integer;
type Field = F;
- fn encode_measurement(&self, value: &F::Integer) -> Result<Vec<F>, FlpError> {
- let max = F::valid_integer_try_from(1)?;
- if *value > max {
- return Err(FlpError::Encode("Count value must be 0 or 1".to_string()));
- }
-
- Ok(vec![F::from(*value)])
+ fn encode_measurement(&self, value: &bool) -> Result<Vec<F>, FlpError> {
+ Ok(vec![F::conditional_select(
+ &F::zero(),
+ &F::one(),
+ Choice::from(u8::from(*value)),
+ )])
}
fn decode_result(&self, data: &[F], _num_measurements: usize) -> Result<F::Integer, FlpError> {
@@ -140,13 +139,12 @@ impl<F: FftFriendlyFieldElement> Sum<F> {
}
impl<F: FftFriendlyFieldElement> Type for Sum<F> {
- const ID: u32 = 0x00000001;
type Measurement = F::Integer;
type AggregateResult = F::Integer;
type Field = F;
fn encode_measurement(&self, summand: &F::Integer) -> Result<Vec<F>, FlpError> {
- let v = F::encode_into_bitvector_representation(summand, self.bits)?;
+ let v = F::encode_as_bitvector(*summand, self.bits)?.collect();
Ok(v)
}
@@ -174,7 +172,7 @@ impl<F: FftFriendlyFieldElement> Type for Sum<F> {
fn truncate(&self, input: Vec<F>) -> Result<Vec<F>, FlpError> {
self.truncate_call_check(&input)?;
- let res = F::decode_from_bitvector_representation(&input)?;
+ let res = F::decode_bitvector(&input)?;
Ok(vec![res])
}
@@ -239,13 +237,12 @@ impl<F: FftFriendlyFieldElement> Average<F> {
}
impl<F: FftFriendlyFieldElement> Type for Average<F> {
- const ID: u32 = 0xFFFF0000;
type Measurement = F::Integer;
type AggregateResult = f64;
type Field = F;
fn encode_measurement(&self, summand: &F::Integer) -> Result<Vec<F>, FlpError> {
- let v = F::encode_into_bitvector_representation(summand, self.bits)?;
+ let v = F::encode_as_bitvector(*summand, self.bits)?.collect();
Ok(v)
}
@@ -279,7 +276,7 @@ impl<F: FftFriendlyFieldElement> Type for Average<F> {
fn truncate(&self, input: Vec<F>) -> Result<Vec<F>, FlpError> {
self.truncate_call_check(&input)?;
- let res = F::decode_from_bitvector_representation(&input)?;
+ let res = F::decode_bitvector(&input)?;
Ok(vec![res])
}
@@ -380,7 +377,6 @@ where
F: FftFriendlyFieldElement,
S: ParallelSumGadget<F, Mul<F>> + Eq + 'static,
{
- const ID: u32 = 0x00000003;
type Measurement = usize;
type AggregateResult = Vec<F::Integer>;
type Field = F;
@@ -574,7 +570,6 @@ where
F: FftFriendlyFieldElement,
S: ParallelSumGadget<F, Mul<F>> + Eq + 'static,
{
- const ID: u32 = 0x00000002;
type Measurement = Vec<F::Integer>;
type AggregateResult = Vec<F::Integer>;
type Field = F;
@@ -588,18 +583,15 @@ where
)));
}
- let mut flattened = vec![F::zero(); self.flattened_len];
- for (summand, chunk) in measurement
- .iter()
- .zip(flattened.chunks_exact_mut(self.bits))
- {
+ let mut flattened = Vec::with_capacity(self.flattened_len);
+ for summand in measurement.iter() {
if summand > &self.max {
return Err(FlpError::Encode(format!(
"summand exceeds maximum of 2^{}-1",
self.bits
)));
}
- F::fill_with_bitvector_representation(summand, chunk)?;
+ flattened.extend(F::encode_as_bitvector(*summand, self.bits)?);
}
Ok(flattened)
@@ -642,7 +634,7 @@ where
self.truncate_call_check(&input)?;
let mut unflattened = Vec::with_capacity(self.len);
for chunk in input.chunks(self.bits) {
- unflattened.push(F::decode_from_bitvector_representation(chunk)?);
+ unflattened.push(F::decode_bitvector(chunk)?);
}
Ok(unflattened)
}
@@ -783,7 +775,7 @@ mod tests {
use crate::flp::gadgets::ParallelSum;
#[cfg(feature = "multithreaded")]
use crate::flp::gadgets::ParallelSumMultithreaded;
- use crate::flp::types::test_utils::{flp_validity_test, ValidityTestCase};
+ use crate::flp::test_utils::FlpTest;
use std::cmp;
#[test]
@@ -797,7 +789,7 @@ mod tests {
count
.decode_result(
&count
- .truncate(count.encode_measurement(&1).unwrap())
+ .truncate(count.encode_measurement(&true).unwrap())
.unwrap(),
1
)
@@ -806,39 +798,11 @@ mod tests {
);
// Test FLP on valid input.
- flp_validity_test(
- &count,
- &count.encode_measurement(&1).unwrap(),
- &ValidityTestCase::<TestField> {
- expect_valid: true,
- expected_output: Some(vec![one]),
- num_shares: 3,
- },
- )
- .unwrap();
-
- flp_validity_test(
- &count,
- &count.encode_measurement(&0).unwrap(),
- &ValidityTestCase::<TestField> {
- expect_valid: true,
- expected_output: Some(vec![zero]),
- num_shares: 3,
- },
- )
- .unwrap();
+ FlpTest::expect_valid::<3>(&count, &count.encode_measurement(&true).unwrap(), &[one]);
+ FlpTest::expect_valid::<3>(&count, &count.encode_measurement(&false).unwrap(), &[zero]);
// Test FLP on invalid input.
- flp_validity_test(
- &count,
- &[TestField::from(1337)],
- &ValidityTestCase::<TestField> {
- expect_valid: false,
- expected_output: None,
- num_shares: 3,
- },
- )
- .unwrap();
+ FlpTest::expect_invalid::<3>(&count, &[TestField::from(1337)]);
// Try running the validity circuit on an input that's too short.
count.valid(&mut count.gadget(), &[], &[], 1).unwrap_err();
@@ -865,72 +829,22 @@ mod tests {
);
// Test FLP on valid input.
- flp_validity_test(
+ FlpTest::expect_valid::<3>(
&sum,
&sum.encode_measurement(&1337).unwrap(),
- &ValidityTestCase {
- expect_valid: true,
- expected_output: Some(vec![TestField::from(1337)]),
- num_shares: 3,
- },
- )
- .unwrap();
-
- flp_validity_test(
- &Sum::new(0).unwrap(),
- &[],
- &ValidityTestCase::<TestField> {
- expect_valid: true,
- expected_output: Some(vec![zero]),
- num_shares: 3,
- },
- )
- .unwrap();
-
- flp_validity_test(
- &Sum::new(2).unwrap(),
- &[one, zero],
- &ValidityTestCase {
- expect_valid: true,
- expected_output: Some(vec![one]),
- num_shares: 3,
- },
- )
- .unwrap();
-
- flp_validity_test(
+ &[TestField::from(1337)],
+ );
+ FlpTest::expect_valid::<3>(&Sum::new(0).unwrap(), &[], &[zero]);
+ FlpTest::expect_valid::<3>(&Sum::new(2).unwrap(), &[one, zero], &[one]);
+ FlpTest::expect_valid::<3>(
&Sum::new(9).unwrap(),
&[one, zero, one, one, zero, one, one, one, zero],
- &ValidityTestCase::<TestField> {
- expect_valid: true,
- expected_output: Some(vec![TestField::from(237)]),
- num_shares: 3,
- },
- )
- .unwrap();
+ &[TestField::from(237)],
+ );
// Test FLP on invalid input.
- flp_validity_test(
- &Sum::new(3).unwrap(),
- &[one, nine, zero],
- &ValidityTestCase::<TestField> {
- expect_valid: false,
- expected_output: None,
- num_shares: 3,
- },
- )
- .unwrap();
-
- flp_validity_test(
- &Sum::new(5).unwrap(),
- &[zero, zero, zero, zero, nine],
- &ValidityTestCase::<TestField> {
- expect_valid: false,
- expected_output: None,
- num_shares: 3,
- },
- )
- .unwrap();
+ FlpTest::expect_invalid::<3>(&Sum::new(3).unwrap(), &[one, nine, zero]);
+ FlpTest::expect_invalid::<3>(&Sum::new(5).unwrap(), &[zero, zero, zero, zero, nine]);
}
#[test]
@@ -1000,83 +914,29 @@ mod tests {
);
// Test valid inputs.
- flp_validity_test(
+ FlpTest::expect_valid::<3>(
&hist,
&hist.encode_measurement(&0).unwrap(),
- &ValidityTestCase::<TestField> {
- expect_valid: true,
- expected_output: Some(vec![one, zero, zero]),
- num_shares: 3,
- },
- )
- .unwrap();
+ &[one, zero, zero],
+ );
- flp_validity_test(
+ FlpTest::expect_valid::<3>(
&hist,
&hist.encode_measurement(&1).unwrap(),
- &ValidityTestCase::<TestField> {
- expect_valid: true,
- expected_output: Some(vec![zero, one, zero]),
- num_shares: 3,
- },
- )
- .unwrap();
+ &[zero, one, zero],
+ );
- flp_validity_test(
+ FlpTest::expect_valid::<3>(
&hist,
&hist.encode_measurement(&2).unwrap(),
- &ValidityTestCase::<TestField> {
- expect_valid: true,
- expected_output: Some(vec![zero, zero, one]),
- num_shares: 3,
- },
- )
- .unwrap();
+ &[zero, zero, one],
+ );
// Test invalid inputs.
- flp_validity_test(
- &hist,
- &[zero, zero, nine],
- &ValidityTestCase::<TestField> {
- expect_valid: false,
- expected_output: None,
- num_shares: 3,
- },
- )
- .unwrap();
-
- flp_validity_test(
- &hist,
- &[zero, one, one],
- &ValidityTestCase::<TestField> {
- expect_valid: false,
- expected_output: None,
- num_shares: 3,
- },
- )
- .unwrap();
-
- flp_validity_test(
- &hist,
- &[one, one, one],
- &ValidityTestCase::<TestField> {
- expect_valid: false,
- expected_output: None,
- num_shares: 3,
- },
- )
- .unwrap();
-
- flp_validity_test(
- &hist,
- &[zero, zero, zero],
- &ValidityTestCase::<TestField> {
- expect_valid: false,
- expected_output: None,
- num_shares: 3,
- },
- )
- .unwrap();
+ FlpTest::expect_invalid::<3>(&hist, &[zero, zero, nine]);
+ FlpTest::expect_invalid::<3>(&hist, &[zero, one, one]);
+ FlpTest::expect_invalid::<3>(&hist, &[one, one, one]);
+ FlpTest::expect_invalid::<3>(&hist, &[zero, zero, zero]);
}
#[test]
@@ -1104,72 +964,38 @@ mod tests {
for len in 1..10 {
let chunk_length = cmp::max((len as f64).sqrt() as usize, 1);
let sum_vec = f(1, len, chunk_length).unwrap();
- flp_validity_test(
+ FlpTest::expect_valid_no_output::<3>(
&sum_vec,
&sum_vec.encode_measurement(&vec![1; len]).unwrap(),
- &ValidityTestCase::<TestField> {
- expect_valid: true,
- expected_output: Some(vec![one; len]),
- num_shares: 3,
- },
- )
- .unwrap();
+ );
}
let len = 100;
let sum_vec = f(1, len, 10).unwrap();
- flp_validity_test(
+ FlpTest::expect_valid::<3>(
&sum_vec,
&sum_vec.encode_measurement(&vec![1; len]).unwrap(),
- &ValidityTestCase::<TestField> {
- expect_valid: true,
- expected_output: Some(vec![one; len]),
- num_shares: 3,
- },
- )
- .unwrap();
+ &vec![one; len],
+ );
let len = 23;
let sum_vec = f(4, len, 4).unwrap();
- flp_validity_test(
+ FlpTest::expect_valid::<3>(
&sum_vec,
&sum_vec.encode_measurement(&vec![9; len]).unwrap(),
- &ValidityTestCase::<TestField> {
- expect_valid: true,
- expected_output: Some(vec![nine; len]),
- num_shares: 3,
- },
- )
- .unwrap();
+ &vec![nine; len],
+ );
// Test on invalid inputs.
for len in 1..10 {
let chunk_length = cmp::max((len as f64).sqrt() as usize, 1);
let sum_vec = f(1, len, chunk_length).unwrap();
- flp_validity_test(
- &sum_vec,
- &vec![nine; len],
- &ValidityTestCase::<TestField> {
- expect_valid: false,
- expected_output: None,
- num_shares: 3,
- },
- )
- .unwrap();
+ FlpTest::expect_invalid::<3>(&sum_vec, &vec![nine; len]);
}
let len = 23;
let sum_vec = f(2, len, 4).unwrap();
- flp_validity_test(
- &sum_vec,
- &vec![nine; 2 * len],
- &ValidityTestCase::<TestField> {
- expect_valid: false,
- expected_output: None,
- num_shares: 3,
- },
- )
- .unwrap();
+ FlpTest::expect_invalid::<3>(&sum_vec, &vec![nine; 2 * len]);
// Round trip
let want = vec![1; len];
@@ -1232,184 +1058,6 @@ mod tests {
}
}
-#[cfg(test)]
-mod test_utils {
- use super::*;
- use crate::field::{random_vector, split_vector, FieldElement};
-
- pub(crate) struct ValidityTestCase<F> {
- pub(crate) expect_valid: bool,
- pub(crate) expected_output: Option<Vec<F>>,
- // Number of shares to split input and proofs into in `flp_test`.
- pub(crate) num_shares: usize,
- }
-
- pub(crate) fn flp_validity_test<T: Type>(
- typ: &T,
- input: &[T::Field],
- t: &ValidityTestCase<T::Field>,
- ) -> Result<(), FlpError> {
- let mut gadgets = typ.gadget();
-
- if input.len() != typ.input_len() {
- return Err(FlpError::Test(format!(
- "unexpected input length: got {}; want {}",
- input.len(),
- typ.input_len()
- )));
- }
-
- if typ.query_rand_len() != gadgets.len() {
- return Err(FlpError::Test(format!(
- "query rand length: got {}; want {}",
- typ.query_rand_len(),
- gadgets.len()
- )));
- }
-
- let joint_rand = random_vector(typ.joint_rand_len()).unwrap();
- let prove_rand = random_vector(typ.prove_rand_len()).unwrap();
- let query_rand = random_vector(typ.query_rand_len()).unwrap();
-
- // Run the validity circuit.
- let v = typ.valid(&mut gadgets, input, &joint_rand, 1)?;
- if v != T::Field::zero() && t.expect_valid {
- return Err(FlpError::Test(format!(
- "expected valid input: valid() returned {v}"
- )));
- }
- if v == T::Field::zero() && !t.expect_valid {
- return Err(FlpError::Test(format!(
- "expected invalid input: valid() returned {v}"
- )));
- }
-
- // Generate the proof.
- let proof = typ.prove(input, &prove_rand, &joint_rand)?;
- if proof.len() != typ.proof_len() {
- return Err(FlpError::Test(format!(
- "unexpected proof length: got {}; want {}",
- proof.len(),
- typ.proof_len()
- )));
- }
-
- // Query the proof.
- let verifier = typ.query(input, &proof, &query_rand, &joint_rand, 1)?;
- if verifier.len() != typ.verifier_len() {
- return Err(FlpError::Test(format!(
- "unexpected verifier length: got {}; want {}",
- verifier.len(),
- typ.verifier_len()
- )));
- }
-
- // Decide if the input is valid.
- let res = typ.decide(&verifier)?;
- if res != t.expect_valid {
- return Err(FlpError::Test(format!(
- "decision is {}; want {}",
- res, t.expect_valid,
- )));
- }
-
- // Run distributed FLP.
- let input_shares: Vec<Vec<T::Field>> = split_vector(input, t.num_shares)
- .unwrap()
- .into_iter()
- .collect();
-
- let proof_shares: Vec<Vec<T::Field>> = split_vector(&proof, t.num_shares)
- .unwrap()
- .into_iter()
- .collect();
-
- let verifier: Vec<T::Field> = (0..t.num_shares)
- .map(|i| {
- typ.query(
- &input_shares[i],
- &proof_shares[i],
- &query_rand,
- &joint_rand,
- t.num_shares,
- )
- .unwrap()
- })
- .reduce(|mut left, right| {
- for (x, y) in left.iter_mut().zip(right.iter()) {
- *x += *y;
- }
- left
- })
- .unwrap();
-
- let res = typ.decide(&verifier)?;
- if res != t.expect_valid {
- return Err(FlpError::Test(format!(
- "distributed decision is {}; want {}",
- res, t.expect_valid,
- )));
- }
-
- // Try verifying various proof mutants.
- for i in 0..proof.len() {
- let mut mutated_proof = proof.clone();
- mutated_proof[i] += T::Field::one();
- let verifier = typ.query(input, &mutated_proof, &query_rand, &joint_rand, 1)?;
- if typ.decide(&verifier)? {
- return Err(FlpError::Test(format!(
- "decision for proof mutant {} is {}; want {}",
- i, true, false,
- )));
- }
- }
-
- // Try verifying a proof that is too short.
- let mut mutated_proof = proof.clone();
- mutated_proof.truncate(gadgets[0].arity() - 1);
- if typ
- .query(input, &mutated_proof, &query_rand, &joint_rand, 1)
- .is_ok()
- {
- return Err(FlpError::Test(
- "query on short proof succeeded; want failure".to_string(),
- ));
- }
-
- // Try verifying a proof that is too long.
- let mut mutated_proof = proof;
- mutated_proof.extend_from_slice(&[T::Field::one(); 17]);
- if typ
- .query(input, &mutated_proof, &query_rand, &joint_rand, 1)
- .is_ok()
- {
- return Err(FlpError::Test(
- "query on long proof succeeded; want failure".to_string(),
- ));
- }
-
- if let Some(ref want) = t.expected_output {
- let got = typ.truncate(input.to_vec())?;
-
- if got.len() != typ.output_len() {
- return Err(FlpError::Test(format!(
- "unexpected output length: got {}; want {}",
- got.len(),
- typ.output_len()
- )));
- }
-
- if &got != want {
- return Err(FlpError::Test(format!(
- "unexpected output: got {got:?}; want {want:?}"
- )));
- }
- }
-
- Ok(())
- }
-}
-
#[cfg(feature = "experimental")]
#[cfg_attr(docsrs, doc(cfg(feature = "experimental")))]
pub mod fixedpoint_l2;
diff --git a/third_party/rust/prio/src/flp/types/fixedpoint_l2.rs b/third_party/rust/prio/src/flp/types/fixedpoint_l2.rs
index b5aa2fd116..8766c035b8 100644
--- a/third_party/rust/prio/src/flp/types/fixedpoint_l2.rs
+++ b/third_party/rust/prio/src/flp/types/fixedpoint_l2.rs
@@ -172,15 +172,17 @@
pub mod compatible_float;
use crate::dp::{distributions::ZCdpDiscreteGaussian, DifferentialPrivacyStrategy, DpError};
-use crate::field::{Field128, FieldElement, FieldElementWithInteger, FieldElementWithIntegerExt};
+use crate::field::{
+ Field128, FieldElement, FieldElementWithInteger, FieldElementWithIntegerExt, Integer,
+};
use crate::flp::gadgets::{Mul, ParallelSumGadget, PolyEval};
use crate::flp::types::fixedpoint_l2::compatible_float::CompatibleFloat;
use crate::flp::types::parallel_sum_range_checks;
use crate::flp::{FlpError, Gadget, Type, TypeWithNoise};
-use crate::vdaf::xof::SeedStreamSha3;
+use crate::vdaf::xof::SeedStreamTurboShake128;
use fixed::traits::Fixed;
use num_bigint::{BigInt, BigUint, TryFromBigIntError};
-use num_integer::Integer;
+use num_integer::Integer as _;
use num_rational::Ratio;
use rand::{distributions::Distribution, Rng};
use rand_core::SeedableRng;
@@ -250,7 +252,7 @@ where
/// fixed point vector with `entries` entries.
pub fn new(entries: usize) -> Result<Self, FlpError> {
// (0) initialize constants
- let fi_one = u128::from(Field128::one());
+ let fi_one = <Field128 as FieldElementWithInteger>::Integer::one();
// (I) Check that the fixed type is compatible.
//
@@ -400,7 +402,6 @@ where
SPoly: ParallelSumGadget<Field128, PolyEval<Field128>> + Eq + Clone + 'static,
SMul: ParallelSumGadget<Field128, Mul<Field128>> + Eq + Clone + 'static,
{
- const ID: u32 = 0xFFFF0000;
type Measurement = Vec<T>;
type AggregateResult = Vec<f64>;
type Field = Field128;
@@ -419,12 +420,9 @@ where
// Encode the integer entries bitwise, and write them into the `encoded`
// vector.
let mut encoded: Vec<Field128> =
- vec![Field128::zero(); self.bits_per_entry * self.entries + self.bits_for_norm];
- for (l, entry) in integer_entries.clone().enumerate() {
- Field128::fill_with_bitvector_representation(
- &entry,
- &mut encoded[l * self.bits_per_entry..(l + 1) * self.bits_per_entry],
- )?;
+ Vec::with_capacity(self.bits_per_entry * self.entries + self.bits_for_norm);
+ for entry in integer_entries.clone() {
+ encoded.extend(Field128::encode_as_bitvector(entry, self.bits_per_entry)?);
}
// (II) Vector norm.
@@ -434,10 +432,7 @@ where
let norm_int = u128::from(norm);
// Write the norm into the `entries` vector.
- Field128::fill_with_bitvector_representation(
- &norm_int,
- &mut encoded[self.range_norm_begin..self.range_norm_end],
- )?;
+ encoded.extend(Field128::encode_as_bitvector(norm_int, self.bits_for_norm)?);
Ok(encoded)
}
@@ -535,7 +530,7 @@ where
// decode the bit-encoded entries into elements in the range [0,2^n):
let decoded_entries: Result<Vec<_>, _> = input[0..self.entries * self.bits_per_entry]
.chunks(self.bits_per_entry)
- .map(Field128::decode_from_bitvector_representation)
+ .map(Field128::decode_bitvector)
.collect();
// run parallel sum gadget on the decoded entries
@@ -544,7 +539,7 @@ where
// Chunks which are too short need to be extended with a share of the
// encoded zero value, that is: 1/num_shares * (2^(n-1))
- let fi_one = u128::from(Field128::one());
+ let fi_one = <Field128 as FieldElementWithInteger>::Integer::one();
let zero_enc = Field128::from(fi_one << (self.bits_per_entry - 1));
let zero_enc_share = zero_enc * num_shares_inverse;
@@ -567,7 +562,7 @@ where
// The submitted norm is also decoded from its bit-encoding, and
// compared with the computed norm.
let submitted_norm_enc = &input[self.range_norm_begin..self.range_norm_end];
- let submitted_norm = Field128::decode_from_bitvector_representation(submitted_norm_enc)?;
+ let submitted_norm = Field128::decode_bitvector(submitted_norm_enc)?;
let norm_check = computed_norm - submitted_norm;
@@ -586,7 +581,7 @@ where
let start = i_entry * self.bits_per_entry;
let end = (i_entry + 1) * self.bits_per_entry;
- let decoded = Field128::decode_from_bitvector_representation(&input[start..end])?;
+ let decoded = Field128::decode_bitvector(&input[start..end])?;
decoded_vector.push(decoded);
}
Ok(decoded_vector)
@@ -644,7 +639,11 @@ where
agg_result: &mut [Self::Field],
_num_measurements: usize,
) -> Result<(), FlpError> {
- self.add_noise(dp_strategy, agg_result, &mut SeedStreamSha3::from_entropy())
+ self.add_noise(
+ dp_strategy,
+ agg_result,
+ &mut SeedStreamTurboShake128::from_entropy(),
+ )
}
}
@@ -686,8 +685,8 @@ mod tests {
use crate::dp::{Rational, ZCdpBudget};
use crate::field::{random_vector, Field128, FieldElement};
use crate::flp::gadgets::ParallelSum;
- use crate::flp::types::test_utils::{flp_validity_test, ValidityTestCase};
- use crate::vdaf::xof::SeedStreamSha3;
+ use crate::flp::test_utils::FlpTest;
+ use crate::vdaf::xof::SeedStreamTurboShake128;
use fixed::types::extra::{U127, U14, U63};
use fixed::{FixedI128, FixedI16, FixedI64};
use fixed_macro::fixed;
@@ -768,15 +767,23 @@ mod tests {
let strategy = ZCdpDiscreteGaussian::from_budget(ZCdpBudget::new(
Rational::from_unsigned(100u8, 3u8).unwrap(),
));
- vsum.add_noise(&strategy, &mut v, &mut SeedStreamSha3::from_seed([0u8; 16]))
- .unwrap();
+ vsum.add_noise(
+ &strategy,
+ &mut v,
+ &mut SeedStreamTurboShake128::from_seed([0u8; 16]),
+ )
+ .unwrap();
assert_eq!(
vsum.decode_result(&v, 1).unwrap(),
match n {
// sensitivity depends on encoding so the noise differs
- 16 => vec![0.150604248046875, 0.139373779296875, -0.03759765625],
- 32 => vec![0.3051439793780446, 0.1226568529382348, 0.08595499861985445],
- 64 => vec![0.2896077990915178, 0.16115188007715098, 0.0788390114728425],
+ 16 => vec![0.288970947265625, 0.168853759765625, 0.085662841796875],
+ 32 => vec![0.257810294162482, 0.10634658299386501, 0.10149003705009818],
+ 64 => vec![
+ 0.37697368351762867,
+ -0.02388947667663828,
+ 0.19813152630930916
+ ],
_ => panic!("unsupported bitsize"),
}
);
@@ -785,52 +792,46 @@ mod tests {
let mut input: Vec<Field128> = vsum.encode_measurement(&fp_vec).unwrap();
assert_eq!(input[0], Field128::zero());
input[0] = one; // it was zero
- flp_validity_test(
- &vsum,
- &input,
- &ValidityTestCase::<Field128> {
- expect_valid: false,
- expected_output: Some(vec![
- Field128::from(enc_vec[0] + 1), // = enc(0.25) + 2^0
- Field128::from(enc_vec[1]),
- Field128::from(enc_vec[2]),
- ]),
- num_shares: 3,
- },
- )
- .unwrap();
+ FlpTest {
+ name: None,
+ flp: &vsum,
+ input: &input,
+ expected_output: Some(&[
+ Field128::from(enc_vec[0] + 1), // = enc(0.25) + 2^0
+ Field128::from(enc_vec[1]),
+ Field128::from(enc_vec[2]),
+ ]),
+ expect_valid: false,
+ }
+ .run::<3>();
// encoding contains entries that are not zero or one
let mut input2: Vec<Field128> = vsum.encode_measurement(&fp_vec).unwrap();
input2[0] = one + one;
- flp_validity_test(
- &vsum,
- &input2,
- &ValidityTestCase::<Field128> {
- expect_valid: false,
- expected_output: Some(vec![
- Field128::from(enc_vec[0] + 2), // = enc(0.25) + 2*2^0
- Field128::from(enc_vec[1]),
- Field128::from(enc_vec[2]),
- ]),
- num_shares: 3,
- },
- )
- .unwrap();
+ FlpTest {
+ name: None,
+ flp: &vsum,
+ input: &input2,
+ expected_output: Some(&[
+ Field128::from(enc_vec[0] + 2), // = enc(0.25) + 2*2^0
+ Field128::from(enc_vec[1]),
+ Field128::from(enc_vec[2]),
+ ]),
+ expect_valid: false,
+ }
+ .run::<3>();
// norm is too big
// 2^n - 1, the field element encoded by the all-1 vector
let one_enc = Field128::from(((2_u128) << (n - 1)) - 1);
- flp_validity_test(
- &vsum,
- &vec![one; 3 * n + 2 * n - 2], // all vector entries and the norm are all-1-vectors
- &ValidityTestCase::<Field128> {
- expect_valid: false,
- expected_output: Some(vec![one_enc; 3]),
- num_shares: 3,
- },
- )
- .unwrap();
+ FlpTest {
+ name: None,
+ flp: &vsum,
+ input: &vec![one; 3 * n + 2 * n - 2], // all vector entries and the norm are all-1-vectors
+ expected_output: Some(&[one_enc; 3]),
+ expect_valid: false,
+ }
+ .run::<3>();
// invalid submission length, should be 3n + (2*n - 2) for a
// 3-element n-bit vector. 3*n bits for 3 entries, (2*n-2) for norm.
diff --git a/third_party/rust/prio/src/idpf.rs b/third_party/rust/prio/src/idpf.rs
index 2bb73f2159..b3da128fa0 100644
--- a/third_party/rust/prio/src/idpf.rs
+++ b/third_party/rust/prio/src/idpf.rs
@@ -1,7 +1,7 @@
//! This module implements the incremental distributed point function (IDPF) described in
-//! [[draft-irtf-cfrg-vdaf-07]].
+//! [[draft-irtf-cfrg-vdaf-08]].
//!
-//! [draft-irtf-cfrg-vdaf-07]: https://datatracker.ietf.org/doc/draft-irtf-cfrg-vdaf/07/
+//! [draft-irtf-cfrg-vdaf-08]: https://datatracker.ietf.org/doc/draft-irtf-cfrg-vdaf/08/
use crate::{
codec::{CodecError, Decode, Encode, ParameterizedDecode},
@@ -24,12 +24,14 @@ use std::{
collections::{HashMap, VecDeque},
fmt::Debug,
io::{Cursor, Read},
+ iter::zip,
ops::{Add, AddAssign, ControlFlow, Index, Sub},
};
use subtle::{Choice, ConditionallyNegatable, ConditionallySelectable, ConstantTimeEq};
/// IDPF-related errors.
#[derive(Debug, thiserror::Error)]
+#[non_exhaustive]
pub enum IdpfError {
/// Error from incompatible shares at different levels.
#[error("tried to merge shares from incompatible levels")]
@@ -107,6 +109,11 @@ impl IdpfInput {
index: self.index[..=level].to_owned().into(),
}
}
+
+ /// Return the bit at the specified level if the level is in bounds.
+ pub fn get(&self, level: usize) -> Option<bool> {
+ self.index.get(level).as_deref().copied()
+ }
}
impl From<BitVec<usize, Lsb0>> for IdpfInput {
@@ -146,7 +153,7 @@ pub trait IdpfValue:
+ Sub<Output = Self>
+ ConditionallyNegatable
+ Encode
- + Decode
+ + ParameterizedDecode<Self::ValueParameter>
+ Sized
{
/// Any run-time parameters needed to produce a value.
@@ -239,11 +246,13 @@ fn extend(seed: &[u8; 16], xof_fixed_key: &XofFixedKeyAes128Key) -> ([[u8; 16];
seed_stream.fill_bytes(&mut seeds[0]);
seed_stream.fill_bytes(&mut seeds[1]);
- let mut byte = [0u8];
- seed_stream.fill_bytes(&mut byte);
- let control_bits = [(byte[0] & 1).into(), ((byte[0] >> 1) & 1).into()];
+ // "Steal" the control bits from the seeds.
+ let control_bits_0 = seeds[0].as_ref()[0] & 1;
+ let control_bits_1 = seeds[1].as_ref()[0] & 1;
+ seeds[0].as_mut()[0] &= 0xfe;
+ seeds[1].as_mut()[0] &= 0xfe;
- (seeds, control_bits)
+ (seeds, [control_bits_0.into(), control_bits_1.into()])
}
fn convert<V>(
@@ -670,7 +679,7 @@ where
VI: Encode,
VL: Encode,
{
- fn encode(&self, bytes: &mut Vec<u8>) {
+ fn encode(&self, bytes: &mut Vec<u8>) -> Result<(), CodecError> {
// Control bits need to be written within each byte in LSB-to-MSB order, and assigned into
// bytes in big-endian order. Thus, the first four levels will have their control bits
// encoded in the last byte, and the last levels will have their control bits encoded in the
@@ -691,11 +700,11 @@ where
bytes.append(&mut packed_control);
for correction_words in self.inner_correction_words.iter() {
- Seed(correction_words.seed).encode(bytes);
- correction_words.value.encode(bytes);
+ Seed(correction_words.seed).encode(bytes)?;
+ correction_words.value.encode(bytes)?;
}
- Seed(self.leaf_correction_word.seed).encode(bytes);
- self.leaf_correction_word.value.encode(bytes);
+ Seed(self.leaf_correction_word.seed).encode(bytes)?;
+ self.leaf_correction_word.value.encode(bytes)
}
fn encoded_len(&self) -> Option<usize> {
@@ -785,7 +794,7 @@ where
impl<V> Eq for IdpfCorrectionWord<V> where V: ConstantTimeEq {}
-fn xor_seeds(left: &[u8; 16], right: &[u8; 16]) -> [u8; 16] {
+pub(crate) fn xor_seeds(left: &[u8; 16], right: &[u8; 16]) -> [u8; 16] {
let mut seed = [0u8; 16];
for (a, (b, c)) in left.iter().zip(right.iter().zip(seed.iter_mut())) {
*c = a ^ b;
@@ -819,7 +828,7 @@ fn control_bit_to_seed_mask(control: Choice) -> [u8; 16] {
/// Take two seeds and a control bit, and return the first seed if the control bit is zero, or the
/// XOR of the two seeds if the control bit is one. This does not branch on the control bit.
-fn conditional_xor_seeds(
+pub(crate) fn conditional_xor_seeds(
normal_input: &[u8; 16],
switched_input: &[u8; 16],
control: Choice,
@@ -832,13 +841,18 @@ fn conditional_xor_seeds(
/// Returns one of two seeds, depending on the value of a selector bit. Does not branch on the
/// selector input or make selector-dependent memory accesses.
-fn conditional_select_seed(select: Choice, seeds: &[[u8; 16]; 2]) -> [u8; 16] {
+pub(crate) fn conditional_select_seed(select: Choice, seeds: &[[u8; 16]; 2]) -> [u8; 16] {
or_seeds(
&and_seeds(&control_bit_to_seed_mask(!select), &seeds[0]),
&and_seeds(&control_bit_to_seed_mask(select), &seeds[1]),
)
}
+/// Interchange the contents of seeds if the choice is 1, otherwise seeds remain unchanged.
+pub(crate) fn conditional_swap_seed(lhs: &mut [u8; 16], rhs: &mut [u8; 16], choice: Choice) {
+ zip(lhs, rhs).for_each(|(a, b)| u8::conditional_swap(a, b, choice));
+}
+
/// An interface that provides memoization of IDPF computations.
///
/// Each instance of a type implementing `IdpfCache` should only be used with one IDPF key and
@@ -947,11 +961,91 @@ impl IdpfCache for RingBufferCache {
}
}
+/// Utilities for testing IDPFs.
+#[cfg(feature = "test-util")]
+#[cfg_attr(docsrs, doc(cfg(feature = "test-util")))]
+pub mod test_utils {
+ use super::*;
+
+ use rand::prelude::*;
+ use zipf::ZipfDistribution;
+
+ /// Generate a set of IDPF inputs with the given bit length `bits`. They are sampled according
+ /// to the Zipf distribution with parameters `zipf_support` and `zipf_exponent`. Return the
+ /// measurements, along with the prefixes traversed during the heavy hitters computation for
+ /// the given threshold.
+ ///
+ /// The prefix tree consists of a sequence of candidate prefixes for each level. For a given level,
+ /// the candidate prefixes are computed from the hit counts of the prefixes at the previous level:
+ /// For any prefix `p` whose hit count is at least the desired threshold, add `p || 0` and `p || 1`
+ /// to the list.
+ pub fn generate_zipf_distributed_batch(
+ rng: &mut impl Rng,
+ bits: usize,
+ threshold: usize,
+ measurement_count: usize,
+ zipf_support: usize,
+ zipf_exponent: f64,
+ ) -> (Vec<IdpfInput>, Vec<Vec<IdpfInput>>) {
+ // Generate random inputs.
+ let mut inputs = Vec::with_capacity(zipf_support);
+ for _ in 0..zipf_support {
+ let bools: Vec<bool> = (0..bits).map(|_| rng.gen()).collect();
+ inputs.push(IdpfInput::from_bools(&bools));
+ }
+
+ // Sample a number of inputs according to the Zipf distribution.
+ let mut samples = Vec::with_capacity(measurement_count);
+ let zipf = ZipfDistribution::new(zipf_support, zipf_exponent).unwrap();
+ for _ in 0..measurement_count {
+ samples.push(inputs[zipf.sample(rng) - 1].clone());
+ }
+
+ // Compute the prefix tree for the desired threshold.
+ let mut prefix_tree = Vec::with_capacity(bits);
+ prefix_tree.push(vec![
+ IdpfInput::from_bools(&[false]),
+ IdpfInput::from_bools(&[true]),
+ ]);
+
+ for level in 0..bits - 1 {
+ // Compute the hit count of each prefix from the previous level.
+ let mut hit_counts = vec![0; prefix_tree[level].len()];
+ for (hit_count, prefix) in hit_counts.iter_mut().zip(prefix_tree[level].iter()) {
+ for sample in samples.iter() {
+ let mut is_prefix = true;
+ for j in 0..prefix.len() {
+ if prefix[j] != sample[j] {
+ is_prefix = false;
+ break;
+ }
+ }
+ if is_prefix {
+ *hit_count += 1;
+ }
+ }
+ }
+
+ // Compute the next set of candidate prefixes.
+ let mut next_prefixes = Vec::with_capacity(prefix_tree.last().unwrap().len());
+ for (hit_count, prefix) in hit_counts.iter().zip(prefix_tree[level].iter()) {
+ if *hit_count >= threshold {
+ next_prefixes.push(prefix.clone_with_suffix(&[false]));
+ next_prefixes.push(prefix.clone_with_suffix(&[true]));
+ }
+ }
+ prefix_tree.push(next_prefixes);
+ }
+
+ (samples, prefix_tree)
+ }
+}
+
#[cfg(test)]
mod tests {
use std::{
collections::HashMap,
- convert::{TryFrom, TryInto},
+ convert::TryInto,
io::Cursor,
ops::{Add, AddAssign, Sub},
str::FromStr,
@@ -1568,16 +1662,16 @@ mod tests {
seed: [0xab; 16],
control_bits: [Choice::from(1), Choice::from(0)],
value: Poplar1IdpfValue::new([
- Field64::try_from(83261u64).unwrap(),
- Field64::try_from(125159u64).unwrap(),
+ Field64::from(83261u64),
+ Field64::from(125159u64),
]),
},
IdpfCorrectionWord{
seed: [0xcd;16],
control_bits: [Choice::from(0), Choice::from(1)],
value: Poplar1IdpfValue::new([
- Field64::try_from(17614120u64).unwrap(),
- Field64::try_from(20674u64).unwrap(),
+ Field64::from(17614120u64),
+ Field64::from(20674u64),
]),
},
]),
@@ -1605,7 +1699,7 @@ mod tests {
"f0debc9a78563412f0debc9a78563412f0debc9a78563412f0debc9a78563412", // field element correction word, continued
))
.unwrap();
- let encoded = public_share.get_encoded();
+ let encoded = public_share.get_encoded().unwrap();
let decoded = IdpfPublicShare::get_decoded_with_param(&3, &message).unwrap();
assert_eq!(public_share, decoded);
assert_eq!(message, encoded);
@@ -1692,7 +1786,7 @@ mod tests {
"0000000000000000000000000000000000000000000000000000000000000000",
))
.unwrap();
- let encoded = public_share.get_encoded();
+ let encoded = public_share.get_encoded().unwrap();
let decoded = IdpfPublicShare::get_decoded_with_param(&9, &message).unwrap();
assert_eq!(public_share, decoded);
assert_eq!(message, encoded);
@@ -1761,7 +1855,7 @@ mod tests {
0,
);
- assert_eq!(public_share.get_encoded(), serialized_public_share);
+ assert_eq!(public_share.get_encoded().unwrap(), serialized_public_share);
assert_eq!(
IdpfPublicShare::get_decoded_with_param(&idpf_bits, &serialized_public_share)
.unwrap(),
@@ -1821,7 +1915,7 @@ mod tests {
/// Load a test vector for Idpf key generation.
fn load_idpfpoplar_test_vector() -> IdpfTestVector {
let test_vec: serde_json::Value =
- serde_json::from_str(include_str!("vdaf/test_vec/07/IdpfPoplar_0.json")).unwrap();
+ serde_json::from_str(include_str!("vdaf/test_vec/08/IdpfPoplar_0.json")).unwrap();
let test_vec_obj = test_vec.as_object().unwrap();
let bits = test_vec_obj
@@ -1939,7 +2033,7 @@ mod tests {
public_share, expected_public_share,
"public share did not match\n{public_share:#x?}\n{expected_public_share:#x?}"
);
- let encoded_public_share = public_share.get_encoded();
+ let encoded_public_share = public_share.get_encoded().unwrap();
assert_eq!(encoded_public_share, test_vector.public_share);
}
@@ -1988,7 +2082,9 @@ mod tests {
}
impl Encode for MyUnit {
- fn encode(&self, _: &mut Vec<u8>) {}
+ fn encode(&self, _: &mut Vec<u8>) -> Result<(), CodecError> {
+ Ok(())
+ }
}
impl Decode for MyUnit {
@@ -2066,8 +2162,8 @@ mod tests {
}
impl Encode for MyVector {
- fn encode(&self, bytes: &mut Vec<u8>) {
- encode_u32_items(bytes, &(), &self.0);
+ fn encode(&self, bytes: &mut Vec<u8>) -> Result<(), CodecError> {
+ encode_u32_items(bytes, &(), &self.0)
}
}
diff --git a/third_party/rust/prio/src/lib.rs b/third_party/rust/prio/src/lib.rs
index c9d4e22c49..630e118646 100644
--- a/third_party/rust/prio/src/lib.rs
+++ b/third_party/rust/prio/src/lib.rs
@@ -17,6 +17,7 @@
pub mod benchmarked;
pub mod codec;
#[cfg(feature = "experimental")]
+#[cfg_attr(docsrs, doc(cfg(feature = "experimental")))]
pub mod dp;
mod fft;
pub mod field;
@@ -32,3 +33,9 @@ mod polynomial;
mod prng;
pub mod topology;
pub mod vdaf;
+#[cfg(all(feature = "crypto-dependencies", feature = "experimental"))]
+#[cfg_attr(
+ docsrs,
+ doc(cfg(all(feature = "crypto-dependencies", feature = "experimental")))
+)]
+pub mod vidpf;
diff --git a/third_party/rust/prio/src/polynomial.rs b/third_party/rust/prio/src/polynomial.rs
index 89d8a91404..272266f538 100644
--- a/third_party/rust/prio/src/polynomial.rs
+++ b/third_party/rust/prio/src/polynomial.rs
@@ -3,7 +3,7 @@
//! Functions for polynomial interpolation and evaluation
-#[cfg(feature = "prio2")]
+#[cfg(all(feature = "crypto-dependencies", feature = "experimental"))]
use crate::fft::{discrete_fourier_transform, discrete_fourier_transform_inv_finish};
use crate::field::FftFriendlyFieldElement;
@@ -204,7 +204,7 @@ pub fn poly_mul<F: FftFriendlyFieldElement>(p: &[F], q: &[F]) -> Vec<F> {
out
}
-#[cfg(feature = "prio2")]
+#[cfg(all(feature = "crypto-dependencies", feature = "experimental"))]
#[inline]
pub fn poly_interpret_eval<F: FftFriendlyFieldElement>(
points: &[F],
diff --git a/third_party/rust/prio/src/prng.rs b/third_party/rust/prio/src/prng.rs
index cb7d3a54c8..2c3f5b6640 100644
--- a/third_party/rust/prio/src/prng.rs
+++ b/third_party/rust/prio/src/prng.rs
@@ -6,10 +6,9 @@
//! NOTE: The public API for this module is a work in progress.
use crate::field::{FieldElement, FieldElementExt};
-#[cfg(feature = "crypto-dependencies")]
+#[cfg(all(feature = "crypto-dependencies", feature = "experimental"))]
use crate::vdaf::xof::SeedStreamAes128;
-#[cfg(feature = "crypto-dependencies")]
-use getrandom::getrandom;
+use crate::vdaf::xof::{Seed, SeedStreamTurboShake128, Xof, XofTurboShake128};
use rand_core::RngCore;
use std::marker::PhantomData;
@@ -19,6 +18,7 @@ const BUFFER_SIZE_IN_ELEMENTS: usize = 32;
/// Errors propagated by methods in this module.
#[derive(Debug, thiserror::Error)]
+#[non_exhaustive]
pub enum PrngError {
/// Failure when calling getrandom().
#[error("getrandom: {0}")]
@@ -35,7 +35,7 @@ pub(crate) struct Prng<F, S> {
buffer_index: usize,
}
-#[cfg(feature = "crypto-dependencies")]
+#[cfg(all(feature = "crypto-dependencies", feature = "experimental"))]
impl<F: FieldElement> Prng<F, SeedStreamAes128> {
/// Create a [`Prng`] from a seed for Prio 2. The first 16 bytes of the seed and the last 16
/// bytes of the seed are used, respectively, for the key and initialization vector for AES128
@@ -44,12 +44,17 @@ impl<F: FieldElement> Prng<F, SeedStreamAes128> {
let seed_stream = SeedStreamAes128::new(&seed[..16], &seed[16..]);
Self::from_seed_stream(seed_stream)
}
+}
+impl<F: FieldElement> Prng<F, SeedStreamTurboShake128> {
/// Create a [`Prng`] from a randomly generated seed.
pub(crate) fn new() -> Result<Self, PrngError> {
- let mut seed = [0; 32];
- getrandom(&mut seed)?;
- Ok(Self::from_prio2_seed(&seed))
+ let seed = Seed::generate()?;
+ Ok(Prng::from_seed_stream(XofTurboShake128::seed_stream(
+ &seed,
+ &[],
+ &[],
+ )))
}
}
@@ -125,18 +130,20 @@ where
#[cfg(test)]
mod tests {
use super::*;
+ #[cfg(feature = "experimental")]
+ use crate::field::{encode_fieldvec, Field128, FieldPrio2};
use crate::{
codec::Decode,
- field::{Field64, FieldPrio2},
- vdaf::xof::{Seed, SeedStreamSha3, Xof, XofShake128},
+ field::Field64,
+ vdaf::xof::{Seed, SeedStreamTurboShake128, Xof, XofTurboShake128},
};
- #[cfg(feature = "prio2")]
+ #[cfg(feature = "experimental")]
use base64::{engine::Engine, prelude::BASE64_STANDARD};
- #[cfg(feature = "prio2")]
+ #[cfg(feature = "experimental")]
use sha2::{Digest, Sha256};
- use std::convert::TryInto;
#[test]
+ #[cfg(feature = "experimental")]
fn secret_sharing_interop() {
let seed = [
0xcd, 0x85, 0x5b, 0xd4, 0x86, 0x48, 0xa4, 0xce, 0x52, 0x5c, 0x36, 0xee, 0x5a, 0x71,
@@ -158,21 +165,22 @@ mod tests {
}
/// takes a seed and hash as base64 encoded strings
- #[cfg(feature = "prio2")]
+ #[cfg(feature = "experimental")]
fn random_data_interop(seed_base64: &str, hash_base64: &str, len: usize) {
let seed = BASE64_STANDARD.decode(seed_base64).unwrap();
let random_data = extract_share_from_seed::<FieldPrio2>(len, &seed);
- let random_bytes = FieldPrio2::slice_into_byte_vec(&random_data);
+ let mut random_bytes = Vec::new();
+ encode_fieldvec(&random_data, &mut random_bytes).unwrap();
- let mut hasher = Sha256::new();
+ let mut hasher = <Sha256 as Digest>::new();
hasher.update(&random_bytes);
let digest = hasher.finalize();
assert_eq!(BASE64_STANDARD.encode(digest), hash_base64);
}
#[test]
- #[cfg(feature = "prio2")]
+ #[cfg(feature = "experimental")]
fn test_hash_interop() {
random_data_interop(
"AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8=",
@@ -206,6 +214,7 @@ mod tests {
);
}
+ #[cfg(feature = "experimental")]
fn extract_share_from_seed<F: FieldElement>(length: usize, seed: &[u8]) -> Vec<F> {
assert_eq!(seed.len(), 32);
Prng::from_prio2_seed(seed.try_into().unwrap())
@@ -218,22 +227,22 @@ mod tests {
// These constants were found in a brute-force search, and they test that the XOF performs
// rejection sampling correctly when the raw output exceeds the prime modulus.
let seed = Seed::get_decoded(&[
- 0x29, 0xb2, 0x98, 0x64, 0xb4, 0xaa, 0x4e, 0x07, 0x2a, 0x44, 0x49, 0x24, 0xf6, 0x74,
- 0x0a, 0x3d,
+ 0xd5, 0x3f, 0xff, 0x5d, 0x88, 0x8c, 0x60, 0x4e, 0x9f, 0x24, 0x16, 0xe1, 0xa2, 0x0a,
+ 0x62, 0x34,
])
.unwrap();
- let expected = Field64::from(2035552711764301796);
+ let expected = Field64::from(3401316594827516850);
- let seed_stream = XofShake128::seed_stream(&seed, b"", b"");
+ let seed_stream = XofTurboShake128::seed_stream(&seed, b"", b"");
let mut prng = Prng::<Field64, _>::from_seed_stream(seed_stream);
- let actual = prng.nth(33236).unwrap();
+ let actual = prng.nth(662).unwrap();
assert_eq!(actual, expected);
#[cfg(all(feature = "crypto-dependencies", feature = "experimental"))]
{
- let mut seed_stream = XofShake128::seed_stream(&seed, b"", b"");
+ let mut seed_stream = XofTurboShake128::seed_stream(&seed, b"", b"");
let mut actual = <Field64 as FieldElement>::zero();
- for _ in 0..=33236 {
+ for _ in 0..=662 {
actual = <Field64 as crate::idpf::IdpfValue>::generate(&mut seed_stream, &());
}
assert_eq!(actual, expected);
@@ -246,12 +255,12 @@ mod tests {
fn left_over_buffer_back_fill() {
let seed = Seed::generate().unwrap();
- let mut prng: Prng<Field64, SeedStreamSha3> =
- Prng::from_seed_stream(XofShake128::seed_stream(&seed, b"", b""));
+ let mut prng: Prng<Field64, SeedStreamTurboShake128> =
+ Prng::from_seed_stream(XofTurboShake128::seed_stream(&seed, b"", b""));
// Construct a `Prng` with a longer-than-usual buffer.
- let mut prng_weird_buffer_size: Prng<Field64, SeedStreamSha3> =
- Prng::from_seed_stream(XofShake128::seed_stream(&seed, b"", b""));
+ let mut prng_weird_buffer_size: Prng<Field64, SeedStreamTurboShake128> =
+ Prng::from_seed_stream(XofTurboShake128::seed_stream(&seed, b"", b""));
let mut extra = [0; 7];
prng_weird_buffer_size.seed_stream.fill_bytes(&mut extra);
prng_weird_buffer_size.buffer.extend_from_slice(&extra);
@@ -265,13 +274,13 @@ mod tests {
#[cfg(feature = "experimental")]
#[test]
- fn into_new_field() {
+ fn into_different_field() {
let seed = Seed::generate().unwrap();
- let want: Prng<Field64, SeedStreamSha3> =
- Prng::from_seed_stream(XofShake128::seed_stream(&seed, b"", b""));
+ let want: Prng<Field64, SeedStreamTurboShake128> =
+ Prng::from_seed_stream(XofTurboShake128::seed_stream(&seed, b"", b""));
let want_buffer = want.buffer.clone();
- let got: Prng<FieldPrio2, _> = want.into_new_field();
+ let got: Prng<Field128, _> = want.into_new_field();
assert_eq!(got.buffer_index, 0);
assert_eq!(got.buffer, want_buffer);
}
diff --git a/third_party/rust/prio/src/topology/ping_pong.rs b/third_party/rust/prio/src/topology/ping_pong.rs
index c55d4f638d..646f181865 100644
--- a/third_party/rust/prio/src/topology/ping_pong.rs
+++ b/third_party/rust/prio/src/topology/ping_pong.rs
@@ -4,7 +4,7 @@
//! two aggregators, designated "Leader" and "Helper". This topology is required for implementing
//! the [Distributed Aggregation Protocol][DAP].
//!
-//! [VDAF]: https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-vdaf-07#section-5.8
+//! [VDAF]: https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-vdaf-08#section-5.8
//! [DAP]: https://datatracker.ietf.org/doc/html/draft-ietf-ppm-dap
use crate::{
@@ -15,6 +15,7 @@ use std::fmt::Debug;
/// Errors emitted by this module.
#[derive(Debug, thiserror::Error)]
+#[non_exhaustive]
pub enum PingPongError {
/// Error running prepare_init
#[error("vdaf.prepare_init: {0}")]
@@ -28,12 +29,12 @@ pub enum PingPongError {
#[error("vdaf.prepare_next {0}")]
VdafPrepareNext(VdafError),
- /// Error decoding a prepare share
- #[error("decode prep share {0}")]
+ /// Error encoding or decoding a prepare share
+ #[error("encode/decode prep share {0}")]
CodecPrepShare(CodecError),
- /// Error decoding a prepare message
- #[error("decode prep message {0}")]
+ /// Error encoding or decoding a prepare message
+ #[error("encode/decode prep message {0}")]
CodecPrepMessage(CodecError),
/// Host is in an unexpected state
@@ -63,7 +64,7 @@ pub enum PingPongError {
/// variants are opaque byte buffers. This is because the ping-pong routines take responsibility for
/// decoding preparation shares and messages, which usually requires having the preparation state.
///
-/// [VDAF]: https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-vdaf-07#section-5.8
+/// [VDAF]: https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-vdaf-08#section-5.8
#[derive(Clone, PartialEq, Eq)]
pub enum PingPongMessage {
/// Corresponds to MessageType.initialize.
@@ -108,27 +109,28 @@ impl Debug for PingPongMessage {
}
impl Encode for PingPongMessage {
- fn encode(&self, bytes: &mut Vec<u8>) {
+ fn encode(&self, bytes: &mut Vec<u8>) -> Result<(), CodecError> {
// The encoding includes an implicit discriminator byte, called MessageType in the VDAF
// spec.
match self {
Self::Initialize { prep_share } => {
- 0u8.encode(bytes);
- encode_u32_items(bytes, &(), prep_share);
+ 0u8.encode(bytes)?;
+ encode_u32_items(bytes, &(), prep_share)?;
}
Self::Continue {
prep_msg,
prep_share,
} => {
- 1u8.encode(bytes);
- encode_u32_items(bytes, &(), prep_msg);
- encode_u32_items(bytes, &(), prep_share);
+ 1u8.encode(bytes)?;
+ encode_u32_items(bytes, &(), prep_msg)?;
+ encode_u32_items(bytes, &(), prep_share)?;
}
Self::Finish { prep_msg } => {
- 2u8.encode(bytes);
- encode_u32_items(bytes, &(), prep_msg);
+ 2u8.encode(bytes)?;
+ encode_u32_items(bytes, &(), prep_msg)?;
}
}
+ Ok(())
}
fn encoded_len(&self) -> Option<usize> {
@@ -182,7 +184,7 @@ impl Decode for PingPongMessage {
/// preprocessed prepare message. Their encoding is much smaller than the `(State, Message)` tuple,
/// which can always be recomputed with [`Self::evaluate`].
///
-/// [VDAF]: https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-vdaf-07#section-5.8
+/// [VDAF]: https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-vdaf-08#section-5.8
#[derive(Clone, Debug, Eq)]
pub struct PingPongTransition<
const VERIFY_KEY_SIZE: usize,
@@ -212,26 +214,31 @@ impl<
),
PingPongError,
> {
- let prep_msg = self.current_prepare_message.get_encoded();
+ let prep_msg = self
+ .current_prepare_message
+ .get_encoded()
+ .map_err(PingPongError::CodecPrepMessage)?;
vdaf.prepare_next(
self.previous_prepare_state.clone(),
self.current_prepare_message.clone(),
)
- .map(|transition| match transition {
- PrepareTransition::Continue(prep_state, prep_share) => (
+ .map_err(PingPongError::VdafPrepareNext)
+ .and_then(|transition| match transition {
+ PrepareTransition::Continue(prep_state, prep_share) => Ok((
PingPongState::Continued(prep_state),
PingPongMessage::Continue {
prep_msg,
- prep_share: prep_share.get_encoded(),
+ prep_share: prep_share
+ .get_encoded()
+ .map_err(PingPongError::CodecPrepShare)?,
},
- ),
- PrepareTransition::Finish(output_share) => (
+ )),
+ PrepareTransition::Finish(output_share) => Ok((
PingPongState::Finished(output_share),
PingPongMessage::Finish { prep_msg },
- ),
+ )),
})
- .map_err(PingPongError::VdafPrepareNext)
}
}
@@ -253,9 +260,9 @@ where
A: Aggregator<VERIFY_KEY_SIZE, NONCE_SIZE>,
A::PrepareState: Encode,
{
- fn encode(&self, bytes: &mut Vec<u8>) {
- self.previous_prepare_state.encode(bytes);
- self.current_prepare_message.encode(bytes);
+ fn encode(&self, bytes: &mut Vec<u8>) -> Result<(), CodecError> {
+ self.previous_prepare_state.encode(bytes)?;
+ self.current_prepare_message.encode(bytes)
}
fn encoded_len(&self) -> Option<usize> {
@@ -293,7 +300,7 @@ where
/// code, and the `Rejected` state is represented as `std::result::Result::Err`, so this enum does
/// not include those variants.
///
-/// [VDAF]: https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-vdaf-07#section-5.8
+/// [VDAF]: https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-vdaf-08#section-5.8
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum PingPongState<
const VERIFY_KEY_SIZE: usize,
@@ -331,7 +338,7 @@ pub enum PingPongContinuedValue<
/// Extension trait on [`crate::vdaf::Aggregator`] which adds the [VDAF Ping-Pong Topology][VDAF].
///
-/// [VDAF]: https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-vdaf-07#section-5.8
+/// [VDAF]: https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-vdaf-08#section-5.8
pub trait PingPongTopology<const VERIFY_KEY_SIZE: usize, const NONCE_SIZE: usize>:
Aggregator<VERIFY_KEY_SIZE, NONCE_SIZE>
{
@@ -351,7 +358,7 @@ pub trait PingPongTopology<const VERIFY_KEY_SIZE: usize, const NONCE_SIZE: usize
/// leader along with the next [`PingPongMessage`] received from the helper as input to
/// [`Self::leader_continued`] to advance to the next round.
///
- /// [VDAF]: https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-vdaf-07#section-5.8
+ /// [VDAF]: https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-vdaf-08#section-5.8
fn leader_initialized(
&self,
verify_key: &[u8; VERIFY_KEY_SIZE],
@@ -362,7 +369,7 @@ pub trait PingPongTopology<const VERIFY_KEY_SIZE: usize, const NONCE_SIZE: usize
) -> Result<(Self::State, PingPongMessage), PingPongError>;
/// Initialize helper state using the helper's input share and the leader's first prepare share.
- /// Corresponds to `ping_pong_helper_init` in the forthcoming `draft-irtf-cfrg-vdaf-07`.
+ /// Corresponds to `ping_pong_helper_init` in [VDAF].
///
/// If successful, the returned [`PingPongTransition`] should be evaluated, yielding a
/// [`PingPongMessage`], which should be transmitted to the leader, and a [`PingPongState`].
@@ -378,6 +385,8 @@ pub trait PingPongTopology<const VERIFY_KEY_SIZE: usize, const NONCE_SIZE: usize
/// # Errors
///
/// `inbound` must be `PingPongMessage::Initialize` or the function will fail.
+ ///
+ /// [VDAF]: https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-vdaf-08#section-5.8
fn helper_initialized(
&self,
verify_key: &[u8; VERIFY_KEY_SIZE],
@@ -415,15 +424,7 @@ pub trait PingPongTopology<const VERIFY_KEY_SIZE: usize, const NONCE_SIZE: usize
///
/// `inbound` must not be `PingPongMessage::Initialize` or the function will fail.
///
- /// # Notes
- ///
- /// The specification of this function in [VDAF] takes the aggregation parameter. This version
- /// does not, because [`crate::vdaf::Aggregator::prepare_preprocess`] does not take the
- /// aggregation parameter. This may change in the future if/when [#670][issue] is addressed.
- ///
- ///
- /// [VDAF]: https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-vdaf-07#section-5.8
- /// [issue]: https://github.com/divviup/libprio-rs/issues/670
+ /// [VDAF]: https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-vdaf-08#section-5.8
fn leader_continued(
&self,
leader_state: Self::State,
@@ -458,15 +459,7 @@ pub trait PingPongTopology<const VERIFY_KEY_SIZE: usize, const NONCE_SIZE: usize
///
/// `inbound` must not be `PingPongMessage::Initialize` or the function will fail.
///
- /// # Notes
- ///
- /// The specification of this function in [VDAF] takes the aggregation parameter. This version
- /// does not, because [`crate::vdaf::Aggregator::prepare_preprocess`] does not take the
- /// aggregation parameter. This may change in the future if/when [#670][issue] is addressed.
- ///
- ///
- /// [VDAF]: https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-vdaf-07#section-5.8
- /// [issue]: https://github.com/divviup/libprio-rs/issues/670
+ /// [VDAF]: https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-vdaf-08#section-5.8
fn helper_continued(
&self,
helper_state: Self::State,
@@ -513,15 +506,17 @@ where
public_share,
input_share,
)
- .map(|(prep_state, prep_share)| {
- (
+ .map_err(PingPongError::VdafPrepareInit)
+ .and_then(|(prep_state, prep_share)| {
+ Ok((
PingPongState::Continued(prep_state),
PingPongMessage::Initialize {
- prep_share: prep_share.get_encoded(),
+ prep_share: prep_share
+ .get_encoded()
+ .map_err(PingPongError::CodecPrepShare)?,
},
- )
+ ))
})
- .map_err(PingPongError::VdafPrepareInit)
}
fn helper_initialized(
@@ -652,18 +647,14 @@ where
(PrepareTransition::Finish(output_share), None) => {
Ok(PingPongContinuedValue::FinishedNoMessage { output_share })
}
- (PrepareTransition::Continue(_, _), None) => {
- return Err(PingPongError::PeerMessageMismatch {
- found: inbound.variant(),
- expected: "continue",
- })
- }
- (PrepareTransition::Finish(_), Some(_)) => {
- return Err(PingPongError::PeerMessageMismatch {
- found: inbound.variant(),
- expected: "finish",
- })
- }
+ (PrepareTransition::Continue(_, _), None) => Err(PingPongError::PeerMessageMismatch {
+ found: inbound.variant(),
+ expected: "continue",
+ }),
+ (PrepareTransition::Finish(_), Some(_)) => Err(PingPongError::PeerMessageMismatch {
+ found: inbound.variant(),
+ expected: "finish",
+ }),
}
}
}
@@ -914,7 +905,7 @@ mod tests {
for (message, expected_hex) in messages {
let mut encoded_val = Vec::new();
- message.encode(&mut encoded_val);
+ message.encode(&mut encoded_val).unwrap();
let got_hex = hex::encode(&encoded_val);
assert_eq!(
&got_hex, expected_hex,
@@ -942,7 +933,7 @@ mod tests {
current_prepare_message: (),
};
- let encoded = transition.get_encoded();
+ let encoded = transition.get_encoded().unwrap();
let hex_encoded = hex::encode(&encoded);
assert_eq!(
diff --git a/third_party/rust/prio/src/vdaf.rs b/third_party/rust/prio/src/vdaf.rs
index 1a6c5f0315..e5f4e14c5a 100644
--- a/third_party/rust/prio/src/vdaf.rs
+++ b/third_party/rust/prio/src/vdaf.rs
@@ -1,14 +1,16 @@
// SPDX-License-Identifier: MPL-2.0
//! Verifiable Distributed Aggregation Functions (VDAFs) as described in
-//! [[draft-irtf-cfrg-vdaf-07]].
+//! [[draft-irtf-cfrg-vdaf-08]].
//!
-//! [draft-irtf-cfrg-vdaf-07]: https://datatracker.ietf.org/doc/draft-irtf-cfrg-vdaf/07/
+//! [draft-irtf-cfrg-vdaf-08]: https://datatracker.ietf.org/doc/draft-irtf-cfrg-vdaf/08/
#[cfg(feature = "experimental")]
use crate::dp::DifferentialPrivacyStrategy;
#[cfg(all(feature = "crypto-dependencies", feature = "experimental"))]
use crate::idpf::IdpfError;
+#[cfg(all(feature = "crypto-dependencies", feature = "experimental"))]
+use crate::vidpf::VidpfError;
use crate::{
codec::{CodecError, Decode, Encode, ParameterizedDecode},
field::{encode_fieldvec, merge_vector, FieldElement, FieldError},
@@ -17,15 +19,16 @@ use crate::{
vdaf::xof::Seed,
};
use serde::{Deserialize, Serialize};
-use std::{fmt::Debug, io::Cursor};
+use std::{error::Error, fmt::Debug, io::Cursor};
use subtle::{Choice, ConstantTimeEq};
/// 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 = 7;
+pub(crate) const VERSION: u8 = 8;
/// Errors emitted by this module.
#[derive(Debug, thiserror::Error)]
+#[non_exhaustive]
pub enum VdafError {
/// An error occurred.
#[error("vdaf error: {0}")]
@@ -55,6 +58,15 @@ pub enum VdafError {
#[cfg(all(feature = "crypto-dependencies", feature = "experimental"))]
#[error("idpf error: {0}")]
Idpf(#[from] IdpfError),
+
+ /// VIDPF error.
+ #[cfg(all(feature = "crypto-dependencies", feature = "experimental"))]
+ #[error("vidpf error: {0}")]
+ Vidpf(#[from] VidpfError),
+
+ /// Errors from other VDAFs.
+ #[error(transparent)]
+ Other(Box<dyn Error + 'static + Send + Sync>),
}
/// An additive share of a vector of field elements.
@@ -67,18 +79,6 @@ pub enum Share<F, const SEED_SIZE: usize> {
Helper(Seed<SEED_SIZE>),
}
-impl<F: Clone, const SEED_SIZE: usize> Share<F, SEED_SIZE> {
- /// Truncate the Leader's share to the given length. If this is the Helper's share, then this
- /// method clones the input without modifying it.
- #[cfg(feature = "prio2")]
- pub(crate) fn truncated(&self, len: usize) -> Self {
- match self {
- Self::Leader(ref data) => Self::Leader(data[..len].to_vec()),
- Self::Helper(ref seed) => Self::Helper(seed.clone()),
- }
- }
-}
-
impl<F: ConstantTimeEq, const SEED_SIZE: usize> PartialEq for Share<F, SEED_SIZE> {
fn eq(&self, other: &Self) -> bool {
self.ct_eq(other).into()
@@ -130,16 +130,15 @@ impl<F: FieldElement, const SEED_SIZE: usize> ParameterizedDecode<ShareDecodingP
}
impl<F: FieldElement, const SEED_SIZE: usize> Encode for Share<F, SEED_SIZE> {
- fn encode(&self, bytes: &mut Vec<u8>) {
+ fn encode(&self, bytes: &mut Vec<u8>) -> Result<(), CodecError> {
match self {
Share::Leader(share_data) => {
for x in share_data {
- x.encode(bytes);
+ x.encode(bytes)?;
}
+ Ok(())
}
- Share::Helper(share_seed) => {
- share_seed.encode(bytes);
- }
+ Share::Helper(share_seed) => share_seed.encode(bytes),
}
}
@@ -158,9 +157,6 @@ impl<F: FieldElement, const SEED_SIZE: usize> Encode for Share<F, SEED_SIZE> {
/// and [`Collector`], which define the roles of the various parties involved in the execution of
/// the VDAF.
pub trait Vdaf: Clone + Debug {
- /// Algorithm identifier for this VDAF.
- const ID: u32;
-
/// The type of Client measurement to be aggregated.
type Measurement: Clone + Debug;
@@ -188,17 +184,20 @@ pub trait Vdaf: Clone + Debug {
+ 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(usage: u16) -> [u8; 8] {
+ fn domain_separation_tag(&self, usage: u16) -> [u8; 8] {
let mut dst = [0_u8; 8];
dst[0] = VERSION;
dst[1] = 0; // algorithm class
- dst[2..6].copy_from_slice(&(Self::ID).to_be_bytes());
+ dst[2..6].copy_from_slice(&(self.algorithm_id()).to_be_bytes());
dst[6..8].copy_from_slice(&usage.to_be_bytes());
dst
}
@@ -211,7 +210,7 @@ pub trait Client<const NONCE_SIZE: usize>: Vdaf {
///
/// Implements `Vdaf::shard` from [VDAF].
///
- /// [VDAF]: https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-vdaf-07#section-5.1
+ /// [VDAF]: https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-vdaf-08#section-5.1
fn shard(
&self,
measurement: &Self::Measurement,
@@ -247,7 +246,7 @@ pub trait Aggregator<const VERIFY_KEY_SIZE: usize, const NONCE_SIZE: usize>: Vda
///
/// Implements `Vdaf.prep_init` from [VDAF].
///
- /// [VDAF]: https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-vdaf-07#section-5.2
+ /// [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],
@@ -262,29 +261,7 @@ pub trait Aggregator<const VERIFY_KEY_SIZE: usize, const NONCE_SIZE: usize>: Vda
///
/// Implements `Vdaf.prep_shares_to_prep` from [VDAF].
///
- /// # Notes
- ///
- /// [`Self::prepare_shares_to_prepare_message`] is preferable since its name better matches the
- /// specification.
- ///
- /// [VDAF]: https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-vdaf-07#section-5.2
- #[deprecated(
- since = "0.15.0",
- note = "Use Vdaf::prepare_shares_to_prepare_message instead"
- )]
- fn prepare_preprocess<M: IntoIterator<Item = Self::PrepareShare>>(
- &self,
- agg_param: &Self::AggregationParam,
- inputs: M,
- ) -> Result<Self::PrepareMessage, VdafError> {
- self.prepare_shares_to_prepare_message(agg_param, inputs)
- }
-
- /// 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-07#section-5.2
+ /// [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,
@@ -301,31 +278,7 @@ pub trait Aggregator<const VERIFY_KEY_SIZE: usize, const NONCE_SIZE: usize>: Vda
///
/// Implements `Vdaf.prep_next` from [VDAF].
///
- /// # Notes
- ///
- /// [`Self::prepare_next`] is preferable since its name better matches the specification.
- ///
- /// [VDAF]: https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-vdaf-07#section-5.2
- #[deprecated(since = "0.15.0", note = "Use Vdaf::prepare_next")]
- fn prepare_step(
- &self,
- state: Self::PrepareState,
- input: Self::PrepareMessage,
- ) -> Result<PrepareTransition<Self, VERIFY_KEY_SIZE, NONCE_SIZE>, VdafError> {
- self.prepare_next(state, input)
- }
-
- /// 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-07#section-5.2
+ /// [VDAF]: https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-vdaf-08#section-5.2
fn prepare_next(
&self,
state: Self::PrepareState,
@@ -342,6 +295,7 @@ pub trait Aggregator<const VERIFY_KEY_SIZE: usize, const NONCE_SIZE: usize>: Vda
/// Aggregator that implements differential privacy with Aggregator-side noise addition.
#[cfg(feature = "experimental")]
+#[cfg_attr(docsrs, doc(cfg(feature = "experimental")))]
pub trait AggregatorWithNoise<
const VERIFY_KEY_SIZE: usize,
const NONCE_SIZE: usize,
@@ -428,7 +382,7 @@ impl<F> From<Vec<F>> for OutputShare<F> {
}
impl<F: FieldElement> Encode for OutputShare<F> {
- fn encode(&self, bytes: &mut Vec<u8>) {
+ fn encode(&self, bytes: &mut Vec<u8>) -> Result<(), CodecError> {
encode_fieldvec(&self.0, bytes)
}
@@ -451,6 +405,12 @@ impl<F> Debug for OutputShare<F> {
pub struct AggregateShare<F>(Vec<F>);
+impl<F> From<Vec<F>> for AggregateShare<F> {
+ fn from(other: Vec<F>) -> Self {
+ Self(other)
+ }
+}
+
impl<F: ConstantTimeEq> PartialEq for AggregateShare<F> {
fn eq(&self, other: &Self) -> bool {
self.ct_eq(other).into()
@@ -498,7 +458,7 @@ impl<F: FieldElement> AggregateShare<F> {
}
impl<F: FieldElement> Encode for AggregateShare<F> {
- fn encode(&self, bytes: &mut Vec<u8>) {
+ fn encode(&self, bytes: &mut Vec<u8>) -> Result<(), CodecError> {
encode_fieldvec(&self.0, bytes)
}
@@ -507,151 +467,190 @@ impl<F: FieldElement> Encode for AggregateShare<F> {
}
}
-#[cfg(test)]
-pub(crate) fn run_vdaf<V, M, const SEED_SIZE: usize>(
- vdaf: &V,
- agg_param: &V::AggregationParam,
- measurements: M,
-) -> Result<V::AggregateResult, VdafError>
-where
- V: Client<16> + Aggregator<SEED_SIZE, 16> + Collector,
- M: IntoIterator<Item = V::Measurement>,
-{
+/// Utilities for testing VDAFs.
+#[cfg(feature = "test-util")]
+#[cfg_attr(docsrs, doc(cfg(feature = "test-util")))]
+pub mod test_utils {
+ use super::{Aggregatable, Aggregator, Client, Collector, PrepareTransition, VdafError};
+ use crate::codec::{Encode, ParameterizedDecode};
use rand::prelude::*;
- let mut rng = thread_rng();
- let mut verify_key = [0; SEED_SIZE];
- rng.fill(&mut verify_key[..]);
-
- let mut agg_shares: Vec<Option<V::AggregateShare>> = vec![None; vdaf.num_aggregators()];
- let mut num_measurements: usize = 0;
- for measurement in measurements.into_iter() {
- num_measurements += 1;
- let nonce = rng.gen();
- let (public_share, input_shares) = vdaf.shard(&measurement, &nonce)?;
- let out_shares = run_vdaf_prepare(
- vdaf,
- &verify_key,
- agg_param,
- &nonce,
- public_share,
- input_shares,
- )?;
- for (out_share, agg_share) in out_shares.into_iter().zip(agg_shares.iter_mut()) {
- // Check serialization of output shares
- let encoded_out_share = out_share.get_encoded();
- let round_trip_out_share =
- V::OutputShare::get_decoded_with_param(&(vdaf, agg_param), &encoded_out_share)
- .unwrap();
- assert_eq!(round_trip_out_share.get_encoded(), encoded_out_share);
- let this_agg_share = V::AggregateShare::from(out_share);
- if let Some(ref mut inner) = agg_share {
- inner.merge(&this_agg_share)?;
- } else {
- *agg_share = Some(this_agg_share);
- }
+ /// Execute the VDAF end-to-end and return the aggregate result.
+ pub fn run_vdaf<V, M, const SEED_SIZE: usize>(
+ vdaf: &V,
+ agg_param: &V::AggregationParam,
+ measurements: M,
+ ) -> Result<V::AggregateResult, VdafError>
+ where
+ V: Client<16> + Aggregator<SEED_SIZE, 16> + Collector,
+ M: IntoIterator<Item = V::Measurement>,
+ {
+ let mut sharded_measurements = Vec::new();
+ for measurement in measurements.into_iter() {
+ let nonce = random();
+ let (public_share, input_shares) = vdaf.shard(&measurement, &nonce)?;
+
+ sharded_measurements.push((public_share, nonce, input_shares));
}
- }
- for agg_share in agg_shares.iter() {
- // Check serialization of aggregate shares
- let encoded_agg_share = agg_share.as_ref().unwrap().get_encoded();
- let round_trip_agg_share =
- V::AggregateShare::get_decoded_with_param(&(vdaf, agg_param), &encoded_agg_share)
- .unwrap();
- assert_eq!(round_trip_agg_share.get_encoded(), encoded_agg_share);
- }
+ run_vdaf_sharded(vdaf, agg_param, sharded_measurements)
+ }
+
+ /// Execute the VDAF on sharded measurements and return the aggregate result.
+ pub fn run_vdaf_sharded<V, M, I, const SEED_SIZE: usize>(
+ vdaf: &V,
+ agg_param: &V::AggregationParam,
+ sharded_measurements: M,
+ ) -> Result<V::AggregateResult, VdafError>
+ where
+ V: Client<16> + Aggregator<SEED_SIZE, 16> + Collector,
+ M: IntoIterator<Item = (V::PublicShare, [u8; 16], I)>,
+ I: IntoIterator<Item = V::InputShare>,
+ {
+ let mut rng = thread_rng();
+ let mut verify_key = [0; SEED_SIZE];
+ rng.fill(&mut verify_key[..]);
+
+ let mut agg_shares: Vec<Option<V::AggregateShare>> = vec![None; vdaf.num_aggregators()];
+ let mut num_measurements: usize = 0;
+ for (public_share, nonce, input_shares) in sharded_measurements.into_iter() {
+ num_measurements += 1;
+ let out_shares = run_vdaf_prepare(
+ vdaf,
+ &verify_key,
+ agg_param,
+ &nonce,
+ public_share,
+ input_shares,
+ )?;
+ for (out_share, agg_share) in out_shares.into_iter().zip(agg_shares.iter_mut()) {
+ // Check serialization of output shares
+ let encoded_out_share = out_share.get_encoded().unwrap();
+ let round_trip_out_share =
+ V::OutputShare::get_decoded_with_param(&(vdaf, agg_param), &encoded_out_share)
+ .unwrap();
+ assert_eq!(
+ round_trip_out_share.get_encoded().unwrap(),
+ encoded_out_share
+ );
- let res = vdaf.unshard(
- agg_param,
- agg_shares.into_iter().map(|option| option.unwrap()),
- num_measurements,
- )?;
- Ok(res)
-}
+ let this_agg_share = V::AggregateShare::from(out_share);
+ if let Some(ref mut inner) = agg_share {
+ inner.merge(&this_agg_share)?;
+ } else {
+ *agg_share = Some(this_agg_share);
+ }
+ }
+ }
-#[cfg(test)]
-pub(crate) fn run_vdaf_prepare<V, M, const SEED_SIZE: usize>(
- vdaf: &V,
- verify_key: &[u8; SEED_SIZE],
- agg_param: &V::AggregationParam,
- nonce: &[u8; 16],
- public_share: V::PublicShare,
- input_shares: M,
-) -> Result<Vec<V::OutputShare>, VdafError>
-where
- V: Client<16> + Aggregator<SEED_SIZE, 16> + Collector,
- M: IntoIterator<Item = V::InputShare>,
-{
- let input_shares = input_shares
- .into_iter()
- .map(|input_share| input_share.get_encoded());
-
- let mut states = Vec::new();
- let mut outbound = Vec::new();
- for (agg_id, input_share) in input_shares.enumerate() {
- let (state, msg) = vdaf.prepare_init(
- verify_key,
- agg_id,
+ for agg_share in agg_shares.iter() {
+ // Check serialization of aggregate shares
+ let encoded_agg_share = agg_share.as_ref().unwrap().get_encoded().unwrap();
+ let round_trip_agg_share =
+ V::AggregateShare::get_decoded_with_param(&(vdaf, agg_param), &encoded_agg_share)
+ .unwrap();
+ assert_eq!(
+ round_trip_agg_share.get_encoded().unwrap(),
+ encoded_agg_share
+ );
+ }
+
+ let res = vdaf.unshard(
agg_param,
- nonce,
- &public_share,
- &V::InputShare::get_decoded_with_param(&(vdaf, agg_id), &input_share)
- .expect("failed to decode input share"),
+ agg_shares.into_iter().map(|option| option.unwrap()),
+ num_measurements,
)?;
- states.push(state);
- outbound.push(msg.get_encoded());
- }
+ Ok(res)
+ }
+
+ /// Execute VDAF preparation for a single report and return the recovered output shares.
+ pub fn run_vdaf_prepare<V, M, const SEED_SIZE: usize>(
+ vdaf: &V,
+ verify_key: &[u8; SEED_SIZE],
+ agg_param: &V::AggregationParam,
+ nonce: &[u8; 16],
+ public_share: V::PublicShare,
+ input_shares: M,
+ ) -> Result<Vec<V::OutputShare>, VdafError>
+ where
+ V: Client<16> + Aggregator<SEED_SIZE, 16> + Collector,
+ M: IntoIterator<Item = V::InputShare>,
+ {
+ let public_share =
+ V::PublicShare::get_decoded_with_param(vdaf, &public_share.get_encoded().unwrap())
+ .unwrap();
+ let input_shares = input_shares
+ .into_iter()
+ .map(|input_share| input_share.get_encoded().unwrap());
- let mut 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();
-
- let mut out_shares = Vec::new();
- loop {
+ let mut states = Vec::new();
let mut 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());
- *state = new_state
- }
- PrepareTransition::Finish(out_share) => {
- out_shares.push(out_share);
+ for (agg_id, input_share) in input_shares.enumerate() {
+ let (state, msg) = vdaf.prepare_init(
+ verify_key,
+ agg_id,
+ agg_param,
+ nonce,
+ &public_share,
+ &V::InputShare::get_decoded_with_param(&(vdaf, agg_id), &input_share)
+ .expect("failed to decode input share"),
+ )?;
+ states.push(state);
+ outbound.push(msg.get_encoded().unwrap());
+ }
+
+ let mut 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();
+
+ let mut out_shares = Vec::new();
+ loop {
+ let mut 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();
- } else if outbound.is_empty() {
- // Each Aggregator recovered an output share.
- break;
- } else {
- panic!("Aggregators did not finish the prepare phase at the same time");
+ 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();
+ } else if 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)
+ Ok(out_shares)
+ }
}
#[cfg(test)]
@@ -663,20 +662,17 @@ where
for<'a> T: ParameterizedDecode<(&'a V, &'a V::AggregationParam)>,
{
// Generate an arbitrary vector of field elements.
- let g = F::one() + F::one();
- let vec: Vec<F> = itertools::iterate(F::one(), |&v| g * v)
- .take(length)
- .collect();
+ let vec: Vec<F> = crate::field::random_vector(length).unwrap();
// Serialize the field element vector into a vector of bytes.
let mut bytes = Vec::with_capacity(vec.len() * F::ENCODED_SIZE);
- encode_fieldvec(&vec, &mut bytes);
+ 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();
+ let encoded = value.get_encoded().unwrap();
assert_eq!(encoded, bytes);
}
@@ -741,6 +737,7 @@ mod tests {
}
#[cfg(feature = "test-util")]
+#[cfg_attr(docsrs, doc(cfg(feature = "test-util")))]
pub mod dummy;
#[cfg(all(feature = "crypto-dependencies", feature = "experimental"))]
#[cfg_attr(
@@ -748,10 +745,14 @@ pub mod dummy;
doc(cfg(all(feature = "crypto-dependencies", feature = "experimental")))
)]
pub mod poplar1;
-#[cfg(feature = "prio2")]
-#[cfg_attr(docsrs, doc(cfg(feature = "prio2")))]
+#[cfg(all(feature = "crypto-dependencies", feature = "experimental"))]
+#[cfg_attr(
+ docsrs,
+ doc(cfg(all(feature = "crypto-dependencies", feature = "experimental")))
+)]
pub mod prio2;
pub mod prio3;
-#[cfg(test)]
-mod prio3_test;
+#[cfg(any(test, feature = "test-util"))]
+#[cfg_attr(docsrs, doc(cfg(feature = "test-util")))]
+pub mod prio3_test;
pub mod xof;
diff --git a/third_party/rust/prio/src/vdaf/dummy.rs b/third_party/rust/prio/src/vdaf/dummy.rs
index 507e7916bb..2bb0f96b8a 100644
--- a/third_party/rust/prio/src/vdaf/dummy.rs
+++ b/third_party/rust/prio/src/vdaf/dummy.rs
@@ -12,6 +12,9 @@ use crate::{
use rand::random;
use std::{fmt::Debug, io::Cursor, sync::Arc};
+/// The Dummy VDAF does summation modulus 256 so we can predict aggregation results.
+const MODULUS: u64 = u8::MAX as u64 + 1;
+
type ArcPrepInitFn =
Arc<dyn Fn(&AggregationParam) -> Result<(), VdafError> + 'static + Send + Sync>;
type ArcPrepStepFn = Arc<
@@ -49,7 +52,9 @@ impl Vdaf {
move |state| -> Result<PrepareTransition<Self, 0, 16>, VdafError> {
let new_round = state.current_round + 1;
if new_round == rounds {
- Ok(PrepareTransition::Finish(OutputShare(state.input_share)))
+ Ok(PrepareTransition::Finish(OutputShare(u64::from(
+ state.input_share,
+ ))))
} else {
Ok(PrepareTransition::Continue(
PrepareState {
@@ -76,7 +81,7 @@ impl Vdaf {
self
}
- /// Provide an alternate implementation of [`vdaf::Aggregator::prepare_step`].
+ /// Provide an alternate implementation of [`vdaf::Aggregator::prepare_next`].
pub fn with_prep_step_fn<
F: Fn(&PrepareState) -> Result<PrepareTransition<Self, 0, 16>, VdafError>,
>(
@@ -98,16 +103,18 @@ impl Default for Vdaf {
}
impl vdaf::Vdaf for Vdaf {
- const ID: u32 = 0xFFFF0000;
-
type Measurement = u8;
- type AggregateResult = u8;
+ type AggregateResult = u64;
type AggregationParam = AggregationParam;
type PublicShare = ();
type InputShare = InputShare;
type OutputShare = OutputShare;
type AggregateShare = AggregateShare;
+ fn algorithm_id(&self) -> u32 {
+ 0xFFFF0000
+ }
+
fn num_aggregators(&self) -> usize {
2
}
@@ -155,7 +162,7 @@ impl vdaf::Aggregator<0, 16> for Vdaf {
fn aggregate<M: IntoIterator<Item = Self::OutputShare>>(
&self,
- _: &Self::AggregationParam,
+ _aggregation_param: &Self::AggregationParam,
output_shares: M,
) -> Result<Self::AggregateShare, VdafError> {
let mut aggregate_share = AggregateShare(0);
@@ -184,12 +191,28 @@ impl vdaf::Client<16> for Vdaf {
}
}
+impl vdaf::Collector for Vdaf {
+ fn unshard<M: IntoIterator<Item = Self::AggregateShare>>(
+ &self,
+ aggregation_param: &Self::AggregationParam,
+ agg_shares: M,
+ _num_measurements: usize,
+ ) -> Result<Self::AggregateResult, VdafError> {
+ Ok(agg_shares
+ .into_iter()
+ .fold(0, |acc, share| (acc + share.0) % MODULUS)
+ // Sum in the aggregation parameter so that collections over the same measurements with
+ // varying parameters will yield predictable but distinct results.
+ + u64::from(aggregation_param.0))
+ }
+}
+
/// A dummy input share.
#[derive(Copy, Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord)]
pub struct InputShare(pub u8);
impl Encode for InputShare {
- fn encode(&self, bytes: &mut Vec<u8>) {
+ fn encode(&self, bytes: &mut Vec<u8>) -> Result<(), CodecError> {
self.0.encode(bytes)
}
@@ -209,7 +232,7 @@ impl Decode for InputShare {
pub struct AggregationParam(pub u8);
impl Encode for AggregationParam {
- fn encode(&self, bytes: &mut Vec<u8>) {
+ fn encode(&self, bytes: &mut Vec<u8>) -> Result<(), CodecError> {
self.0.encode(bytes)
}
@@ -226,17 +249,17 @@ impl Decode for AggregationParam {
/// Dummy output share.
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
-pub struct OutputShare(pub u8);
+pub struct OutputShare(pub u64);
impl Decode for OutputShare {
fn decode(bytes: &mut Cursor<&[u8]>) -> Result<Self, CodecError> {
- Ok(Self(u8::decode(bytes)?))
+ Ok(Self(u64::decode(bytes)?))
}
}
impl Encode for OutputShare {
- fn encode(&self, bytes: &mut Vec<u8>) {
- self.0.encode(bytes);
+ fn encode(&self, bytes: &mut Vec<u8>) -> Result<(), CodecError> {
+ self.0.encode(bytes)
}
fn encoded_len(&self) -> Option<usize> {
@@ -252,9 +275,9 @@ pub struct PrepareState {
}
impl Encode for PrepareState {
- fn encode(&self, bytes: &mut Vec<u8>) {
- self.input_share.encode(bytes);
- self.current_round.encode(bytes);
+ fn encode(&self, bytes: &mut Vec<u8>) -> Result<(), CodecError> {
+ self.input_share.encode(bytes)?;
+ self.current_round.encode(bytes)
}
fn encoded_len(&self) -> Option<usize> {
@@ -282,31 +305,30 @@ impl Aggregatable for AggregateShare {
type OutputShare = OutputShare;
fn merge(&mut self, other: &Self) -> Result<(), VdafError> {
- self.0 += other.0;
+ self.0 = (self.0 + other.0) % MODULUS;
Ok(())
}
fn accumulate(&mut self, out_share: &Self::OutputShare) -> Result<(), VdafError> {
- self.0 += u64::from(out_share.0);
+ self.0 = (self.0 + out_share.0) % MODULUS;
Ok(())
}
}
impl From<OutputShare> for AggregateShare {
fn from(out_share: OutputShare) -> Self {
- Self(u64::from(out_share.0))
+ Self(out_share.0)
}
}
impl Decode for AggregateShare {
fn decode(bytes: &mut Cursor<&[u8]>) -> Result<Self, CodecError> {
- let val = u64::decode(bytes)?;
- Ok(Self(val))
+ Ok(Self(u64::decode(bytes)?))
}
}
impl Encode for AggregateShare {
- fn encode(&self, bytes: &mut Vec<u8>) {
+ fn encode(&self, bytes: &mut Vec<u8>) -> Result<(), CodecError> {
self.0.encode(bytes)
}
@@ -314,3 +336,86 @@ impl Encode for AggregateShare {
self.0.encoded_len()
}
}
+
+/// Returns the aggregate result that the dummy VDAF would compute over the provided measurements,
+/// for the provided aggregation parameter.
+pub fn expected_aggregate_result<M>(aggregation_parameter: u8, measurements: M) -> u64
+where
+ M: IntoIterator<Item = u8>,
+{
+ (measurements.into_iter().map(u64::from).sum::<u64>()) % MODULUS
+ + u64::from(aggregation_parameter)
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+ use crate::vdaf::{test_utils::run_vdaf_sharded, Client};
+ use rand::prelude::*;
+
+ fn run_test(rounds: u32, aggregation_parameter: u8) {
+ let vdaf = Vdaf::new(rounds);
+ let mut verify_key = [0; 0];
+ thread_rng().fill(&mut verify_key[..]);
+ let measurements = [10, 20, 30, 40, 50, 60, 70, 80, 90, 100];
+
+ let mut sharded_measurements = Vec::new();
+ for measurement in measurements {
+ let nonce = thread_rng().gen();
+ let (public_share, input_shares) = vdaf.shard(&measurement, &nonce).unwrap();
+
+ sharded_measurements.push((public_share, nonce, input_shares));
+ }
+
+ let result = run_vdaf_sharded(
+ &vdaf,
+ &AggregationParam(aggregation_parameter),
+ sharded_measurements.clone(),
+ )
+ .unwrap();
+ assert_eq!(
+ result,
+ expected_aggregate_result(aggregation_parameter, measurements)
+ );
+ }
+
+ #[test]
+ fn single_round_agg_param_10() {
+ run_test(1, 10)
+ }
+
+ #[test]
+ fn single_round_agg_param_20() {
+ run_test(1, 20)
+ }
+
+ #[test]
+ fn single_round_agg_param_32() {
+ run_test(1, 32)
+ }
+
+ #[test]
+ fn single_round_agg_param_u8_max() {
+ run_test(1, u8::MAX)
+ }
+
+ #[test]
+ fn two_round_agg_param_10() {
+ run_test(2, 10)
+ }
+
+ #[test]
+ fn two_round_agg_param_20() {
+ run_test(2, 20)
+ }
+
+ #[test]
+ fn two_round_agg_param_32() {
+ run_test(2, 32)
+ }
+
+ #[test]
+ fn two_round_agg_param_u8_max() {
+ run_test(2, u8::MAX)
+ }
+}
diff --git a/third_party/rust/prio/src/vdaf/poplar1.rs b/third_party/rust/prio/src/vdaf/poplar1.rs
index e8591f2049..514ed39069 100644
--- a/third_party/rust/prio/src/vdaf/poplar1.rs
+++ b/third_party/rust/prio/src/vdaf/poplar1.rs
@@ -1,8 +1,8 @@
// SPDX-License-Identifier: MPL-2.0
-//! Implementation of Poplar1 as specified in [[draft-irtf-cfrg-vdaf-07]].
+//! Implementation of Poplar1 as specified in [[draft-irtf-cfrg-vdaf-08]].
//!
-//! [draft-irtf-cfrg-vdaf-07]: https://datatracker.ietf.org/doc/draft-irtf-cfrg-vdaf/07/
+//! [draft-irtf-cfrg-vdaf-08]: https://datatracker.ietf.org/doc/draft-irtf-cfrg-vdaf/08/
use crate::{
codec::{CodecError, Decode, Encode, ParameterizedDecode},
@@ -10,7 +10,7 @@ use crate::{
idpf::{Idpf, IdpfInput, IdpfOutputShare, IdpfPublicShare, IdpfValue, RingBufferCache},
prng::Prng,
vdaf::{
- xof::{Seed, Xof, XofShake128},
+ xof::{Seed, Xof, XofTurboShake128},
Aggregatable, Aggregator, Client, Collector, PrepareTransition, Vdaf, VdafError,
},
};
@@ -34,9 +34,9 @@ const DST_VERIFY_RANDOMNESS: u16 = 4;
impl<P, const SEED_SIZE: usize> Poplar1<P, SEED_SIZE> {
/// Create an instance of [`Poplar1`]. The caller provides the bit length of each
- /// measurement (`BITS` as defined in the [[draft-irtf-cfrg-vdaf-07]]).
+ /// measurement (`BITS` as defined in [[draft-irtf-cfrg-vdaf-08]]).
///
- /// [draft-irtf-cfrg-vdaf-07]: https://datatracker.ietf.org/doc/draft-irtf-cfrg-vdaf/07/
+ /// [draft-irtf-cfrg-vdaf-08]: https://datatracker.ietf.org/doc/draft-irtf-cfrg-vdaf/08/
pub fn new(bits: usize) -> Self {
Self {
bits,
@@ -45,12 +45,12 @@ impl<P, const SEED_SIZE: usize> Poplar1<P, SEED_SIZE> {
}
}
-impl Poplar1<XofShake128, 16> {
- /// Create an instance of [`Poplar1`] using [`XofShake128`]. The caller provides the bit length of
- /// each measurement (`BITS` as defined in the [[draft-irtf-cfrg-vdaf-07]]).
+impl Poplar1<XofTurboShake128, 16> {
+ /// Create an instance of [`Poplar1`] using [`XofTurboShake128`]. The caller provides the bit length of
+ /// each measurement (`BITS` as defined in [[draft-irtf-cfrg-vdaf-08]]).
///
- /// [draft-irtf-cfrg-vdaf-07]: https://datatracker.ietf.org/doc/draft-irtf-cfrg-vdaf/07/
- pub fn new_shake128(bits: usize) -> Self {
+ /// [draft-irtf-cfrg-vdaf-08]: https://datatracker.ietf.org/doc/draft-irtf-cfrg-vdaf/08/
+ pub fn new_turboshake128(bits: usize) -> Self {
Poplar1::new(bits)
}
}
@@ -65,6 +65,7 @@ pub struct Poplar1<P, const SEED_SIZE: usize> {
impl<P: Xof<SEED_SIZE>, const SEED_SIZE: usize> Poplar1<P, SEED_SIZE> {
/// Construct a `Prng` with the given seed and info-string suffix.
fn init_prng<I, B, F>(
+ &self,
seed: &[u8; SEED_SIZE],
usage: u16,
binder_chunks: I,
@@ -75,7 +76,7 @@ impl<P: Xof<SEED_SIZE>, const SEED_SIZE: usize> Poplar1<P, SEED_SIZE> {
P: Xof<SEED_SIZE>,
F: FieldElement,
{
- let mut xof = P::init(seed, &Self::domain_separation_tag(usage));
+ let mut xof = P::init(seed, &self.domain_separation_tag(usage));
for binder_chunk in binder_chunks.into_iter() {
xof.update(binder_chunk.as_ref());
}
@@ -156,15 +157,15 @@ impl<const SEED_SIZE: usize> ConstantTimeEq for Poplar1InputShare<SEED_SIZE> {
}
impl<const SEED_SIZE: usize> Encode for Poplar1InputShare<SEED_SIZE> {
- fn encode(&self, bytes: &mut Vec<u8>) {
- self.idpf_key.encode(bytes);
- self.corr_seed.encode(bytes);
+ fn encode(&self, bytes: &mut Vec<u8>) -> Result<(), CodecError> {
+ self.idpf_key.encode(bytes)?;
+ self.corr_seed.encode(bytes)?;
for corr in self.corr_inner.iter() {
- corr[0].encode(bytes);
- corr[1].encode(bytes);
+ corr[0].encode(bytes)?;
+ corr[1].encode(bytes)?;
}
- self.corr_leaf[0].encode(bytes);
- self.corr_leaf[1].encode(bytes);
+ self.corr_leaf[0].encode(bytes)?;
+ self.corr_leaf[1].encode(bytes)
}
fn encoded_len(&self) -> Option<usize> {
@@ -219,7 +220,7 @@ impl ConstantTimeEq for Poplar1PrepareState {
}
impl Encode for Poplar1PrepareState {
- fn encode(&self, bytes: &mut Vec<u8>) {
+ fn encode(&self, bytes: &mut Vec<u8>) -> Result<(), CodecError> {
self.0.encode(bytes)
}
@@ -268,15 +269,15 @@ impl ConstantTimeEq for PrepareStateVariant {
}
impl Encode for PrepareStateVariant {
- fn encode(&self, bytes: &mut Vec<u8>) {
+ fn encode(&self, bytes: &mut Vec<u8>) -> Result<(), CodecError> {
match self {
PrepareStateVariant::Inner(prep_state) => {
- 0u8.encode(bytes);
- prep_state.encode(bytes);
+ 0u8.encode(bytes)?;
+ prep_state.encode(bytes)
}
PrepareStateVariant::Leaf(prep_state) => {
- 1u8.encode(bytes);
- prep_state.encode(bytes);
+ 1u8.encode(bytes)?;
+ prep_state.encode(bytes)
}
}
}
@@ -342,16 +343,17 @@ impl<F> Debug for PrepareState<F> {
}
impl<F: FieldElement> Encode for PrepareState<F> {
- fn encode(&self, bytes: &mut Vec<u8>) {
- self.sketch.encode(bytes);
+ fn encode(&self, bytes: &mut Vec<u8>) -> Result<(), CodecError> {
+ self.sketch.encode(bytes)?;
// `expect` safety: output_share's length is the same as the number of prefixes; the number
// of prefixes is capped at 2^32-1.
u32::try_from(self.output_share.len())
.expect("Couldn't convert output_share length to u32")
- .encode(bytes);
+ .encode(bytes)?;
for elem in &self.output_share {
- elem.encode(bytes);
+ elem.encode(bytes)?;
}
+ Ok(())
}
fn encoded_len(&self) -> Option<usize> {
@@ -430,14 +432,14 @@ impl<F: ConstantTimeEq> ConstantTimeEq for SketchState<F> {
}
impl<F: FieldElement> Encode for SketchState<F> {
- fn encode(&self, bytes: &mut Vec<u8>) {
+ fn encode(&self, bytes: &mut Vec<u8>) -> Result<(), CodecError> {
match self {
SketchState::RoundOne {
A_share, B_share, ..
} => {
- 0u8.encode(bytes);
- A_share.encode(bytes);
- B_share.encode(bytes);
+ 0u8.encode(bytes)?;
+ A_share.encode(bytes)?;
+ B_share.encode(bytes)
}
SketchState::RoundTwo => 1u8.encode(bytes),
}
@@ -519,19 +521,19 @@ enum PrepareMessageVariant {
}
impl Encode for Poplar1PrepareMessage {
- fn encode(&self, bytes: &mut Vec<u8>) {
+ fn encode(&self, bytes: &mut Vec<u8>) -> Result<(), CodecError> {
match self.0 {
PrepareMessageVariant::SketchInner(vec) => {
- vec[0].encode(bytes);
- vec[1].encode(bytes);
- vec[2].encode(bytes);
+ vec[0].encode(bytes)?;
+ vec[1].encode(bytes)?;
+ vec[2].encode(bytes)
}
PrepareMessageVariant::SketchLeaf(vec) => {
- vec[0].encode(bytes);
- vec[1].encode(bytes);
- vec[2].encode(bytes);
+ vec[0].encode(bytes)?;
+ vec[1].encode(bytes)?;
+ vec[2].encode(bytes)
}
- PrepareMessageVariant::Done => (),
+ PrepareMessageVariant::Done => Ok(()),
}
}
@@ -614,17 +616,19 @@ impl ConstantTimeEq for Poplar1FieldVec {
}
impl Encode for Poplar1FieldVec {
- fn encode(&self, bytes: &mut Vec<u8>) {
+ fn encode(&self, bytes: &mut Vec<u8>) -> Result<(), CodecError> {
match self {
Self::Inner(ref data) => {
for elem in data {
- elem.encode(bytes);
+ elem.encode(bytes)?;
}
+ Ok(())
}
Self::Leaf(ref data) => {
for elem in data {
- elem.encode(bytes);
+ elem.encode(bytes)?;
}
+ Ok(())
}
}
}
@@ -769,11 +773,11 @@ impl Poplar1AggregationParam {
}
impl Encode for Poplar1AggregationParam {
- fn encode(&self, bytes: &mut Vec<u8>) {
+ fn encode(&self, bytes: &mut Vec<u8>) -> Result<(), CodecError> {
// Okay to unwrap because `try_from_prefixes()` checks this conversion succeeds.
let prefix_count = u32::try_from(self.prefixes.len()).unwrap();
- self.level.encode(bytes);
- prefix_count.encode(bytes);
+ self.level.encode(bytes)?;
+ prefix_count.encode(bytes)?;
// The encoding of the prefixes is defined by treating the IDPF indices as integers,
// shifting and ORing them together, and encoding the resulting arbitrary precision integer
@@ -799,6 +803,7 @@ impl Encode for Poplar1AggregationParam {
let mut packed = packed.into_vec();
packed.reverse();
bytes.append(&mut packed);
+ Ok(())
}
fn encoded_len(&self) -> Option<usize> {
@@ -839,7 +844,6 @@ impl Decode for Poplar1AggregationParam {
}
impl<P: Xof<SEED_SIZE>, const SEED_SIZE: usize> Vdaf for Poplar1<P, SEED_SIZE> {
- const ID: u32 = 0x00001000;
type Measurement = IdpfInput;
type AggregateResult = Vec<u64>;
type AggregationParam = Poplar1AggregationParam;
@@ -848,6 +852,10 @@ impl<P: Xof<SEED_SIZE>, const SEED_SIZE: usize> Vdaf for Poplar1<P, SEED_SIZE> {
type OutputShare = Poplar1FieldVec;
type AggregateShare = Poplar1FieldVec;
+ fn algorithm_id(&self) -> u32 {
+ 0x00001000
+ }
+
fn num_aggregators(&self) -> usize {
2
}
@@ -870,7 +878,7 @@ impl<P: Xof<SEED_SIZE>, const SEED_SIZE: usize> Poplar1<P, SEED_SIZE> {
// Generate the authenticator for each inner level of the IDPF tree.
let mut prng =
- Self::init_prng::<_, _, Field64>(&poplar_random[2], DST_SHARD_RANDOMNESS, [&[]]);
+ self.init_prng::<_, _, Field64>(&poplar_random[2], DST_SHARD_RANDOMNESS, [nonce]);
let auth_inner: Vec<Field64> = (0..self.bits - 1).map(|_| prng.get()).collect();
// Generate the authenticator for the last level of the IDPF tree (i.e., the leaves).
@@ -900,12 +908,12 @@ impl<P: Xof<SEED_SIZE>, const SEED_SIZE: usize> Poplar1<P, SEED_SIZE> {
let corr_seed_0 = &poplar_random[0];
let corr_seed_1 = &poplar_random[1];
let mut prng = prng.into_new_field::<Field64>();
- let mut corr_prng_0 = Self::init_prng::<_, _, Field64>(
+ let mut corr_prng_0 = self.init_prng::<_, _, Field64>(
corr_seed_0,
DST_CORR_INNER,
[[0].as_slice(), nonce.as_slice()],
);
- let mut corr_prng_1 = Self::init_prng::<_, _, Field64>(
+ let mut corr_prng_1 = self.init_prng::<_, _, Field64>(
corr_seed_1,
DST_CORR_INNER,
[[1].as_slice(), nonce.as_slice()],
@@ -921,12 +929,12 @@ impl<P: Xof<SEED_SIZE>, const SEED_SIZE: usize> Poplar1<P, SEED_SIZE> {
// Generate the correlated randomness for the leaf nodes.
let mut prng = prng.into_new_field::<Field255>();
- let mut corr_prng_0 = Self::init_prng::<_, _, Field255>(
+ let mut corr_prng_0 = self.init_prng::<_, _, Field255>(
corr_seed_0,
DST_CORR_LEAF,
[[0].as_slice(), nonce.as_slice()],
);
- let mut corr_prng_1 = Self::init_prng::<_, _, Field255>(
+ let mut corr_prng_1 = self.init_prng::<_, _, Field255>(
corr_seed_1,
DST_CORR_LEAF,
[[1].as_slice(), nonce.as_slice()],
@@ -952,6 +960,60 @@ impl<P: Xof<SEED_SIZE>, const SEED_SIZE: usize> Poplar1<P, SEED_SIZE> {
],
))
}
+
+ /// Evaluate the IDPF at the given prefixes and compute the Aggregator's share of the sketch.
+ #[allow(clippy::too_many_arguments)]
+ fn eval_and_sketch<F>(
+ &self,
+ verify_key: &[u8; SEED_SIZE],
+ agg_id: usize,
+ nonce: &[u8; 16],
+ agg_param: &Poplar1AggregationParam,
+ public_share: &Poplar1PublicShare,
+ idpf_key: &Seed<16>,
+ corr_prng: &mut Prng<F, P::SeedStream>,
+ ) -> Result<(Vec<F>, Vec<F>), VdafError>
+ where
+ P: Xof<SEED_SIZE>,
+ F: FieldElement,
+ Poplar1IdpfValue<F>:
+ From<IdpfOutputShare<Poplar1IdpfValue<Field64>, Poplar1IdpfValue<Field255>>>,
+ {
+ let mut verify_prng = self.init_prng(
+ verify_key,
+ DST_VERIFY_RANDOMNESS,
+ [nonce.as_slice(), agg_param.level.to_be_bytes().as_slice()],
+ );
+
+ let mut out_share = Vec::with_capacity(agg_param.prefixes.len());
+ let mut sketch_share = vec![
+ corr_prng.get(), // a_share
+ corr_prng.get(), // b_share
+ corr_prng.get(), // c_share
+ ];
+
+ let mut idpf_eval_cache = RingBufferCache::new(agg_param.prefixes.len());
+ let idpf = Idpf::<Poplar1IdpfValue<Field64>, Poplar1IdpfValue<Field255>>::new((), ());
+ for prefix in agg_param.prefixes.iter() {
+ let share = Poplar1IdpfValue::<F>::from(idpf.eval(
+ agg_id,
+ public_share,
+ idpf_key,
+ prefix,
+ nonce,
+ &mut idpf_eval_cache,
+ )?);
+
+ let r = verify_prng.get();
+ let checked_data_share = share.0[0] * r;
+ sketch_share[0] += checked_data_share;
+ sketch_share[1] += checked_data_share * r;
+ sketch_share[2] += share.0[1] * r;
+ out_share.push(share.0[0]);
+ }
+
+ Ok((out_share, sketch_share))
+ }
}
impl<P: Xof<SEED_SIZE>, const SEED_SIZE: usize> Client<16> for Poplar1<P, SEED_SIZE> {
@@ -1000,7 +1062,7 @@ impl<P: Xof<SEED_SIZE>, const SEED_SIZE: usize> Aggregator<SEED_SIZE, 16>
};
if usize::from(agg_param.level) < self.bits - 1 {
- let mut corr_prng = Self::init_prng::<_, _, Field64>(
+ let mut corr_prng = self.init_prng::<_, _, Field64>(
input_share.corr_seed.as_ref(),
DST_CORR_INNER,
[[agg_id as u8].as_slice(), nonce.as_slice()],
@@ -1011,7 +1073,7 @@ impl<P: Xof<SEED_SIZE>, const SEED_SIZE: usize> Aggregator<SEED_SIZE, 16>
corr_prng.get();
}
- let (output_share, sketch_share) = eval_and_sketch::<P, Field64, SEED_SIZE>(
+ let (output_share, sketch_share) = self.eval_and_sketch::<Field64>(
verify_key,
agg_id,
nonce,
@@ -1033,13 +1095,13 @@ impl<P: Xof<SEED_SIZE>, const SEED_SIZE: usize> Aggregator<SEED_SIZE, 16>
Poplar1FieldVec::Inner(sketch_share),
))
} else {
- let corr_prng = Self::init_prng::<_, _, Field255>(
+ let corr_prng = self.init_prng::<_, _, Field255>(
input_share.corr_seed.as_ref(),
DST_CORR_LEAF,
[[agg_id as u8].as_slice(), nonce.as_slice()],
);
- let (output_share, sketch_share) = eval_and_sketch::<P, Field255, SEED_SIZE>(
+ let (output_share, sketch_share) = self.eval_and_sketch::<Field255>(
verify_key,
agg_id,
nonce,
@@ -1257,59 +1319,6 @@ fn compute_next_corr_shares<F: FieldElement + From<u64>, S: RngCore>(
(corr_0, corr_1)
}
-/// Evaluate the IDPF at the given prefixes and compute the Aggregator's share of the sketch.
-fn eval_and_sketch<P, F, const SEED_SIZE: usize>(
- verify_key: &[u8; SEED_SIZE],
- agg_id: usize,
- nonce: &[u8; 16],
- agg_param: &Poplar1AggregationParam,
- public_share: &Poplar1PublicShare,
- idpf_key: &Seed<16>,
- corr_prng: &mut Prng<F, P::SeedStream>,
-) -> Result<(Vec<F>, Vec<F>), VdafError>
-where
- P: Xof<SEED_SIZE>,
- F: FieldElement,
- Poplar1IdpfValue<F>:
- From<IdpfOutputShare<Poplar1IdpfValue<Field64>, Poplar1IdpfValue<Field255>>>,
-{
- // TODO(cjpatton) spec: Consider not encoding the prefixes here.
- let mut verify_prng = Poplar1::<P, SEED_SIZE>::init_prng(
- verify_key,
- DST_VERIFY_RANDOMNESS,
- [nonce.as_slice(), agg_param.level.to_be_bytes().as_slice()],
- );
-
- let mut out_share = Vec::with_capacity(agg_param.prefixes.len());
- let mut sketch_share = vec![
- corr_prng.get(), // a_share
- corr_prng.get(), // b_share
- corr_prng.get(), // c_share
- ];
-
- let mut idpf_eval_cache = RingBufferCache::new(agg_param.prefixes.len());
- let idpf = Idpf::<Poplar1IdpfValue<Field64>, Poplar1IdpfValue<Field255>>::new((), ());
- for prefix in agg_param.prefixes.iter() {
- let share = Poplar1IdpfValue::<F>::from(idpf.eval(
- agg_id,
- public_share,
- idpf_key,
- prefix,
- nonce,
- &mut idpf_eval_cache,
- )?);
-
- let r = verify_prng.get();
- let checked_data_share = share.0[0] * r;
- sketch_share[0] += checked_data_share;
- sketch_share[1] += checked_data_share * r;
- sketch_share[2] += share.0[1] * r;
- out_share.push(share.0[0]);
- }
-
- Ok((out_share, sketch_share))
-}
-
/// Compute the Aggregator's share of the sketch verifier. The shares should sum to zero.
#[allow(non_snake_case)]
fn finish_sketch<F: FieldElement>(
@@ -1447,9 +1456,9 @@ impl<F> Encode for Poplar1IdpfValue<F>
where
F: FieldElement,
{
- fn encode(&self, bytes: &mut Vec<u8>) {
- self.0[0].encode(bytes);
- self.0[1].encode(bytes);
+ fn encode(&self, bytes: &mut Vec<u8>) -> Result<(), CodecError> {
+ self.0[0].encode(bytes)?;
+ self.0[1].encode(bytes)
}
fn encoded_len(&self) -> Option<usize> {
@@ -1491,7 +1500,7 @@ where
#[cfg(test)]
mod tests {
use super::*;
- use crate::vdaf::{equality_comparison_test, run_vdaf_prepare};
+ use crate::vdaf::{equality_comparison_test, test_utils::run_vdaf_prepare};
use assert_matches::assert_matches;
use rand::prelude::*;
use serde::Deserialize;
@@ -1628,7 +1637,7 @@ mod tests {
#[test]
fn shard_prepare() {
let mut rng = thread_rng();
- let vdaf = Poplar1::new_shake128(64);
+ let vdaf = Poplar1::new_turboshake128(64);
let verify_key = rng.gen();
let input = IdpfInput::from_bytes(b"12341324");
let nonce = rng.gen();
@@ -1672,7 +1681,7 @@ mod tests {
fn heavy_hitters() {
let mut rng = thread_rng();
let verify_key = rng.gen();
- let vdaf = Poplar1::new_shake128(8);
+ let vdaf = Poplar1::new_turboshake128(8);
run_heavy_hitters(
&vdaf,
@@ -1699,7 +1708,7 @@ mod tests {
corr_leaf: [Field255::one(), <Field255 as FieldElement>::zero()],
};
assert_eq!(
- input_share.get_encoded().len(),
+ input_share.get_encoded().unwrap().len(),
input_share.encoded_len().unwrap()
);
@@ -1710,7 +1719,7 @@ mod tests {
Field64::one(),
]));
assert_eq!(
- prep_msg.get_encoded().len(),
+ prep_msg.get_encoded().unwrap().len(),
prep_msg.encoded_len().unwrap()
);
let prep_msg = Poplar1PrepareMessage(PrepareMessageVariant::SketchLeaf([
@@ -1719,24 +1728,24 @@ mod tests {
Field255::one(),
]));
assert_eq!(
- prep_msg.get_encoded().len(),
+ prep_msg.get_encoded().unwrap().len(),
prep_msg.encoded_len().unwrap()
);
let prep_msg = Poplar1PrepareMessage(PrepareMessageVariant::Done);
assert_eq!(
- prep_msg.get_encoded().len(),
+ prep_msg.get_encoded().unwrap().len(),
prep_msg.encoded_len().unwrap()
);
// Field vector variants.
let field_vec = Poplar1FieldVec::Inner(vec![Field64::one(); 23]);
assert_eq!(
- field_vec.get_encoded().len(),
+ field_vec.get_encoded().unwrap().len(),
field_vec.encoded_len().unwrap()
);
let field_vec = Poplar1FieldVec::Leaf(vec![Field255::one(); 23]);
assert_eq!(
- field_vec.get_encoded().len(),
+ field_vec.get_encoded().unwrap().len(),
field_vec.encoded_len().unwrap()
);
@@ -1747,7 +1756,7 @@ mod tests {
]))
.unwrap();
assert_eq!(
- agg_param.get_encoded().len(),
+ agg_param.get_encoded().unwrap().len(),
agg_param.encoded_len().unwrap()
);
let agg_param = Poplar1AggregationParam::try_from_prefixes(Vec::from([
@@ -1756,14 +1765,14 @@ mod tests {
]))
.unwrap();
assert_eq!(
- agg_param.get_encoded().len(),
+ agg_param.get_encoded().unwrap().len(),
agg_param.encoded_len().unwrap()
);
}
#[test]
fn round_trip_prepare_state() {
- let vdaf = Poplar1::new_shake128(1);
+ let vdaf = Poplar1::new_turboshake128(1);
for (agg_id, prep_state) in [
(
0,
@@ -1862,7 +1871,7 @@ mod tests {
})),
),
] {
- let encoded_prep_state = prep_state.get_encoded();
+ let encoded_prep_state = prep_state.get_encoded().unwrap();
assert_eq!(prep_state.encoded_len(), Some(encoded_prep_state.len()));
let decoded_prep_state =
Poplar1PrepareState::get_decoded_with_param(&(&vdaf, agg_id), &encoded_prep_state)
@@ -1947,7 +1956,7 @@ mod tests {
),
] {
let agg_param = Poplar1AggregationParam::try_from_prefixes(prefixes).unwrap();
- let encoded = agg_param.get_encoded();
+ let encoded = agg_param.get_encoded().unwrap();
assert_eq!(encoded, reference_encoding);
let decoded = Poplar1AggregationParam::get_decoded(reference_encoding).unwrap();
assert_eq!(decoded, agg_param);
@@ -2037,7 +2046,7 @@ mod tests {
}
// Shard measurement.
- let poplar = Poplar1::new_shake128(test_vector.bits);
+ let poplar = Poplar1::new_turboshake128(test_vector.bits);
let (public_share, input_shares) = poplar
.shard_with_random(&measurement, &nonce, &idpf_random, &poplar_random)
.unwrap();
@@ -2118,14 +2127,17 @@ mod tests {
Poplar1PublicShare::get_decoded_with_param(&poplar, prep.public_share.as_ref())
.unwrap()
);
- assert_eq!(&public_share.get_encoded(), prep.public_share.as_ref());
+ assert_eq!(
+ &public_share.get_encoded().unwrap(),
+ prep.public_share.as_ref()
+ );
assert_eq!(
input_shares[0],
Poplar1InputShare::get_decoded_with_param(&(&poplar, 0), prep.input_shares[0].as_ref())
.unwrap()
);
assert_eq!(
- &input_shares[0].get_encoded(),
+ &input_shares[0].get_encoded().unwrap(),
prep.input_shares[0].as_ref()
);
assert_eq!(
@@ -2134,7 +2146,7 @@ mod tests {
.unwrap()
);
assert_eq!(
- &input_shares[1].get_encoded(),
+ &input_shares[1].get_encoded().unwrap(),
prep.input_shares[1].as_ref()
);
assert_eq!(
@@ -2146,7 +2158,7 @@ mod tests {
.unwrap()
);
assert_eq!(
- &init_prep_share_0.get_encoded(),
+ &init_prep_share_0.get_encoded().unwrap(),
prep.prep_shares[0][0].as_ref()
);
assert_eq!(
@@ -2158,7 +2170,7 @@ mod tests {
.unwrap()
);
assert_eq!(
- &init_prep_share_1.get_encoded(),
+ &init_prep_share_1.get_encoded().unwrap(),
prep.prep_shares[0][1].as_ref()
);
assert_eq!(
@@ -2169,7 +2181,10 @@ mod tests {
)
.unwrap()
);
- assert_eq!(&r1_prep_msg.get_encoded(), prep.prep_messages[0].as_ref());
+ assert_eq!(
+ &r1_prep_msg.get_encoded().unwrap(),
+ prep.prep_messages[0].as_ref()
+ );
assert_eq!(
r1_prep_share_0,
@@ -2180,7 +2195,7 @@ mod tests {
.unwrap()
);
assert_eq!(
- &r1_prep_share_0.get_encoded(),
+ &r1_prep_share_0.get_encoded().unwrap(),
prep.prep_shares[1][0].as_ref()
);
assert_eq!(
@@ -2192,7 +2207,7 @@ mod tests {
.unwrap()
);
assert_eq!(
- &r1_prep_share_1.get_encoded(),
+ &r1_prep_share_1.get_encoded().unwrap(),
prep.prep_shares[1][1].as_ref()
);
assert_eq!(
@@ -2203,7 +2218,10 @@ mod tests {
)
.unwrap()
);
- assert_eq!(&r2_prep_msg.get_encoded(), prep.prep_messages[1].as_ref());
+ assert_eq!(
+ &r2_prep_msg.get_encoded().unwrap(),
+ prep.prep_messages[1].as_ref()
+ );
for (out_share, expected_out_share) in [
(out_share_0, &prep.out_shares[0]),
(out_share_1, &prep.out_shares[1]),
@@ -2212,13 +2230,13 @@ mod tests {
Poplar1FieldVec::Inner(vec) => {
assert_eq!(vec.len(), expected_out_share.len());
for (element, expected) in vec.iter().zip(expected_out_share.iter()) {
- assert_eq!(&element.get_encoded(), expected.as_ref());
+ assert_eq!(&element.get_encoded().unwrap(), expected.as_ref());
}
}
Poplar1FieldVec::Leaf(vec) => {
assert_eq!(vec.len(), expected_out_share.len());
for (element, expected) in vec.iter().zip(expected_out_share.iter()) {
- assert_eq!(&element.get_encoded(), expected.as_ref());
+ assert_eq!(&element.get_encoded().unwrap(), expected.as_ref());
}
}
};
@@ -2233,7 +2251,7 @@ mod tests {
);
assert_eq!(
- &agg_share_0.get_encoded(),
+ &agg_share_0.get_encoded().unwrap(),
test_vector.agg_shares[0].as_ref()
);
assert_eq!(
@@ -2245,7 +2263,7 @@ mod tests {
.unwrap()
);
assert_eq!(
- &agg_share_1.get_encoded(),
+ &agg_share_1.get_encoded().unwrap(),
test_vector.agg_shares[1].as_ref()
);
assert_eq!(agg_result, test_vector.agg_result);
@@ -2253,22 +2271,22 @@ mod tests {
#[test]
fn test_vec_poplar1_0() {
- check_test_vec(include_str!("test_vec/07/Poplar1_0.json"));
+ check_test_vec(include_str!("test_vec/08/Poplar1_0.json"));
}
#[test]
fn test_vec_poplar1_1() {
- check_test_vec(include_str!("test_vec/07/Poplar1_1.json"));
+ check_test_vec(include_str!("test_vec/08/Poplar1_1.json"));
}
#[test]
fn test_vec_poplar1_2() {
- check_test_vec(include_str!("test_vec/07/Poplar1_2.json"));
+ check_test_vec(include_str!("test_vec/08/Poplar1_2.json"));
}
#[test]
fn test_vec_poplar1_3() {
- check_test_vec(include_str!("test_vec/07/Poplar1_3.json"));
+ check_test_vec(include_str!("test_vec/08/Poplar1_3.json"));
}
#[test]
diff --git a/third_party/rust/prio/src/vdaf/prio2.rs b/third_party/rust/prio/src/vdaf/prio2.rs
index 4669c47d00..ba725d90d7 100644
--- a/third_party/rust/prio/src/vdaf/prio2.rs
+++ b/third_party/rust/prio/src/vdaf/prio2.rs
@@ -88,8 +88,13 @@ impl Prio2 {
)
.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()),
+ };
+
Ok((
- Prio2PrepareState(input_share.truncated(self.input_len)),
+ Prio2PrepareState(truncated_share),
Prio2PrepareShare(verifier_share),
))
}
@@ -117,7 +122,6 @@ impl Prio2 {
}
impl Vdaf for Prio2 {
- const ID: u32 = 0xFFFF0000;
type Measurement = Vec<u32>;
type AggregateResult = Vec<u32>;
type AggregationParam = ();
@@ -126,6 +130,10 @@ impl Vdaf for Prio2 {
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
@@ -184,8 +192,8 @@ impl ConstantTimeEq for Prio2PrepareState {
}
impl Encode for Prio2PrepareState {
- fn encode(&self, bytes: &mut Vec<u8>) {
- self.0.encode(bytes);
+ fn encode(&self, bytes: &mut Vec<u8>) -> Result<(), CodecError> {
+ self.0.encode(bytes)
}
fn encoded_len(&self) -> Option<usize> {
@@ -213,10 +221,10 @@ impl<'a> ParameterizedDecode<(&'a Prio2, usize)> for Prio2PrepareState {
pub struct Prio2PrepareShare(v2_server::VerificationMessage<FieldPrio2>);
impl Encode for Prio2PrepareShare {
- fn encode(&self, bytes: &mut Vec<u8>) {
- self.0.f_r.encode(bytes);
- self.0.g_r.encode(bytes);
- self.0.h_r.encode(bytes);
+ fn encode(&self, bytes: &mut Vec<u8>) -> Result<(), CodecError> {
+ self.0.f_r.encode(bytes)?;
+ self.0.g_r.encode(bytes)?;
+ self.0.h_r.encode(bytes)
}
fn encoded_len(&self) -> Option<usize> {
@@ -388,7 +396,7 @@ mod tests {
use super::*;
use crate::vdaf::{
equality_comparison_test, fieldvec_roundtrip_test, prio2::test_vector::Priov2TestVector,
- run_vdaf,
+ test_utils::run_vdaf,
};
use assert_matches::assert_matches;
use rand::prelude::*;
@@ -434,7 +442,7 @@ mod tests {
)
.unwrap();
- let encoded_prepare_state = prepare_state.get_encoded();
+ let encoded_prepare_state = prepare_state.get_encoded().unwrap();
let decoded_prepare_state = Prio2PrepareState::get_decoded_with_param(
&(&prio2, agg_id),
&encoded_prepare_state,
@@ -446,7 +454,7 @@ mod tests {
encoded_prepare_state.len()
);
- let encoded_prepare_share = prepare_share.get_encoded();
+ let encoded_prepare_share = prepare_share.get_encoded().unwrap();
let decoded_prepare_share =
Prio2PrepareShare::get_decoded_with_param(&prepare_state, &encoded_prepare_share)
.expect("failed to decode prepare share");
diff --git a/third_party/rust/prio/src/vdaf/prio2/client.rs b/third_party/rust/prio/src/vdaf/prio2/client.rs
index dbce39ee3f..9515601d8a 100644
--- a/third_party/rust/prio/src/vdaf/prio2/client.rs
+++ b/third_party/rust/prio/src/vdaf/prio2/client.rs
@@ -4,10 +4,14 @@
//! Primitives for the Prio2 client.
use crate::{
- field::{FftFriendlyFieldElement, FieldError},
+ codec::CodecError,
+ field::FftFriendlyFieldElement,
polynomial::{poly_fft, PolyAuxMemory},
prng::{Prng, PrngError},
- vdaf::{xof::SeedStreamAes128, VdafError},
+ vdaf::{
+ xof::{Seed, SeedStreamAes128},
+ VdafError,
+ },
};
use std::convert::TryFrom;
@@ -32,9 +36,9 @@ pub enum SerializeError {
/// Emitted by `unpack_proof[_mut]` if the serialized share+proof has the wrong length
#[error("serialized input has wrong length")]
UnpackInputSizeMismatch,
- /// Finite field operation error.
- #[error("finite field operation error")]
- Field(#[from] FieldError),
+ /// Codec error.
+ #[error(transparent)]
+ Codec(#[from] CodecError),
}
#[derive(Debug)]
@@ -63,7 +67,7 @@ impl<F: FftFriendlyFieldElement> ClientMemory<F> {
}
Ok(Self {
- prng: Prng::new()?,
+ prng: Prng::from_prio2_seed(Seed::<32>::generate()?.as_ref()),
points_f: vec![F::zero(); n],
points_g: vec![F::zero(); n],
evals_f: vec![F::zero(); 2 * n],
diff --git a/third_party/rust/prio/src/vdaf/prio2/server.rs b/third_party/rust/prio/src/vdaf/prio2/server.rs
index 11c161babf..9d2871c867 100644
--- a/third_party/rust/prio/src/vdaf/prio2/server.rs
+++ b/third_party/rust/prio/src/vdaf/prio2/server.rs
@@ -101,9 +101,13 @@ pub(crate) fn is_valid_share<F: FftFriendlyFieldElement>(
#[cfg(test)]
mod test_util {
use crate::{
+ codec::ParameterizedDecode,
field::{merge_vector, FftFriendlyFieldElement},
prng::Prng,
- vdaf::prio2::client::proof_length,
+ vdaf::{
+ prio2::client::{proof_length, SerializeError},
+ Share, ShareDecodingParameter,
+ },
};
use super::{generate_verification_message, is_valid_share, ServerError, VerificationMessage};
@@ -133,17 +137,17 @@ mod test_util {
/// Deserialize
fn deserialize_share(&self, share: &[u8]) -> Result<Vec<F>, ServerError> {
let len = proof_length(self.dimension);
- Ok(if self.is_first_server {
- F::byte_slice_into_vec(share)?
+ let decoding_parameter = if self.is_first_server {
+ ShareDecodingParameter::Leader(len)
} else {
- if share.len() != 32 {
- return Err(ServerError::ShareLength);
- }
-
- Prng::from_prio2_seed(&share.try_into().unwrap())
- .take(len)
- .collect()
- })
+ 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
@@ -194,14 +198,19 @@ mod test_util {
mod tests {
use super::*;
use crate::{
- codec::Encode,
+ codec::{Encode, ParameterizedDecode},
field::{FieldElement, FieldPrio2},
prng::Prng,
vdaf::{
- prio2::{client::unpack_proof_mut, server::test_util::Server, Prio2},
- Client,
+ 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> {
@@ -286,10 +295,13 @@ mod tests {
let vdaf = Prio2::new(dim).unwrap();
let (_, shares) = vdaf.shard(&data, &[0; 16]).unwrap();
- let share1_original = shares[0].get_encoded();
- let share2 = shares[1].get_encoded();
+ let share1_original = shares[0].get_encoded().unwrap();
+ let share2 = shares[1].get_encoded().unwrap();
- let mut share1_field = FieldPrio2::byte_slice_into_vec(&share1_original).unwrap();
+ let mut share1_field: Vec<FieldPrio2> = assert_matches!(
+ Share::get_decoded_with_param(&ShareDecodingParameter::<32>::Leader(proof_length(dim)), &share1_original),
+ Ok(Share::Leader(vec)) => vec
+ );
let unpacked_share1 = unpack_proof_mut(&mut share1_field, dim).unwrap();
let one = FieldPrio2::from(1);
@@ -304,7 +316,9 @@ mod tests {
};
// reserialize altered share1
- let share1_modified = FieldPrio2::slice_into_byte_vec(&share1_field);
+ let share1_modified = Share::<FieldPrio2, 32>::Leader(share1_field)
+ .get_encoded()
+ .unwrap();
let mut prng = Prng::from_prio2_seed(&random());
let eval_at = vdaf.choose_eval_at(&mut prng);
diff --git a/third_party/rust/prio/src/vdaf/prio2/test_vector.rs b/third_party/rust/prio/src/vdaf/prio2/test_vector.rs
index ae2b8b0f9d..114b437b55 100644
--- a/third_party/rust/prio/src/vdaf/prio2/test_vector.rs
+++ b/third_party/rust/prio/src/vdaf/prio2/test_vector.rs
@@ -48,9 +48,16 @@ mod base64 {
//! instead of an array of an array of integers when serializing to JSON.
//
// Thank you, Alice! https://users.rust-lang.org/t/serialize-a-vec-u8-to-json-as-base64/57781/2
- use crate::field::{FieldElement, FieldPrio2};
+ use crate::{
+ codec::ParameterizedDecode,
+ field::{encode_fieldvec, FieldElement, FieldPrio2},
+ vdaf::{Share, ShareDecodingParameter},
+ };
+ use assert_matches::assert_matches;
use base64::{engine::Engine, prelude::BASE64_STANDARD};
- use serde::{de::Error, Deserialize, Deserializer, Serialize, Serializer};
+ use serde::{
+ de::Error as _, ser::Error as _, Deserialize, Deserializer, Serialize, Serializer,
+ };
pub fn serialize_bytes<S: Serializer>(v: &[Vec<u8>], s: S) -> Result<S::Ok, S::Error> {
let base64_vec = v
@@ -63,21 +70,28 @@ mod base64 {
pub fn deserialize_bytes<'de, D: Deserializer<'de>>(d: D) -> Result<Vec<Vec<u8>>, D::Error> {
<Vec<String>>::deserialize(d)?
.iter()
- .map(|s| BASE64_STANDARD.decode(s.as_bytes()).map_err(Error::custom))
+ .map(|s| {
+ BASE64_STANDARD
+ .decode(s.as_bytes())
+ .map_err(D::Error::custom)
+ })
.collect()
}
pub fn serialize_field<S: Serializer>(v: &[FieldPrio2], s: S) -> Result<S::Ok, S::Error> {
- String::serialize(
- &BASE64_STANDARD.encode(FieldPrio2::slice_into_byte_vec(v)),
- s,
- )
+ let mut bytes = Vec::new();
+ encode_fieldvec(v, &mut bytes).map_err(S::Error::custom)?;
+ String::serialize(&BASE64_STANDARD.encode(&bytes), s)
}
pub fn deserialize_field<'de, D: Deserializer<'de>>(d: D) -> Result<Vec<FieldPrio2>, D::Error> {
let bytes = BASE64_STANDARD
.decode(String::deserialize(d)?.as_bytes())
- .map_err(Error::custom)?;
- FieldPrio2::byte_slice_into_vec(&bytes).map_err(Error::custom)
+ .map_err(D::Error::custom)?;
+ let decoding_parameter =
+ ShareDecodingParameter::<32>::Leader(bytes.len() / FieldPrio2::ENCODED_SIZE);
+ let share = Share::<FieldPrio2, 32>::get_decoded_with_param(&decoding_parameter, &bytes)
+ .map_err(D::Error::custom)?;
+ assert_matches!(share, Share::Leader(vec) => Ok(vec))
}
}
diff --git a/third_party/rust/prio/src/vdaf/prio3.rs b/third_party/rust/prio/src/vdaf/prio3.rs
index 4a7cdefb84..084f87f411 100644
--- a/third_party/rust/prio/src/vdaf/prio3.rs
+++ b/third_party/rust/prio/src/vdaf/prio3.rs
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: MPL-2.0
-//! Implementation of the Prio3 VDAF [[draft-irtf-cfrg-vdaf-07]].
+//! Implementation of the Prio3 VDAF [[draft-irtf-cfrg-vdaf-08]].
//!
//! **WARNING:** This code has not undergone significant security analysis. Use at your own risk.
//!
@@ -9,7 +9,7 @@
//! 2019 [[BBCG+19]], that lead to substantial improvements in terms of run time and communication
//! cost. The security of the construction was analyzed in [[DPRS23]].
//!
-//! Prio3 is a transformation of a Fully Linear Proof (FLP) system [[draft-irtf-cfrg-vdaf-07]] into
+//! Prio3 is a transformation of a Fully Linear Proof (FLP) system [[draft-irtf-cfrg-vdaf-08]] into
//! a VDAF. The base type, [`Prio3`], supports a wide variety of aggregation functions, some of
//! which are instantiated here:
//!
@@ -20,14 +20,14 @@
//!
//! Additional types can be constructed from [`Prio3`] as needed.
//!
-//! (*) denotes that the type is specified in [[draft-irtf-cfrg-vdaf-07]].
+//! (*) denotes that the type is specified in [[draft-irtf-cfrg-vdaf-08]].
//!
//! [BBCG+19]: https://ia.cr/2019/188
//! [CGB17]: https://crypto.stanford.edu/prio/
//! [DPRS23]: https://ia.cr/2023/130
-//! [draft-irtf-cfrg-vdaf-07]: https://datatracker.ietf.org/doc/draft-irtf-cfrg-vdaf/07/
+//! [draft-irtf-cfrg-vdaf-08]: https://datatracker.ietf.org/doc/draft-irtf-cfrg-vdaf/08/
-use super::xof::XofShake128;
+use super::xof::XofTurboShake128;
#[cfg(feature = "experimental")]
use super::AggregatorWithNoise;
use crate::codec::{CodecError, Decode, Encode, ParameterizedDecode};
@@ -72,19 +72,19 @@ const DST_JOINT_RAND_SEED: u16 = 6;
const DST_JOINT_RAND_PART: u16 = 7;
/// The count type. Each measurement is an integer in `[0,2)` and the aggregate result is the sum.
-pub type Prio3Count = Prio3<Count<Field64>, XofShake128, 16>;
+pub type Prio3Count = Prio3<Count<Field64>, XofTurboShake128, 16>;
impl Prio3Count {
/// Construct an instance of Prio3Count with the given number of aggregators.
pub fn new_count(num_aggregators: u8) -> Result<Self, VdafError> {
- Prio3::new(num_aggregators, Count::new())
+ Prio3::new(num_aggregators, 1, 0x00000000, Count::new())
}
}
/// The count-vector type. Each measurement is a vector of integers in `[0,2^bits)` and the
/// aggregate is the element-wise sum.
pub type Prio3SumVec =
- Prio3<SumVec<Field128, ParallelSum<Field128, Mul<Field128>>>, XofShake128, 16>;
+ Prio3<SumVec<Field128, ParallelSum<Field128, Mul<Field128>>>, XofTurboShake128, 16>;
impl Prio3SumVec {
/// Construct an instance of Prio3SumVec with the given number of aggregators. `bits` defines
@@ -96,7 +96,12 @@ impl Prio3SumVec {
len: usize,
chunk_length: usize,
) -> Result<Self, VdafError> {
- Prio3::new(num_aggregators, SumVec::new(bits, len, chunk_length)?)
+ Prio3::new(
+ num_aggregators,
+ 1,
+ 0x00000002,
+ SumVec::new(bits, len, chunk_length)?,
+ )
}
}
@@ -104,8 +109,11 @@ impl Prio3SumVec {
/// time. Note that the improvement is only noticeable for very large input lengths.
#[cfg(feature = "multithreaded")]
#[cfg_attr(docsrs, doc(cfg(feature = "multithreaded")))]
-pub type Prio3SumVecMultithreaded =
- Prio3<SumVec<Field128, ParallelSumMultithreaded<Field128, Mul<Field128>>>, XofShake128, 16>;
+pub type Prio3SumVecMultithreaded = Prio3<
+ SumVec<Field128, ParallelSumMultithreaded<Field128, Mul<Field128>>>,
+ XofTurboShake128,
+ 16,
+>;
#[cfg(feature = "multithreaded")]
impl Prio3SumVecMultithreaded {
@@ -118,13 +126,18 @@ impl Prio3SumVecMultithreaded {
len: usize,
chunk_length: usize,
) -> Result<Self, VdafError> {
- Prio3::new(num_aggregators, SumVec::new(bits, len, chunk_length)?)
+ Prio3::new(
+ num_aggregators,
+ 1,
+ 0x00000002,
+ SumVec::new(bits, len, chunk_length)?,
+ )
}
}
/// The sum type. Each measurement is an integer in `[0,2^bits)` for some `0 < bits < 64` and the
/// aggregate is the sum.
-pub type Prio3Sum = Prio3<Sum<Field128>, XofShake128, 16>;
+pub type Prio3Sum = Prio3<Sum<Field128>, XofTurboShake128, 16>;
impl Prio3Sum {
/// Construct an instance of Prio3Sum with the given number of aggregators and required bit
@@ -136,7 +149,7 @@ impl Prio3Sum {
)));
}
- Prio3::new(num_aggregators, Sum::new(bits)?)
+ Prio3::new(num_aggregators, 1, 0x00000001, Sum::new(bits)?)
}
}
@@ -160,7 +173,7 @@ pub type Prio3FixedPointBoundedL2VecSum<Fx> = Prio3<
ParallelSum<Field128, PolyEval<Field128>>,
ParallelSum<Field128, Mul<Field128>>,
>,
- XofShake128,
+ XofTurboShake128,
16,
>;
@@ -173,7 +186,12 @@ impl<Fx: Fixed + CompatibleFloat> Prio3FixedPointBoundedL2VecSum<Fx> {
entries: usize,
) -> Result<Self, VdafError> {
check_num_aggregators(num_aggregators)?;
- Prio3::new(num_aggregators, FixedPointBoundedL2VecSum::new(entries)?)
+ Prio3::new(
+ num_aggregators,
+ 1,
+ 0xFFFF0000,
+ FixedPointBoundedL2VecSum::new(entries)?,
+ )
}
}
@@ -191,7 +209,7 @@ pub type Prio3FixedPointBoundedL2VecSumMultithreaded<Fx> = Prio3<
ParallelSumMultithreaded<Field128, PolyEval<Field128>>,
ParallelSumMultithreaded<Field128, Mul<Field128>>,
>,
- XofShake128,
+ XofTurboShake128,
16,
>;
@@ -204,14 +222,19 @@ impl<Fx: Fixed + CompatibleFloat> Prio3FixedPointBoundedL2VecSumMultithreaded<Fx
entries: usize,
) -> Result<Self, VdafError> {
check_num_aggregators(num_aggregators)?;
- Prio3::new(num_aggregators, FixedPointBoundedL2VecSum::new(entries)?)
+ Prio3::new(
+ num_aggregators,
+ 1,
+ 0xFFFF0000,
+ FixedPointBoundedL2VecSum::new(entries)?,
+ )
}
}
/// The histogram type. Each measurement is an integer in `[0, length)` and the result is a
/// histogram counting the number of occurrences of each measurement.
pub type Prio3Histogram =
- Prio3<Histogram<Field128, ParallelSum<Field128, Mul<Field128>>>, XofShake128, 16>;
+ Prio3<Histogram<Field128, ParallelSum<Field128, Mul<Field128>>>, XofTurboShake128, 16>;
impl Prio3Histogram {
/// Constructs an instance of Prio3Histogram with the given number of aggregators,
@@ -221,7 +244,12 @@ impl Prio3Histogram {
length: usize,
chunk_length: usize,
) -> Result<Self, VdafError> {
- Prio3::new(num_aggregators, Histogram::new(length, chunk_length)?)
+ Prio3::new(
+ num_aggregators,
+ 1,
+ 0x00000003,
+ Histogram::new(length, chunk_length)?,
+ )
}
}
@@ -229,8 +257,11 @@ impl Prio3Histogram {
/// time. Note that this improvement is only noticeable for very large input lengths.
#[cfg(feature = "multithreaded")]
#[cfg_attr(docsrs, doc(cfg(feature = "multithreaded")))]
-pub type Prio3HistogramMultithreaded =
- Prio3<Histogram<Field128, ParallelSumMultithreaded<Field128, Mul<Field128>>>, XofShake128, 16>;
+pub type Prio3HistogramMultithreaded = Prio3<
+ Histogram<Field128, ParallelSumMultithreaded<Field128, Mul<Field128>>>,
+ XofTurboShake128,
+ 16,
+>;
#[cfg(feature = "multithreaded")]
impl Prio3HistogramMultithreaded {
@@ -241,13 +272,18 @@ impl Prio3HistogramMultithreaded {
length: usize,
chunk_length: usize,
) -> Result<Self, VdafError> {
- Prio3::new(num_aggregators, Histogram::new(length, chunk_length)?)
+ Prio3::new(
+ num_aggregators,
+ 1,
+ 0x00000003,
+ Histogram::new(length, chunk_length)?,
+ )
}
}
/// The average type. Each measurement is an integer in `[0,2^bits)` for some `0 < bits < 64` and
/// the aggregate is the arithmetic average.
-pub type Prio3Average = Prio3<Average<Field128>, XofShake128, 16>;
+pub type Prio3Average = Prio3<Average<Field128>, XofTurboShake128, 16>;
impl Prio3Average {
/// Construct an instance of Prio3Average with the given number of aggregators and required bit
@@ -263,6 +299,8 @@ impl Prio3Average {
Ok(Prio3 {
num_aggregators,
+ num_proofs: 1,
+ algorithm_id: 0xFFFF0000,
typ: Average::new(bits)?,
phantom: PhantomData,
})
@@ -277,7 +315,7 @@ impl Prio3Average {
/// - a [`Xof`] for deriving vectors of field elements from seeds.
///
/// New instances can be defined by aliasing the base type. For example, [`Prio3Count`] is an alias
-/// for `Prio3<Count<Field64>, XofShake128, 16>`.
+/// for `Prio3<Count<Field64>, XofTurboShake128, 16>`.
///
/// ```
/// use prio::vdaf::{
@@ -292,7 +330,7 @@ impl Prio3Average {
/// let mut out_shares = vec![vec![]; num_shares.into()];
/// let mut rng = thread_rng();
/// let verify_key = rng.gen();
-/// let measurements = [0, 1, 1, 1, 0];
+/// let measurements = [false, true, true, true, false];
/// for measurement in measurements {
/// // Shard
/// let nonce = rng.gen::<[u8; 16]>();
@@ -316,7 +354,7 @@ impl Prio3Average {
/// let prep_msg = vdaf.prepare_shares_to_prepare_message(&(), prep_shares).unwrap();
///
/// for (agg_id, state) in prep_states.into_iter().enumerate() {
-/// let out_share = match vdaf.prepare_step(state, prep_msg.clone()).unwrap() {
+/// let out_share = match vdaf.prepare_next(state, prep_msg.clone()).unwrap() {
/// PrepareTransition::Finish(out_share) => out_share,
/// _ => panic!("unexpected transition"),
/// };
@@ -339,6 +377,8 @@ where
P: Xof<SEED_SIZE>,
{
num_aggregators: u8,
+ num_proofs: u8,
+ algorithm_id: u32,
typ: T,
phantom: PhantomData<P>,
}
@@ -348,12 +388,25 @@ where
T: Type,
P: Xof<SEED_SIZE>,
{
- /// Construct an instance of this Prio3 VDAF with the given number of aggregators and the
- /// underlying type.
- pub fn new(num_aggregators: u8, typ: T) -> Result<Self, VdafError> {
+ /// Construct an instance of this Prio3 VDAF with the given number of aggregators, number of
+ /// proofs to generate and verify, the algorithm ID, and the underlying type.
+ pub fn new(
+ num_aggregators: u8,
+ num_proofs: u8,
+ algorithm_id: u32,
+ typ: T,
+ ) -> Result<Self, VdafError> {
check_num_aggregators(num_aggregators)?;
+ if num_proofs == 0 {
+ return Err(VdafError::Uncategorized(
+ "num_proofs must be at least 1".to_string(),
+ ));
+ }
+
Ok(Self {
num_aggregators,
+ num_proofs,
+ algorithm_id,
typ,
phantom: PhantomData,
})
@@ -369,19 +422,72 @@ where
self.typ.verifier_len()
}
+ #[inline]
+ fn num_proofs(&self) -> usize {
+ self.num_proofs.into()
+ }
+
+ fn derive_prove_rands(&self, prove_rand_seed: &Seed<SEED_SIZE>) -> Vec<T::Field> {
+ P::seed_stream(
+ prove_rand_seed,
+ &self.domain_separation_tag(DST_PROVE_RANDOMNESS),
+ &[self.num_proofs],
+ )
+ .into_field_vec(self.typ.prove_rand_len() * self.num_proofs())
+ }
+
fn derive_joint_rand_seed<'a>(
- parts: impl Iterator<Item = &'a Seed<SEED_SIZE>>,
+ &self,
+ joint_rand_parts: impl Iterator<Item = &'a Seed<SEED_SIZE>>,
) -> Seed<SEED_SIZE> {
let mut xof = P::init(
&[0; SEED_SIZE],
- &Self::domain_separation_tag(DST_JOINT_RAND_SEED),
+ &self.domain_separation_tag(DST_JOINT_RAND_SEED),
);
- for part in parts {
+ for part in joint_rand_parts {
xof.update(part.as_ref());
}
xof.into_seed()
}
+ fn derive_joint_rands<'a>(
+ &self,
+ joint_rand_parts: impl Iterator<Item = &'a Seed<SEED_SIZE>>,
+ ) -> (Seed<SEED_SIZE>, Vec<T::Field>) {
+ let joint_rand_seed = self.derive_joint_rand_seed(joint_rand_parts);
+ let joint_rands = P::seed_stream(
+ &joint_rand_seed,
+ &self.domain_separation_tag(DST_JOINT_RANDOMNESS),
+ &[self.num_proofs],
+ )
+ .into_field_vec(self.typ.joint_rand_len() * self.num_proofs());
+
+ (joint_rand_seed, joint_rands)
+ }
+
+ fn derive_helper_proofs_share(
+ &self,
+ proofs_share_seed: &Seed<SEED_SIZE>,
+ agg_id: u8,
+ ) -> Prng<T::Field, P::SeedStream> {
+ Prng::from_seed_stream(P::seed_stream(
+ proofs_share_seed,
+ &self.domain_separation_tag(DST_PROOF_SHARE),
+ &[self.num_proofs, agg_id],
+ ))
+ }
+
+ fn derive_query_rands(&self, verify_key: &[u8; SEED_SIZE], nonce: &[u8; 16]) -> Vec<T::Field> {
+ let mut xof = P::init(
+ verify_key,
+ &self.domain_separation_tag(DST_QUERY_RANDOMNESS),
+ );
+ xof.update(&[self.num_proofs]);
+ xof.update(nonce);
+ xof.into_seed_stream()
+ .into_field_vec(self.typ.query_rand_len() * self.num_proofs())
+ }
+
fn random_size(&self) -> usize {
if self.typ.joint_rand_len() == 0 {
// Two seeds per helper for measurement and proof shares, plus one seed for proving
@@ -438,42 +544,45 @@ where
let proof_share_seed = random_seeds.next().unwrap().try_into().unwrap();
let measurement_share_prng: Prng<T::Field, _> = Prng::from_seed_stream(P::seed_stream(
&Seed(measurement_share_seed),
- &Self::domain_separation_tag(DST_MEASUREMENT_SHARE),
+ &self.domain_separation_tag(DST_MEASUREMENT_SHARE),
&[agg_id],
));
- let joint_rand_blind =
- if let Some(helper_joint_rand_parts) = helper_joint_rand_parts.as_mut() {
- let joint_rand_blind = random_seeds.next().unwrap().try_into().unwrap();
- let mut joint_rand_part_xof = P::init(
- &joint_rand_blind,
- &Self::domain_separation_tag(DST_JOINT_RAND_PART),
- );
- joint_rand_part_xof.update(&[agg_id]); // Aggregator ID
- joint_rand_part_xof.update(nonce);
-
- let mut encoding_buffer = Vec::with_capacity(T::Field::ENCODED_SIZE);
- for (x, y) in leader_measurement_share
- .iter_mut()
- .zip(measurement_share_prng)
- {
- *x -= y;
- y.encode(&mut encoding_buffer);
- joint_rand_part_xof.update(&encoding_buffer);
- encoding_buffer.clear();
- }
+ let joint_rand_blind = if let Some(helper_joint_rand_parts) =
+ helper_joint_rand_parts.as_mut()
+ {
+ let joint_rand_blind = random_seeds.next().unwrap().try_into().unwrap();
+ let mut joint_rand_part_xof = P::init(
+ &joint_rand_blind,
+ &self.domain_separation_tag(DST_JOINT_RAND_PART),
+ );
+ joint_rand_part_xof.update(&[agg_id]); // Aggregator ID
+ joint_rand_part_xof.update(nonce);
+
+ let mut encoding_buffer = Vec::with_capacity(T::Field::ENCODED_SIZE);
+ for (x, y) in leader_measurement_share
+ .iter_mut()
+ .zip(measurement_share_prng)
+ {
+ *x -= y;
+ y.encode(&mut encoding_buffer).map_err(|_| {
+ VdafError::Uncategorized("failed to encode measurement share".to_string())
+ })?;
+ joint_rand_part_xof.update(&encoding_buffer);
+ encoding_buffer.clear();
+ }
- helper_joint_rand_parts.push(joint_rand_part_xof.into_seed());
+ helper_joint_rand_parts.push(joint_rand_part_xof.into_seed());
- Some(joint_rand_blind)
- } else {
- for (x, y) in leader_measurement_share
- .iter_mut()
- .zip(measurement_share_prng)
- {
- *x -= y;
- }
- None
- };
+ Some(joint_rand_blind)
+ } else {
+ for (x, y) in leader_measurement_share
+ .iter_mut()
+ .zip(measurement_share_prng)
+ {
+ *x -= y;
+ }
+ None
+ };
let helper =
HelperShare::from_seeds(measurement_share_seed, proof_share_seed, joint_rand_blind);
helper_shares.push(helper);
@@ -483,71 +592,75 @@ where
let public_share = Prio3PublicShare {
joint_rand_parts: helper_joint_rand_parts
.as_ref()
- .map(|helper_joint_rand_parts| {
- let leader_blind_bytes = random_seeds.next().unwrap().try_into().unwrap();
- let leader_blind = Seed::from_bytes(leader_blind_bytes);
-
- let mut joint_rand_part_xof = P::init(
- leader_blind.as_ref(),
- &Self::domain_separation_tag(DST_JOINT_RAND_PART),
- );
- joint_rand_part_xof.update(&[0]); // Aggregator ID
- joint_rand_part_xof.update(nonce);
- let mut encoding_buffer = Vec::with_capacity(T::Field::ENCODED_SIZE);
- for x in leader_measurement_share.iter() {
- x.encode(&mut encoding_buffer);
- joint_rand_part_xof.update(&encoding_buffer);
- encoding_buffer.clear();
- }
- leader_blind_opt = Some(leader_blind);
-
- let leader_joint_rand_seed_part = joint_rand_part_xof.into_seed();
-
- let mut vec = Vec::with_capacity(self.num_aggregators());
- vec.push(leader_joint_rand_seed_part);
- vec.extend(helper_joint_rand_parts.iter().cloned());
- vec
- }),
+ .map(
+ |helper_joint_rand_parts| -> Result<Vec<Seed<SEED_SIZE>>, VdafError> {
+ let leader_blind_bytes = random_seeds.next().unwrap().try_into().unwrap();
+ let leader_blind = Seed::from_bytes(leader_blind_bytes);
+
+ let mut joint_rand_part_xof = P::init(
+ leader_blind.as_ref(),
+ &self.domain_separation_tag(DST_JOINT_RAND_PART),
+ );
+ joint_rand_part_xof.update(&[0]); // Aggregator ID
+ joint_rand_part_xof.update(nonce);
+ let mut encoding_buffer = Vec::with_capacity(T::Field::ENCODED_SIZE);
+ for x in leader_measurement_share.iter() {
+ x.encode(&mut encoding_buffer).map_err(|_| {
+ VdafError::Uncategorized(
+ "failed to encode measurement share".to_string(),
+ )
+ })?;
+ joint_rand_part_xof.update(&encoding_buffer);
+ encoding_buffer.clear();
+ }
+ leader_blind_opt = Some(leader_blind);
+
+ let leader_joint_rand_seed_part = joint_rand_part_xof.into_seed();
+
+ let mut vec = Vec::with_capacity(self.num_aggregators());
+ vec.push(leader_joint_rand_seed_part);
+ vec.extend(helper_joint_rand_parts.iter().cloned());
+ Ok(vec)
+ },
+ )
+ .transpose()?,
};
// Compute the joint randomness.
- let joint_rand: Vec<T::Field> = public_share
+ let joint_rands = public_share
.joint_rand_parts
.as_ref()
- .map(|joint_rand_parts| {
- let joint_rand_seed = Self::derive_joint_rand_seed(joint_rand_parts.iter());
- P::seed_stream(
- &joint_rand_seed,
- &Self::domain_separation_tag(DST_JOINT_RANDOMNESS),
- &[],
- )
- .into_field_vec(self.typ.joint_rand_len())
- })
+ .map(|joint_rand_parts| self.derive_joint_rands(joint_rand_parts.iter()).1)
.unwrap_or_default();
- // Run the proof-generation algorithm.
- let prove_rand_seed = random_seeds.next().unwrap().try_into().unwrap();
- let prove_rand = P::seed_stream(
- &Seed::from_bytes(prove_rand_seed),
- &Self::domain_separation_tag(DST_PROVE_RANDOMNESS),
- &[],
- )
- .into_field_vec(self.typ.prove_rand_len());
- let mut leader_proof_share =
- self.typ
- .prove(&encoded_measurement, &prove_rand, &joint_rand)?;
+ // Generate the proofs.
+ let prove_rands = self.derive_prove_rands(&Seed::from_bytes(
+ random_seeds.next().unwrap().try_into().unwrap(),
+ ));
+ let mut leader_proofs_share = Vec::with_capacity(self.typ.proof_len() * self.num_proofs());
+ for p in 0..self.num_proofs() {
+ let prove_rand =
+ &prove_rands[p * self.typ.prove_rand_len()..(p + 1) * self.typ.prove_rand_len()];
+ let joint_rand =
+ &joint_rands[p * self.typ.joint_rand_len()..(p + 1) * self.typ.joint_rand_len()];
+
+ leader_proofs_share.append(&mut self.typ.prove(
+ &encoded_measurement,
+ prove_rand,
+ joint_rand,
+ )?);
+ }
// Generate the proof shares and distribute the joint randomness seed hints.
for (j, helper) in helper_shares.iter_mut().enumerate() {
- let proof_share_prng: Prng<T::Field, _> = Prng::from_seed_stream(P::seed_stream(
- &helper.proof_share,
- &Self::domain_separation_tag(DST_PROOF_SHARE),
- &[j as u8 + 1],
- ));
- for (x, y) in leader_proof_share
- .iter_mut()
- .zip(proof_share_prng)
- .take(self.typ.proof_len())
+ for (x, y) in
+ leader_proofs_share
+ .iter_mut()
+ .zip(self.derive_helper_proofs_share(
+ &helper.proofs_share,
+ u8::try_from(j).unwrap() + 1,
+ ))
+ .take(self.typ.proof_len() * self.num_proofs())
{
*x -= y;
}
@@ -557,14 +670,14 @@ where
let mut out = Vec::with_capacity(num_aggregators as usize);
out.push(Prio3InputShare {
measurement_share: Share::Leader(leader_measurement_share),
- proof_share: Share::Leader(leader_proof_share),
+ proofs_share: Share::Leader(leader_proofs_share),
joint_rand_blind: leader_blind_opt,
});
for helper in helper_shares.into_iter() {
out.push(Prio3InputShare {
measurement_share: Share::Helper(helper.measurement_share),
- proof_share: Share::Helper(helper.proof_share),
+ proofs_share: Share::Helper(helper.proofs_share),
joint_rand_blind: helper.joint_rand_blind,
});
}
@@ -585,7 +698,6 @@ where
T: Type,
P: Xof<SEED_SIZE>,
{
- const ID: u32 = T::ID;
type Measurement = T::Measurement;
type AggregateResult = T::AggregateResult;
type AggregationParam = ();
@@ -594,6 +706,10 @@ where
type OutputShare = OutputShare<T::Field>;
type AggregateShare = AggregateShare<T::Field>;
+ fn algorithm_id(&self) -> u32 {
+ self.algorithm_id
+ }
+
fn num_aggregators(&self) -> usize {
self.num_aggregators as usize
}
@@ -607,12 +723,13 @@ pub struct Prio3PublicShare<const SEED_SIZE: usize> {
}
impl<const SEED_SIZE: usize> Encode for Prio3PublicShare<SEED_SIZE> {
- fn encode(&self, bytes: &mut Vec<u8>) {
+ fn encode(&self, bytes: &mut Vec<u8>) -> Result<(), CodecError> {
if let Some(joint_rand_parts) = self.joint_rand_parts.as_ref() {
for part in joint_rand_parts.iter() {
- part.encode(bytes);
+ part.encode(bytes)?;
}
}
+ Ok(())
}
fn encoded_len(&self) -> Option<usize> {
@@ -675,7 +792,7 @@ pub struct Prio3InputShare<F, const SEED_SIZE: usize> {
measurement_share: Share<F, SEED_SIZE>,
/// The proof share.
- proof_share: Share<F, SEED_SIZE>,
+ proofs_share: Share<F, SEED_SIZE>,
/// Blinding seed used by the Aggregator to compute the joint randomness. This field is optional
/// because not every [`Type`] requires joint randomness.
@@ -697,28 +814,29 @@ impl<F: ConstantTimeEq, const SEED_SIZE: usize> ConstantTimeEq for Prio3InputSha
self.joint_rand_blind.as_ref(),
other.joint_rand_blind.as_ref(),
) & self.measurement_share.ct_eq(&other.measurement_share)
- & self.proof_share.ct_eq(&other.proof_share)
+ & self.proofs_share.ct_eq(&other.proofs_share)
}
}
impl<F: FftFriendlyFieldElement, const SEED_SIZE: usize> Encode for Prio3InputShare<F, SEED_SIZE> {
- fn encode(&self, bytes: &mut Vec<u8>) {
+ fn encode(&self, bytes: &mut Vec<u8>) -> Result<(), CodecError> {
if matches!(
- (&self.measurement_share, &self.proof_share),
+ (&self.measurement_share, &self.proofs_share),
(Share::Leader(_), Share::Helper(_)) | (Share::Helper(_), Share::Leader(_))
) {
panic!("tried to encode input share with ambiguous encoding")
}
- self.measurement_share.encode(bytes);
- self.proof_share.encode(bytes);
+ self.measurement_share.encode(bytes)?;
+ self.proofs_share.encode(bytes)?;
if let Some(ref blind) = self.joint_rand_blind {
- blind.encode(bytes);
+ blind.encode(bytes)?;
}
+ Ok(())
}
fn encoded_len(&self) -> Option<usize> {
- let mut len = self.measurement_share.encoded_len()? + self.proof_share.encoded_len()?;
+ let mut len = self.measurement_share.encoded_len()? + self.proofs_share.encoded_len()?;
if let Some(ref blind) = self.joint_rand_blind {
len += blind.encoded_len()?;
}
@@ -742,7 +860,7 @@ where
let (input_decoder, proof_decoder) = if agg_id == 0 {
(
ShareDecodingParameter::Leader(prio3.typ.input_len()),
- ShareDecodingParameter::Leader(prio3.typ.proof_len()),
+ ShareDecodingParameter::Leader(prio3.typ.proof_len() * prio3.num_proofs()),
)
} else {
(
@@ -752,7 +870,7 @@ where
};
let measurement_share = Share::decode_with_param(&input_decoder, bytes)?;
- let proof_share = Share::decode_with_param(&proof_decoder, bytes)?;
+ let proofs_share = Share::decode_with_param(&proof_decoder, bytes)?;
let joint_rand_blind = if prio3.typ.joint_rand_len() > 0 {
let blind = Seed::decode(bytes)?;
Some(blind)
@@ -762,7 +880,7 @@ where
Ok(Prio3InputShare {
measurement_share,
- proof_share,
+ proofs_share,
joint_rand_blind,
})
}
@@ -772,7 +890,7 @@ where
/// Message broadcast by each [`Aggregator`] in each round of the Preparation phase.
pub struct Prio3PrepareShare<F, const SEED_SIZE: usize> {
/// A share of the FLP verifier message. (See [`Type`].)
- verifier: Vec<F>,
+ verifiers: Vec<F>,
/// A part of the joint randomness seed.
joint_rand_part: Option<Seed<SEED_SIZE>>,
@@ -792,25 +910,26 @@ impl<F: ConstantTimeEq, const SEED_SIZE: usize> ConstantTimeEq for Prio3PrepareS
option_ct_eq(
self.joint_rand_part.as_ref(),
other.joint_rand_part.as_ref(),
- ) & self.verifier.ct_eq(&other.verifier)
+ ) & self.verifiers.ct_eq(&other.verifiers)
}
}
impl<F: FftFriendlyFieldElement, const SEED_SIZE: usize> Encode
for Prio3PrepareShare<F, SEED_SIZE>
{
- fn encode(&self, bytes: &mut Vec<u8>) {
- for x in &self.verifier {
- x.encode(bytes);
+ fn encode(&self, bytes: &mut Vec<u8>) -> Result<(), CodecError> {
+ for x in &self.verifiers {
+ x.encode(bytes)?;
}
if let Some(ref seed) = self.joint_rand_part {
- seed.encode(bytes);
+ seed.encode(bytes)?;
}
+ Ok(())
}
fn encoded_len(&self) -> Option<usize> {
// Each element of the verifier has the same size.
- let mut len = F::ENCODED_SIZE * self.verifier.len();
+ let mut len = F::ENCODED_SIZE * self.verifiers.len();
if let Some(ref seed) = self.joint_rand_part {
len += seed.encoded_len()?;
}
@@ -825,9 +944,9 @@ impl<F: FftFriendlyFieldElement, const SEED_SIZE: usize>
decoding_parameter: &Prio3PrepareState<F, SEED_SIZE>,
bytes: &mut Cursor<&[u8]>,
) -> Result<Self, CodecError> {
- let mut verifier = Vec::with_capacity(decoding_parameter.verifier_len);
- for _ in 0..decoding_parameter.verifier_len {
- verifier.push(F::decode(bytes)?);
+ let mut verifiers = Vec::with_capacity(decoding_parameter.verifiers_len);
+ for _ in 0..decoding_parameter.verifiers_len {
+ verifiers.push(F::decode(bytes)?);
}
let joint_rand_part = if decoding_parameter.joint_rand_seed.is_some() {
@@ -837,7 +956,7 @@ impl<F: FftFriendlyFieldElement, const SEED_SIZE: usize>
};
Ok(Prio3PrepareShare {
- verifier,
+ verifiers,
joint_rand_part,
})
}
@@ -869,10 +988,11 @@ impl<const SEED_SIZE: usize> ConstantTimeEq for Prio3PrepareMessage<SEED_SIZE> {
}
impl<const SEED_SIZE: usize> Encode for Prio3PrepareMessage<SEED_SIZE> {
- fn encode(&self, bytes: &mut Vec<u8>) {
+ fn encode(&self, bytes: &mut Vec<u8>) -> Result<(), CodecError> {
if let Some(ref seed) = self.joint_rand_seed {
- seed.encode(bytes);
+ seed.encode(bytes)?;
}
+ Ok(())
}
fn encoded_len(&self) -> Option<usize> {
@@ -924,7 +1044,7 @@ pub struct Prio3PrepareState<F, const SEED_SIZE: usize> {
measurement_share: Share<F, SEED_SIZE>,
joint_rand_seed: Option<Seed<SEED_SIZE>>,
agg_id: u8,
- verifier_len: usize,
+ verifiers_len: usize,
}
impl<F: ConstantTimeEq, const SEED_SIZE: usize> PartialEq for Prio3PrepareState<F, SEED_SIZE> {
@@ -939,7 +1059,7 @@ impl<F: ConstantTimeEq, const SEED_SIZE: usize> ConstantTimeEq for Prio3PrepareS
fn ct_eq(&self, other: &Self) -> Choice {
// We allow short-circuiting on the presence or absence of the joint_rand_seed, as well as
// the aggregator ID & verifier length parameters.
- if self.agg_id != other.agg_id || self.verifier_len != other.verifier_len {
+ if self.agg_id != other.agg_id || self.verifiers_len != other.verifiers_len {
return Choice::from(0);
}
@@ -962,7 +1082,7 @@ impl<F, const SEED_SIZE: usize> Debug for Prio3PrepareState<F, SEED_SIZE> {
},
)
.field("agg_id", &self.agg_id)
- .field("verifier_len", &self.verifier_len)
+ .field("verifiers_len", &self.verifiers_len)
.finish()
}
}
@@ -971,11 +1091,12 @@ impl<F: FftFriendlyFieldElement, const SEED_SIZE: usize> Encode
for Prio3PrepareState<F, SEED_SIZE>
{
/// Append the encoded form of this object to the end of `bytes`, growing the vector as needed.
- fn encode(&self, bytes: &mut Vec<u8>) {
- self.measurement_share.encode(bytes);
+ fn encode(&self, bytes: &mut Vec<u8>) -> Result<(), CodecError> {
+ self.measurement_share.encode(bytes)?;
if let Some(ref seed) = self.joint_rand_seed {
- seed.encode(bytes);
+ seed.encode(bytes)?;
}
+ Ok(())
}
fn encoded_len(&self) -> Option<usize> {
@@ -1018,7 +1139,7 @@ where
measurement_share,
joint_rand_seed,
agg_id,
- verifier_len: prio3.typ.verifier_len(),
+ verifiers_len: prio3.typ.verifier_len() * prio3.num_proofs(),
})
}
}
@@ -1051,14 +1172,6 @@ where
VdafError,
> {
let agg_id = self.role_try_from(agg_id)?;
- let mut query_rand_xof = P::init(
- verify_key,
- &Self::domain_separation_tag(DST_QUERY_RANDOMNESS),
- );
- query_rand_xof.update(nonce);
- let query_rand = query_rand_xof
- .into_seed_stream()
- .into_field_vec(self.typ.query_rand_len());
// Create a reference to the (expanded) measurement share.
let expanded_measurement_share: Option<Vec<T::Field>> = match msg.measurement_share {
@@ -1066,7 +1179,7 @@ where
Share::Helper(ref seed) => Some(
P::seed_stream(
seed,
- &Self::domain_separation_tag(DST_MEASUREMENT_SHARE),
+ &self.domain_separation_tag(DST_MEASUREMENT_SHARE),
&[agg_id],
)
.into_field_vec(self.typ.input_len()),
@@ -1078,33 +1191,32 @@ where
};
// Create a reference to the (expanded) proof share.
- let expanded_proof_share: Option<Vec<T::Field>> = match msg.proof_share {
+ let expanded_proofs_share: Option<Vec<T::Field>> = match msg.proofs_share {
Share::Leader(_) => None,
- Share::Helper(ref seed) => Some(
- P::seed_stream(
- seed,
- &Self::domain_separation_tag(DST_PROOF_SHARE),
- &[agg_id],
- )
- .into_field_vec(self.typ.proof_len()),
+ Share::Helper(ref proof_shares_seed) => Some(
+ self.derive_helper_proofs_share(proof_shares_seed, agg_id)
+ .take(self.typ.proof_len() * self.num_proofs())
+ .collect(),
),
};
- let proof_share = match msg.proof_share {
+ let proofs_share = match msg.proofs_share {
Share::Leader(ref data) => data,
- Share::Helper(_) => expanded_proof_share.as_ref().unwrap(),
+ Share::Helper(_) => expanded_proofs_share.as_ref().unwrap(),
};
// Compute the joint randomness.
- let (joint_rand_seed, joint_rand_part, joint_rand) = if self.typ.joint_rand_len() > 0 {
+ let (joint_rand_seed, joint_rand_part, joint_rands) = if self.typ.joint_rand_len() > 0 {
let mut joint_rand_part_xof = P::init(
msg.joint_rand_blind.as_ref().unwrap().as_ref(),
- &Self::domain_separation_tag(DST_JOINT_RAND_PART),
+ &self.domain_separation_tag(DST_JOINT_RAND_PART),
);
joint_rand_part_xof.update(&[agg_id]);
joint_rand_part_xof.update(nonce);
let mut encoding_buffer = Vec::with_capacity(T::Field::ENCODED_SIZE);
for x in measurement_share {
- x.encode(&mut encoding_buffer);
+ x.encode(&mut encoding_buffer).map_err(|_| {
+ VdafError::Uncategorized("failed to encode measurement share".to_string())
+ })?;
joint_rand_part_xof.update(&encoding_buffer);
encoding_buffer.clear();
}
@@ -1131,37 +1243,47 @@ where
.skip(agg_id as usize + 1),
);
- let joint_rand_seed = Self::derive_joint_rand_seed(corrected_joint_rand_parts);
+ let (joint_rand_seed, joint_rands) =
+ self.derive_joint_rands(corrected_joint_rand_parts);
- let joint_rand = P::seed_stream(
- &joint_rand_seed,
- &Self::domain_separation_tag(DST_JOINT_RANDOMNESS),
- &[],
+ (
+ Some(joint_rand_seed),
+ Some(own_joint_rand_part),
+ joint_rands,
)
- .into_field_vec(self.typ.joint_rand_len());
- (Some(joint_rand_seed), Some(own_joint_rand_part), joint_rand)
} else {
(None, None, Vec::new())
};
// Run the query-generation algorithm.
- let verifier_share = self.typ.query(
- measurement_share,
- proof_share,
- &query_rand,
- &joint_rand,
- self.num_aggregators as usize,
- )?;
+ let query_rands = self.derive_query_rands(verify_key, nonce);
+ let mut verifiers_share = Vec::with_capacity(self.typ.verifier_len() * self.num_proofs());
+ for p in 0..self.num_proofs() {
+ let query_rand =
+ &query_rands[p * self.typ.query_rand_len()..(p + 1) * self.typ.query_rand_len()];
+ let joint_rand =
+ &joint_rands[p * self.typ.joint_rand_len()..(p + 1) * self.typ.joint_rand_len()];
+ let proof_share =
+ &proofs_share[p * self.typ.proof_len()..(p + 1) * self.typ.proof_len()];
+
+ verifiers_share.append(&mut self.typ.query(
+ measurement_share,
+ proof_share,
+ query_rand,
+ joint_rand,
+ self.num_aggregators as usize,
+ )?);
+ }
Ok((
Prio3PrepareState {
measurement_share: msg.measurement_share.clone(),
joint_rand_seed,
agg_id,
- verifier_len: verifier_share.len(),
+ verifiers_len: verifiers_share.len(),
},
Prio3PrepareShare {
- verifier: verifier_share,
+ verifiers: verifiers_share,
joint_rand_part,
},
))
@@ -1174,17 +1296,17 @@ where
_: &Self::AggregationParam,
inputs: M,
) -> Result<Prio3PrepareMessage<SEED_SIZE>, VdafError> {
- let mut verifier = vec![T::Field::zero(); self.typ.verifier_len()];
+ let mut verifiers = vec![T::Field::zero(); self.typ.verifier_len() * self.num_proofs()];
let mut joint_rand_parts = Vec::with_capacity(self.num_aggregators());
let mut count = 0;
for share in inputs.into_iter() {
count += 1;
- if share.verifier.len() != verifier.len() {
+ if share.verifiers.len() != verifiers.len() {
return Err(VdafError::Uncategorized(format!(
"unexpected verifier share length: got {}; want {}",
- share.verifier.len(),
- verifier.len(),
+ share.verifiers.len(),
+ verifiers.len(),
)));
}
@@ -1193,7 +1315,7 @@ where
joint_rand_parts.push(joint_rand_seed_part);
}
- for (x, y) in verifier.iter_mut().zip(share.verifier) {
+ for (x, y) in verifiers.iter_mut().zip(share.verifiers) {
*x += y;
}
}
@@ -1205,19 +1327,17 @@ where
)));
}
- // Check the proof verifier.
- match self.typ.decide(&verifier) {
- Ok(true) => (),
- Ok(false) => {
+ // Check the proof verifiers.
+ for verifier in verifiers.chunks(self.typ.verifier_len()) {
+ if !self.typ.decide(verifier)? {
return Err(VdafError::Uncategorized(
"proof verifier check failed".into(),
- ))
+ ));
}
- Err(err) => return Err(VdafError::from(err)),
- };
+ }
let joint_rand_seed = if self.typ.joint_rand_len() > 0 {
- Some(Self::derive_joint_rand_seed(joint_rand_parts.iter()))
+ Some(self.derive_joint_rand_seed(joint_rand_parts.iter()))
} else {
None
};
@@ -1249,7 +1369,7 @@ where
let measurement_share = match step.measurement_share {
Share::Leader(data) => data,
Share::Helper(seed) => {
- let dst = Self::domain_separation_tag(DST_MEASUREMENT_SHARE);
+ let dst = self.domain_separation_tag(DST_MEASUREMENT_SHARE);
P::seed_stream(&seed, &dst, &[step.agg_id]).into_field_vec(self.typ.input_len())
}
};
@@ -1324,7 +1444,7 @@ where
#[derive(Clone)]
struct HelperShare<const SEED_SIZE: usize> {
measurement_share: Seed<SEED_SIZE>,
- proof_share: Seed<SEED_SIZE>,
+ proofs_share: Seed<SEED_SIZE>,
joint_rand_blind: Option<Seed<SEED_SIZE>>,
}
@@ -1336,7 +1456,7 @@ impl<const SEED_SIZE: usize> HelperShare<SEED_SIZE> {
) -> Self {
HelperShare {
measurement_share: Seed::from_bytes(measurement_share),
- proof_share: Seed::from_bytes(proof_share),
+ proofs_share: Seed::from_bytes(proof_share),
joint_rand_blind: joint_rand_blind.map(Seed::from_bytes),
}
}
@@ -1458,7 +1578,8 @@ mod tests {
#[cfg(feature = "experimental")]
use crate::flp::gadgets::ParallelSumGadget;
use crate::vdaf::{
- equality_comparison_test, fieldvec_roundtrip_test, run_vdaf, run_vdaf_prepare,
+ equality_comparison_test, fieldvec_roundtrip_test,
+ test_utils::{run_vdaf, run_vdaf_prepare},
};
use assert_matches::assert_matches;
#[cfg(feature = "experimental")]
@@ -1474,24 +1595,27 @@ mod tests {
fn test_prio3_count() {
let prio3 = Prio3::new_count(2).unwrap();
- assert_eq!(run_vdaf(&prio3, &(), [1, 0, 0, 1, 1]).unwrap(), 3);
+ assert_eq!(
+ run_vdaf(&prio3, &(), [true, false, false, true, true]).unwrap(),
+ 3
+ );
let mut nonce = [0; 16];
let mut verify_key = [0; 16];
thread_rng().fill(&mut verify_key[..]);
thread_rng().fill(&mut nonce[..]);
- let (public_share, input_shares) = prio3.shard(&0, &nonce).unwrap();
+ let (public_share, input_shares) = prio3.shard(&false, &nonce).unwrap();
run_vdaf_prepare(&prio3, &verify_key, &(), &nonce, public_share, input_shares).unwrap();
- let (public_share, input_shares) = prio3.shard(&1, &nonce).unwrap();
+ let (public_share, input_shares) = prio3.shard(&true, &nonce).unwrap();
run_vdaf_prepare(&prio3, &verify_key, &(), &nonce, public_share, input_shares).unwrap();
- test_serialization(&prio3, &1, &nonce).unwrap();
+ test_serialization(&prio3, &true, &nonce).unwrap();
let prio3_extra_helper = Prio3::new_count(3).unwrap();
assert_eq!(
- run_vdaf(&prio3_extra_helper, &(), [1, 0, 0, 1, 1]).unwrap(),
+ run_vdaf(&prio3_extra_helper, &(), [true, false, false, true, true]).unwrap(),
3,
);
}
@@ -1522,7 +1646,7 @@ mod tests {
assert_matches!(result, Err(VdafError::Uncategorized(_)));
let (public_share, mut input_shares) = prio3.shard(&1, &nonce).unwrap();
- assert_matches!(input_shares[0].proof_share, Share::Leader(ref mut data) => {
+ assert_matches!(input_shares[0].proofs_share, Share::Leader(ref mut data) => {
data[0] += Field128::one();
});
let result = run_vdaf_prepare(&prio3, &verify_key, &(), &nonce, public_share, input_shares);
@@ -1550,6 +1674,30 @@ mod tests {
}
#[test]
+ fn test_prio3_sum_vec_multiproof() {
+ let prio3 = Prio3::<
+ SumVec<Field128, ParallelSum<Field128, Mul<Field128>>>,
+ XofTurboShake128,
+ 16,
+ >::new(2, 2, 0xFFFF0000, SumVec::new(2, 20, 4).unwrap())
+ .unwrap();
+
+ assert_eq!(
+ run_vdaf(
+ &prio3,
+ &(),
+ [
+ vec![0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 1, 1, 0, 1],
+ vec![0, 2, 0, 0, 1, 0, 0, 0, 1, 1, 1, 3, 0, 3, 0, 0, 0, 1, 0, 0],
+ vec![1, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 0, 1],
+ ]
+ )
+ .unwrap(),
+ vec![1, 3, 1, 0, 3, 1, 0, 1, 2, 2, 3, 3, 1, 5, 1, 2, 1, 3, 0, 2],
+ );
+ }
+
+ #[test]
#[cfg(feature = "multithreaded")]
fn test_prio3_sum_vec_multithreaded() {
let prio3 = Prio3::new_sum_vec_multithreaded(2, 2, 20, 4).unwrap();
@@ -1598,7 +1746,7 @@ mod tests {
fn test_fixed_vec<Fx, PE, M, const SIZE: usize>(
fp_0: Fx,
- prio3: Prio3<FixedPointBoundedL2VecSum<Fx, PE, M>, XofShake128, 16>,
+ prio3: Prio3<FixedPointBoundedL2VecSum<Fx, PE, M>, XofTurboShake128, 16>,
) where
Fx: Fixed + CompatibleFloat + std::ops::Neg<Output = Fx>,
PE: Eq + ParallelSumGadget<Field128, PolyEval<Field128>> + Clone + 'static,
@@ -1690,7 +1838,7 @@ mod tests {
fp_4_inv: Fx,
fp_8_inv: Fx,
fp_16_inv: Fx,
- prio3: Prio3<FixedPointBoundedL2VecSum<Fx, PE, M>, XofShake128, 16>,
+ prio3: Prio3<FixedPointBoundedL2VecSum<Fx, PE, M>, XofTurboShake128, 16>,
) where
Fx: Fixed + CompatibleFloat + std::ops::Neg<Output = Fx>,
PE: Eq + ParallelSumGadget<Field128, PolyEval<Field128>> + Clone + 'static,
@@ -1752,7 +1900,7 @@ mod tests {
let (public_share, mut input_shares) = prio3
.shard(&vec![fp_4_inv, fp_8_inv, fp_16_inv], &nonce)
.unwrap();
- assert_matches!(input_shares[0].proof_share, Share::Leader(ref mut data) => {
+ assert_matches!(input_shares[0].proofs_share, Share::Leader(ref mut data) => {
data[0] += Field128::one();
});
let result =
@@ -1823,7 +1971,7 @@ mod tests {
}
if let (Share::Helper(left), Share::Helper(right)) =
- (&x.proof_share, &y.proof_share)
+ (&x.proofs_share, &y.proofs_share)
{
assert_ne!(left, right);
}
@@ -1847,7 +1995,7 @@ mod tests {
thread_rng().fill(&mut verify_key[..]);
let (public_share, input_shares) = prio3.shard(measurement, nonce)?;
- let encoded_public_share = public_share.get_encoded();
+ let encoded_public_share = public_share.get_encoded().unwrap();
let decoded_public_share =
Prio3PublicShare::get_decoded_with_param(prio3, &encoded_public_share)
.expect("failed to decode public share");
@@ -1858,7 +2006,7 @@ mod tests {
);
for (agg_id, input_share) in input_shares.iter().enumerate() {
- let encoded_input_share = input_share.get_encoded();
+ let encoded_input_share = input_share.get_encoded().unwrap();
let decoded_input_share =
Prio3InputShare::get_decoded_with_param(&(prio3, agg_id), &encoded_input_share)
.expect("failed to decode input share");
@@ -1875,7 +2023,7 @@ mod tests {
let (prepare_state, prepare_share) =
prio3.prepare_init(&verify_key, agg_id, &(), nonce, &public_share, input_share)?;
- let encoded_prepare_state = prepare_state.get_encoded();
+ let encoded_prepare_state = prepare_state.get_encoded().unwrap();
let decoded_prepare_state =
Prio3PrepareState::get_decoded_with_param(&(prio3, agg_id), &encoded_prepare_state)
.expect("failed to decode prepare state");
@@ -1885,7 +2033,7 @@ mod tests {
encoded_prepare_state.len()
);
- let encoded_prepare_share = prepare_share.get_encoded();
+ let encoded_prepare_share = prepare_share.get_encoded().unwrap();
let decoded_prepare_share =
Prio3PrepareShare::get_decoded_with_param(&prepare_state, &encoded_prepare_share)
.expect("failed to decode prepare share");
@@ -1903,7 +2051,7 @@ mod tests {
.prepare_shares_to_prepare_message(&(), prepare_shares)
.unwrap();
- let encoded_prepare_message = prepare_message.get_encoded();
+ let encoded_prepare_message = prepare_message.get_encoded().unwrap();
let decoded_prepare_message = Prio3PrepareMessage::get_decoded_with_param(
&last_prepare_state.unwrap(),
&encoded_prepare_message,
@@ -1967,31 +2115,31 @@ mod tests {
// Default.
Prio3InputShare {
measurement_share: Share::Leader(Vec::from([0])),
- proof_share: Share::Leader(Vec::from([1])),
+ proofs_share: Share::Leader(Vec::from([1])),
joint_rand_blind: Some(Seed([2])),
},
// Modified measurement share.
Prio3InputShare {
measurement_share: Share::Leader(Vec::from([100])),
- proof_share: Share::Leader(Vec::from([1])),
+ proofs_share: Share::Leader(Vec::from([1])),
joint_rand_blind: Some(Seed([2])),
},
// Modified proof share.
Prio3InputShare {
measurement_share: Share::Leader(Vec::from([0])),
- proof_share: Share::Leader(Vec::from([101])),
+ proofs_share: Share::Leader(Vec::from([101])),
joint_rand_blind: Some(Seed([2])),
},
// Modified joint_rand_blind.
Prio3InputShare {
measurement_share: Share::Leader(Vec::from([0])),
- proof_share: Share::Leader(Vec::from([1])),
+ proofs_share: Share::Leader(Vec::from([1])),
joint_rand_blind: Some(Seed([102])),
},
// Missing joint_rand_blind.
Prio3InputShare {
measurement_share: Share::Leader(Vec::from([0])),
- proof_share: Share::Leader(Vec::from([1])),
+ proofs_share: Share::Leader(Vec::from([1])),
joint_rand_blind: None,
},
])
@@ -2002,22 +2150,22 @@ mod tests {
equality_comparison_test(&[
// Default.
Prio3PrepareShare {
- verifier: Vec::from([0]),
+ verifiers: Vec::from([0]),
joint_rand_part: Some(Seed([1])),
},
// Modified verifier.
Prio3PrepareShare {
- verifier: Vec::from([100]),
+ verifiers: Vec::from([100]),
joint_rand_part: Some(Seed([1])),
},
// Modified joint_rand_part.
Prio3PrepareShare {
- verifier: Vec::from([0]),
+ verifiers: Vec::from([0]),
joint_rand_part: Some(Seed([101])),
},
// Missing joint_rand_part.
Prio3PrepareShare {
- verifier: Vec::from([0]),
+ verifiers: Vec::from([0]),
joint_rand_part: None,
},
])
@@ -2049,42 +2197,42 @@ mod tests {
measurement_share: Share::Leader(Vec::from([0])),
joint_rand_seed: Some(Seed([1])),
agg_id: 2,
- verifier_len: 3,
+ verifiers_len: 3,
},
// Modified measurement share.
Prio3PrepareState {
measurement_share: Share::Leader(Vec::from([100])),
joint_rand_seed: Some(Seed([1])),
agg_id: 2,
- verifier_len: 3,
+ verifiers_len: 3,
},
// Modified joint_rand_seed.
Prio3PrepareState {
measurement_share: Share::Leader(Vec::from([0])),
joint_rand_seed: Some(Seed([101])),
agg_id: 2,
- verifier_len: 3,
+ verifiers_len: 3,
},
// Missing joint_rand_seed.
Prio3PrepareState {
measurement_share: Share::Leader(Vec::from([0])),
joint_rand_seed: None,
agg_id: 2,
- verifier_len: 3,
+ verifiers_len: 3,
},
// Modified agg_id.
Prio3PrepareState {
measurement_share: Share::Leader(Vec::from([0])),
joint_rand_seed: Some(Seed([1])),
agg_id: 102,
- verifier_len: 3,
+ verifiers_len: 3,
},
// Modified verifier_len.
Prio3PrepareState {
measurement_share: Share::Leader(Vec::from([0])),
joint_rand_seed: Some(Seed([1])),
agg_id: 2,
- verifier_len: 103,
+ verifiers_len: 103,
},
])
}
diff --git a/third_party/rust/prio/src/vdaf/prio3_test.rs b/third_party/rust/prio/src/vdaf/prio3_test.rs
index 372a2c8560..9a3dfd85f4 100644
--- a/third_party/rust/prio/src/vdaf/prio3_test.rs
+++ b/third_party/rust/prio/src/vdaf/prio3_test.rs
@@ -1,5 +1,7 @@
// SPDX-License-Identifier: MPL-2.0
+//! Tools for evaluating Prio3 test vectors.
+
use crate::{
codec::{Encode, ParameterizedDecode},
flp::Type,
@@ -58,19 +60,21 @@ macro_rules! err {
// TODO Generalize this method to work with any VDAF. To do so we would need to add
// `shard_with_random()` to traits. (There may be a less invasive alternative.)
-fn check_prep_test_vec<M, T, P, const SEED_SIZE: usize>(
+fn check_prep_test_vec<MS, MP, T, P, const SEED_SIZE: usize>(
prio3: &Prio3<T, P, SEED_SIZE>,
verify_key: &[u8; SEED_SIZE],
test_num: usize,
- t: &TPrio3Prep<M>,
+ t: &TPrio3Prep<MS>,
) -> Vec<OutputShare<T::Field>>
where
- T: Type<Measurement = M>,
+ MS: Clone,
+ MP: From<MS>,
+ T: Type<Measurement = MP>,
P: Xof<SEED_SIZE>,
{
let nonce = <[u8; 16]>::try_from(t.nonce.clone()).unwrap();
let (public_share, input_shares) = prio3
- .shard_with_random(&t.measurement, &nonce, &t.rand)
+ .shard_with_random(&t.measurement.clone().into(), &nonce, &t.rand)
.expect("failed to generate input shares");
assert_eq!(
@@ -86,7 +90,7 @@ where
"#{test_num}"
);
assert_eq!(
- input_shares[agg_id].get_encoded(),
+ input_shares[agg_id].get_encoded().unwrap(),
want.as_ref(),
"#{test_num}"
)
@@ -110,14 +114,18 @@ where
.unwrap_or_else(|e| err!(test_num, e, "decode test vector (prep share)")),
"#{test_num}"
);
- assert_eq!(prep_shares[i].get_encoded(), want.as_ref(), "#{test_num}");
+ assert_eq!(
+ prep_shares[i].get_encoded().unwrap(),
+ want.as_ref(),
+ "#{test_num}"
+ );
}
let inbound = prio3
.prepare_shares_to_prepare_message(&(), prep_shares)
.unwrap_or_else(|e| err!(test_num, e, "prep preprocess"));
assert_eq!(t.prep_messages.len(), 1);
- assert_eq!(inbound.get_encoded(), t.prep_messages[0].as_ref());
+ assert_eq!(inbound.get_encoded().unwrap(), t.prep_messages[0].as_ref());
let mut out_shares = Vec::new();
for state in states.iter_mut() {
@@ -130,7 +138,11 @@ where
}
for (got, want) in out_shares.iter().zip(t.out_shares.iter()) {
- let got: Vec<Vec<u8>> = got.as_ref().iter().map(|x| x.get_encoded()).collect();
+ let got: Vec<Vec<u8>> = got
+ .as_ref()
+ .iter()
+ .map(|x| x.get_encoded().unwrap())
+ .collect();
assert_eq!(got.len(), want.len());
for (got_elem, want_elem) in got.iter().zip(want.iter()) {
assert_eq!(got_elem.as_slice(), want_elem.as_ref());
@@ -141,12 +153,14 @@ where
}
#[must_use]
-fn check_aggregate_test_vec<M, T, P, const SEED_SIZE: usize>(
+fn check_aggregate_test_vec<MS, MP, T, P, const SEED_SIZE: usize>(
prio3: &Prio3<T, P, SEED_SIZE>,
- t: &TPrio3<M>,
+ t: &TPrio3<MS>,
) -> T::AggregateResult
where
- T: Type<Measurement = M>,
+ MS: Clone,
+ MP: From<MS>,
+ T: Type<Measurement = MP>,
P: Xof<SEED_SIZE>,
{
let verify_key = t.verify_key.as_ref().try_into().unwrap();
@@ -167,85 +181,113 @@ where
.collect::<Vec<_>>();
for (got, want) in aggregate_shares.iter().zip(t.agg_shares.iter()) {
- let got = got.get_encoded();
+ let got = got.get_encoded().unwrap();
assert_eq!(got.as_slice(), want.as_ref());
}
prio3.unshard(&(), aggregate_shares, 1).unwrap()
}
+/// Evaluate a Prio3 test vector. The instance of Prio3 is constructed from the `new_vdaf` callback,
+/// which takes in the VDAF parameters encoded by the test vectors and the number of shares.
+///
+/// This version allows customizing the deserialization of measurements, via an additional type
+/// parameter.
+#[cfg(feature = "test-util")]
+#[cfg_attr(docsrs, doc(cfg(feature = "test-util")))]
+pub fn check_test_vec_custom_de<MS, MP, A, T, P, const SEED_SIZE: usize>(
+ test_vec_json_str: &str,
+ new_vdaf: impl Fn(&HashMap<String, serde_json::Value>, u8) -> Prio3<T, P, SEED_SIZE>,
+) where
+ MS: for<'de> Deserialize<'de> + Clone,
+ MP: From<MS>,
+ A: for<'de> Deserialize<'de> + Debug + Eq,
+ T: Type<Measurement = MP, AggregateResult = A>,
+ P: Xof<SEED_SIZE>,
+{
+ let t: TPrio3<MS> = serde_json::from_str(test_vec_json_str).unwrap();
+ let vdaf = new_vdaf(&t.other_params, t.shares);
+ let agg_result = check_aggregate_test_vec(&vdaf, &t);
+ assert_eq!(agg_result, serde_json::from_value(t.agg_result).unwrap());
+}
+
+/// Evaluate a Prio3 test vector. The instance of Prio3 is constructed from the `new_vdaf` callback,
+/// which takes in the VDAF parameters encoded by the test vectors and the number of shares.
+#[cfg(feature = "test-util")]
+#[cfg_attr(docsrs, doc(cfg(feature = "test-util")))]
+pub fn check_test_vec<M, A, T, P, const SEED_SIZE: usize>(
+ test_vec_json_str: &str,
+ new_vdaf: impl Fn(&HashMap<String, serde_json::Value>, u8) -> Prio3<T, P, SEED_SIZE>,
+) where
+ M: for<'de> Deserialize<'de> + Clone,
+ A: for<'de> Deserialize<'de> + Debug + Eq,
+ T: Type<Measurement = M, AggregateResult = A>,
+ P: Xof<SEED_SIZE>,
+{
+ check_test_vec_custom_de::<M, M, _, _, _, SEED_SIZE>(test_vec_json_str, new_vdaf)
+}
+
+#[derive(Debug, Clone, Deserialize)]
+#[serde(transparent)]
+struct Prio3CountMeasurement(u8);
+
+impl From<Prio3CountMeasurement> for bool {
+ fn from(value: Prio3CountMeasurement) -> Self {
+ value.0 != 0
+ }
+}
+
#[test]
fn test_vec_prio3_count() {
for test_vector_str in [
- include_str!("test_vec/07/Prio3Count_0.json"),
- include_str!("test_vec/07/Prio3Count_1.json"),
+ include_str!("test_vec/08/Prio3Count_0.json"),
+ include_str!("test_vec/08/Prio3Count_1.json"),
] {
- let t: TPrio3<u64> = serde_json::from_str(test_vector_str).unwrap();
- let prio3 = Prio3::new_count(t.shares).unwrap();
-
- let aggregate_result = check_aggregate_test_vec(&prio3, &t);
- assert_eq!(aggregate_result, t.agg_result.as_u64().unwrap());
+ check_test_vec_custom_de::<Prio3CountMeasurement, _, _, _, _, 16>(
+ test_vector_str,
+ |_json_params, num_shares| Prio3::new_count(num_shares).unwrap(),
+ );
}
}
#[test]
fn test_vec_prio3_sum() {
for test_vector_str in [
- include_str!("test_vec/07/Prio3Sum_0.json"),
- include_str!("test_vec/07/Prio3Sum_1.json"),
+ include_str!("test_vec/08/Prio3Sum_0.json"),
+ include_str!("test_vec/08/Prio3Sum_1.json"),
] {
- let t: TPrio3<u128> = serde_json::from_str(test_vector_str).unwrap();
- let bits = t.other_params["bits"].as_u64().unwrap() as usize;
- let prio3 = Prio3::new_sum(t.shares, bits).unwrap();
-
- let aggregate_result = check_aggregate_test_vec(&prio3, &t);
- assert_eq!(aggregate_result, t.agg_result.as_u64().unwrap() as u128);
+ check_test_vec(test_vector_str, |json_params, num_shares| {
+ let bits = json_params["bits"].as_u64().unwrap() as usize;
+ Prio3::new_sum(num_shares, bits).unwrap()
+ });
}
}
#[test]
fn test_vec_prio3_sum_vec() {
for test_vector_str in [
- include_str!("test_vec/07/Prio3SumVec_0.json"),
- include_str!("test_vec/07/Prio3SumVec_1.json"),
+ include_str!("test_vec/08/Prio3SumVec_0.json"),
+ include_str!("test_vec/08/Prio3SumVec_1.json"),
] {
- let t: TPrio3<Vec<u128>> = serde_json::from_str(test_vector_str).unwrap();
- let bits = t.other_params["bits"].as_u64().unwrap() as usize;
- let length = t.other_params["length"].as_u64().unwrap() as usize;
- let chunk_length = t.other_params["chunk_length"].as_u64().unwrap() as usize;
- let prio3 = Prio3::new_sum_vec(t.shares, bits, length, chunk_length).unwrap();
-
- let aggregate_result = check_aggregate_test_vec(&prio3, &t);
- let expected_aggregate_result = t
- .agg_result
- .as_array()
- .unwrap()
- .iter()
- .map(|val| val.as_u64().unwrap() as u128)
- .collect::<Vec<u128>>();
- assert_eq!(aggregate_result, expected_aggregate_result);
+ check_test_vec(test_vector_str, |json_params, num_shares| {
+ let bits = json_params["bits"].as_u64().unwrap() as usize;
+ let length = json_params["length"].as_u64().unwrap() as usize;
+ let chunk_length = json_params["chunk_length"].as_u64().unwrap() as usize;
+ Prio3::new_sum_vec(num_shares, bits, length, chunk_length).unwrap()
+ });
}
}
#[test]
fn test_vec_prio3_histogram() {
for test_vector_str in [
- include_str!("test_vec/07/Prio3Histogram_0.json"),
- include_str!("test_vec/07/Prio3Histogram_1.json"),
+ include_str!("test_vec/08/Prio3Histogram_0.json"),
+ include_str!("test_vec/08/Prio3Histogram_1.json"),
] {
- let t: TPrio3<usize> = serde_json::from_str(test_vector_str).unwrap();
- let length = t.other_params["length"].as_u64().unwrap() as usize;
- let chunk_length = t.other_params["chunk_length"].as_u64().unwrap() as usize;
- let prio3 = Prio3::new_histogram(t.shares, length, chunk_length).unwrap();
-
- let aggregate_result = check_aggregate_test_vec(&prio3, &t);
- let expected_aggregate_result = t
- .agg_result
- .as_array()
- .unwrap()
- .iter()
- .map(|val| val.as_u64().unwrap() as u128)
- .collect::<Vec<u128>>();
- assert_eq!(aggregate_result, expected_aggregate_result);
+ check_test_vec(test_vector_str, |json_params, num_shares| {
+ let length = json_params["length"].as_u64().unwrap() as usize;
+ let chunk_length = json_params["chunk_length"].as_u64().unwrap() as usize;
+ Prio3::new_histogram(num_shares, length, chunk_length).unwrap()
+ });
}
}
diff --git a/third_party/rust/prio/src/vdaf/test_vec/07/IdpfPoplar_0.json b/third_party/rust/prio/src/vdaf/test_vec/07/IdpfPoplar_0.json
deleted file mode 100644
index 2ff7aa7ffd..0000000000
--- a/third_party/rust/prio/src/vdaf/test_vec/07/IdpfPoplar_0.json
+++ /dev/null
@@ -1,52 +0,0 @@
-{
- "alpha": "0",
- "beta_inner": [
- [
- "0",
- "0"
- ],
- [
- "1",
- "1"
- ],
- [
- "2",
- "2"
- ],
- [
- "3",
- "3"
- ],
- [
- "4",
- "4"
- ],
- [
- "5",
- "5"
- ],
- [
- "6",
- "6"
- ],
- [
- "7",
- "7"
- ],
- [
- "8",
- "8"
- ]
- ],
- "beta_leaf": [
- "9",
- "9"
- ],
- "binder": "736f6d65206e6f6e6365",
- "bits": 10,
- "keys": [
- "000102030405060708090a0b0c0d0e0f",
- "101112131415161718191a1b1c1d1e1f"
- ],
- "public_share": "921909356f44964d29c537aeeaeba92e573e4298c88dcc35bd3ae6acb4367236226b1af3151d5814f308f04e208fde2110c72523338563bc1c5fb47d22b5c34ae102e1e82fa250c7e23b95e985f91d7d91887fa7fb301ec20a06b1d4408d9a594754dcd86ec00c91f40f17c1ff52ed99fcd59965fe243a6cec7e672fefc5e3a29e653d5dcca8917e8af2c4f19d122c6dd30a3e2a80fb809383ced9d24fcd86516025174f5183fddfc6d74dde3b78834391c785defc8e4fbff92214df4c8322ee433a8eaeed7369419e0d6037a536e081df333aaab9e8e4d207d846961f015d96d57e3b59e24927773d6e0d66108955c1da134baab4eacd363c8e452b8c3845d5fb5c0ff6c27d7423a73d32742ccc3c750a17cd1f6026dd98a2cf6d2bff2dd339017b25af23d6db00ae8975e3f7e6aaef4af71f3e8cd14eb5c4373db9c3a76fc04659b761e650a97cb873df894064ecb2043a4317ef237ffe8f130eb5c2ca2a132c16f14943cd7e462568c8544b82e29329eb2a"
-}
diff --git a/third_party/rust/prio/src/vdaf/test_vec/07/Poplar1_0.json b/third_party/rust/prio/src/vdaf/test_vec/07/Poplar1_0.json
deleted file mode 100644
index 79fadca3df..0000000000
--- a/third_party/rust/prio/src/vdaf/test_vec/07/Poplar1_0.json
+++ /dev/null
@@ -1,56 +0,0 @@
-{
- "agg_param": [
- 0,
- [
- 0,
- 1
- ]
- ],
- "agg_result": [
- 0,
- 1
- ],
- "agg_shares": [
- "70f1cb8dc03c9eea88d270d6211a8667",
- "910e34723ec361157a2d8f29dde57998"
- ],
- "bits": 4,
- "prep": [
- {
- "input_shares": [
- "000102030405060708090a0b0c0d0e0f202122232425262728292a2b2c2d2e2f311e448ab125690bc3a084a34301982c6aa325ab3f268338c9f4db9bda518743ee75c6c8ef7655d2d167d5385213d3bd1be920fad83c1b35fd9239efb406370db4d0a8e97eb41413957e264ded24e074ca433b6b5d451d0f65ec1d4ac246a36da12ecb2a537a449aeeb9d70bd064e930",
- "101112131415161718191a1b1c1d1e1f303132333435363738393a3b3c3d3e3f96998a1415c9876c2887f2dcc52f090ec64bcaeb3165e98f47d261a0bed49a156c054b063cad6277a526505ac31807288abfb796b6cee614e5c41ab75c2b9912cc246c66c5e248a7cfc30ad92eefec7e67c2da39726d5b7277eb1449c779f834b0ab75f383f07bd2f3747cb7b98f617c"
- ],
- "measurement": 13,
- "nonce": "000102030405060708090a0b0c0d0e0f",
- "out_shares": [
- [
- "70f1cb8dc03c9eea",
- "88d270d6211a8667"
- ],
- [
- "910e34723ec36115",
- "7a2d8f29dde57998"
- ]
- ],
- "prep_messages": [
- "d4cd54eb29f676c2d10fab848e6e85ebd51804e3562cf23b",
- ""
- ],
- "prep_shares": [
- [
- "bd68d28c9fff9a30f84122278759025501b83270bf27b41d",
- "1765825e8af6db91d9cd885d07158396d460d17297043e1e"
- ],
- [
- "7c9659b7c681b4a4",
- "8569a648387e4b5b"
- ]
- ],
- "public_share": "b2c16aa5676c3188a74dff403c179dfb28c515d5a9892f38e5eb7be1c96bfdb0ebf761e6500e206a4ce363d09ab0a1d9b225e51798fd599f9dcd204058958c2d625646e5662534ff6650a9af834a248d46304f6d7a3b845f46c71433c833a86846147e264aaee1eb3e0bb19e53cd521e92ab9991265b731bfdb508fb164cd9d48d2c43953e7144a8b97e395bdd8aa2db7a1088f3bf8d245e15172e88764bba8271f6a19f70dc47a279e899394ea8658958",
- "rand": "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f"
- }
- ],
- "shares": 2,
- "verify_key": "000102030405060708090a0b0c0d0e0f"
-}
diff --git a/third_party/rust/prio/src/vdaf/test_vec/07/Poplar1_1.json b/third_party/rust/prio/src/vdaf/test_vec/07/Poplar1_1.json
deleted file mode 100644
index a566fe8b4d..0000000000
--- a/third_party/rust/prio/src/vdaf/test_vec/07/Poplar1_1.json
+++ /dev/null
@@ -1,64 +0,0 @@
-{
- "agg_param": [
- 1,
- [
- 0,
- 1,
- 2,
- 3
- ]
- ],
- "agg_result": [
- 0,
- 0,
- 0,
- 1
- ],
- "agg_shares": [
- "d83fbcbf13566502f5849058b8b089e568a4e8aab8565425f69a56f809fc4527",
- "29c04340eba99afd0c7b6fa7464f761a995b175546a9abda0c65a907f503bad8"
- ],
- "bits": 4,
- "prep": [
- {
- "input_shares": [
- "000102030405060708090a0b0c0d0e0f202122232425262728292a2b2c2d2e2f311e448ab125690bc3a084a34301982c6aa325ab3f268338c9f4db9bda518743ee75c6c8ef7655d2d167d5385213d3bd1be920fad83c1b35fd9239efb406370db4d0a8e97eb41413957e264ded24e074ca433b6b5d451d0f65ec1d4ac246a36da12ecb2a537a449aeeb9d70bd064e930",
- "101112131415161718191a1b1c1d1e1f303132333435363738393a3b3c3d3e3f96998a1415c9876c2887f2dcc52f090ec64bcaeb3165e98f47d261a0bed49a156c054b063cad6277a526505ac31807288abfb796b6cee614e5c41ab75c2b9912cc246c66c5e248a7cfc30ad92eefec7e67c2da39726d5b7277eb1449c779f834b0ab75f383f07bd2f3747cb7b98f617c"
- ],
- "measurement": 13,
- "nonce": "000102030405060708090a0b0c0d0e0f",
- "out_shares": [
- [
- "d83fbcbf13566502",
- "f5849058b8b089e5",
- "68a4e8aab8565425",
- "f69a56f809fc4527"
- ],
- [
- "29c04340eba99afd",
- "0c7b6fa7464f761a",
- "995b175546a9abda",
- "0c65a907f503bad8"
- ]
- ],
- "prep_messages": [
- "d45c0eabcc906acfb8239f3d0ef2b69a0f465979b04e355c",
- ""
- ],
- "prep_shares": [
- [
- "5d1b91841835491251436306076eaaa674d4b95b84b2a084",
- "77417d26b45b21bd68e03b3706840cf49c719f1d2b9c94d7"
- ],
- [
- "6e703a28b5960604",
- "938fc5d74969f9fb"
- ]
- ],
- "public_share": "b2c16aa5676c3188a74dff403c179dfb28c515d5a9892f38e5eb7be1c96bfdb0ebf761e6500e206a4ce363d09ab0a1d9b225e51798fd599f9dcd204058958c2d625646e5662534ff6650a9af834a248d46304f6d7a3b845f46c71433c833a86846147e264aaee1eb3e0bb19e53cd521e92ab9991265b731bfdb508fb164cd9d48d2c43953e7144a8b97e395bdd8aa2db7a1088f3bf8d245e15172e88764bba8271f6a19f70dc47a279e899394ea8658958",
- "rand": "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f"
- }
- ],
- "shares": 2,
- "verify_key": "000102030405060708090a0b0c0d0e0f"
-}
diff --git a/third_party/rust/prio/src/vdaf/test_vec/07/Poplar1_2.json b/third_party/rust/prio/src/vdaf/test_vec/07/Poplar1_2.json
deleted file mode 100644
index 8141bc942e..0000000000
--- a/third_party/rust/prio/src/vdaf/test_vec/07/Poplar1_2.json
+++ /dev/null
@@ -1,64 +0,0 @@
-{
- "agg_param": [
- 2,
- [
- 0,
- 2,
- 4,
- 6
- ]
- ],
- "agg_result": [
- 0,
- 0,
- 0,
- 1
- ],
- "agg_shares": [
- "7ea47022f22f6be9bce8e0ee2eb522bcbc2d246c17704beed7043426b646fe26",
- "835b8fdd0cd0941645171f11d04add4345d2db93e78fb4112bfbcbd948b901d9"
- ],
- "bits": 4,
- "prep": [
- {
- "input_shares": [
- "000102030405060708090a0b0c0d0e0f202122232425262728292a2b2c2d2e2f311e448ab125690bc3a084a34301982c6aa325ab3f268338c9f4db9bda518743ee75c6c8ef7655d2d167d5385213d3bd1be920fad83c1b35fd9239efb406370db4d0a8e97eb41413957e264ded24e074ca433b6b5d451d0f65ec1d4ac246a36da12ecb2a537a449aeeb9d70bd064e930",
- "101112131415161718191a1b1c1d1e1f303132333435363738393a3b3c3d3e3f96998a1415c9876c2887f2dcc52f090ec64bcaeb3165e98f47d261a0bed49a156c054b063cad6277a526505ac31807288abfb796b6cee614e5c41ab75c2b9912cc246c66c5e248a7cfc30ad92eefec7e67c2da39726d5b7277eb1449c779f834b0ab75f383f07bd2f3747cb7b98f617c"
- ],
- "measurement": 13,
- "nonce": "000102030405060708090a0b0c0d0e0f",
- "out_shares": [
- [
- "7ea47022f22f6be9",
- "bce8e0ee2eb522bc",
- "bc2d246c17704bee",
- "d7043426b646fe26"
- ],
- [
- "835b8fdd0cd09416",
- "45171f11d04add43",
- "45d2db93e78fb411",
- "2bfbcbd948b901d9"
- ]
- ],
- "prep_messages": [
- "6fb240ce8b8a2a8ce62112240f676105e0398515599f04b4",
- ""
- ],
- "prep_shares": [
- [
- "ca0f02c7c61655263bf76d954b8abd16eb6e5ce2b26911b2",
- "a5a23e07c573d565ac2aa48ec2dca3eef5ca2833a635f301"
- ],
- [
- "f5171a3cc9d49422",
- "0ce8e5c3352b6bdd"
- ]
- ],
- "public_share": "b2c16aa5676c3188a74dff403c179dfb28c515d5a9892f38e5eb7be1c96bfdb0ebf761e6500e206a4ce363d09ab0a1d9b225e51798fd599f9dcd204058958c2d625646e5662534ff6650a9af834a248d46304f6d7a3b845f46c71433c833a86846147e264aaee1eb3e0bb19e53cd521e92ab9991265b731bfdb508fb164cd9d48d2c43953e7144a8b97e395bdd8aa2db7a1088f3bf8d245e15172e88764bba8271f6a19f70dc47a279e899394ea8658958",
- "rand": "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f"
- }
- ],
- "shares": 2,
- "verify_key": "000102030405060708090a0b0c0d0e0f"
-}
diff --git a/third_party/rust/prio/src/vdaf/test_vec/07/Poplar1_3.json b/third_party/rust/prio/src/vdaf/test_vec/07/Poplar1_3.json
deleted file mode 100644
index 1741ec0ebc..0000000000
--- a/third_party/rust/prio/src/vdaf/test_vec/07/Poplar1_3.json
+++ /dev/null
@@ -1,76 +0,0 @@
-{
- "agg_param": [
- 3,
- [
- 1,
- 3,
- 5,
- 7,
- 9,
- 13,
- 15
- ]
- ],
- "agg_result": [
- 0,
- 0,
- 0,
- 0,
- 0,
- 1,
- 0
- ],
- "agg_shares": [
- "ec2be80f01fd1ded599b1a18d6ef112c400f421cca2c080d4ccc5cdd09562b3e556c1aaabe9dd47e8bc25979394c7bb5c61fd1db34b8dfdcc3eff4a5304fb7706b5462025bb400e644f2e0752f38098702491691494a2b498176ef41c4e6a962f716473c53087a3e80db0b9acb50cb15081b5ea4b50c48093f67a8c75875422dfd64ab2fa71fa3f3b55ec708ba4086672aff514d0cffe6f1c07f117c22af9b2c67b2a0c7ec1366ce474721174edb8b9eb33faef5f9c9d0c956e4407a86473120cfa46e8c634c1bc66c63a2009911f82c8426a45013e637aaba0e471b03f0a67a",
- "01d417f0fe02e212a664e5e72910eed3bff0bde335d3f7f2b333a322f6a9d4419893e55541622b81743da686c6b3844a39e02e24cb4720233c100b5acfb0480f82ab9dfda44bff19bb0d1f8ad0c7f678fdb6e96eb6b5d4b67e8910be3b19561df6e8b8c3acf785c17f24f46534af34eaf7e4a15b4af3b7f6c0985738a78abd52f09a54d058e05c0c4aa138f745bf7998d500aeb2f300190e3f80ee83dd506453874d5f3813ec9931b8b8dee8b12474614cc0510a06362f36a91bbf8579b8ce5f1e5b91739cb3e439939c5dff66ee07d37bd95bafec19c85545f1b8e4fc0f5905"
- ],
- "bits": 4,
- "prep": [
- {
- "input_shares": [
- "000102030405060708090a0b0c0d0e0f202122232425262728292a2b2c2d2e2f311e448ab125690bc3a084a34301982c6aa325ab3f268338c9f4db9bda518743ee75c6c8ef7655d2d167d5385213d3bd1be920fad83c1b35fd9239efb406370db4d0a8e97eb41413957e264ded24e074ca433b6b5d451d0f65ec1d4ac246a36da12ecb2a537a449aeeb9d70bd064e930",
- "101112131415161718191a1b1c1d1e1f303132333435363738393a3b3c3d3e3f96998a1415c9876c2887f2dcc52f090ec64bcaeb3165e98f47d261a0bed49a156c054b063cad6277a526505ac31807288abfb796b6cee614e5c41ab75c2b9912cc246c66c5e248a7cfc30ad92eefec7e67c2da39726d5b7277eb1449c779f834b0ab75f383f07bd2f3747cb7b98f617c"
- ],
- "measurement": 13,
- "nonce": "000102030405060708090a0b0c0d0e0f",
- "out_shares": [
- [
- "ec2be80f01fd1ded599b1a18d6ef112c400f421cca2c080d4ccc5cdd09562b3e",
- "556c1aaabe9dd47e8bc25979394c7bb5c61fd1db34b8dfdcc3eff4a5304fb770",
- "6b5462025bb400e644f2e0752f38098702491691494a2b498176ef41c4e6a962",
- "f716473c53087a3e80db0b9acb50cb15081b5ea4b50c48093f67a8c75875422d",
- "fd64ab2fa71fa3f3b55ec708ba4086672aff514d0cffe6f1c07f117c22af9b2c",
- "67b2a0c7ec1366ce474721174edb8b9eb33faef5f9c9d0c956e4407a86473120",
- "cfa46e8c634c1bc66c63a2009911f82c8426a45013e637aaba0e471b03f0a67a"
- ],
- [
- "01d417f0fe02e212a664e5e72910eed3bff0bde335d3f7f2b333a322f6a9d441",
- "9893e55541622b81743da686c6b3844a39e02e24cb4720233c100b5acfb0480f",
- "82ab9dfda44bff19bb0d1f8ad0c7f678fdb6e96eb6b5d4b67e8910be3b19561d",
- "f6e8b8c3acf785c17f24f46534af34eaf7e4a15b4af3b7f6c0985738a78abd52",
- "f09a54d058e05c0c4aa138f745bf7998d500aeb2f300190e3f80ee83dd506453",
- "874d5f3813ec9931b8b8dee8b12474614cc0510a06362f36a91bbf8579b8ce5f",
- "1e5b91739cb3e439939c5dff66ee07d37bd95bafec19c85545f1b8e4fc0f5905"
- ]
- ],
- "prep_messages": [
- "4a2b97cf17e54b126a86c6791c50d6507ee8b74b3d9903bcf3881121bc6e0975c4efb2d8b8a132b8a6caa4eb39ac2bbb5bdc351604fa9e78d1a6f5a5f615bb0c8819f485d8b24a4e48da47d3b7458a9cfde1e85c66453319a3f6d43dc40a0135",
- ""
- ],
- "prep_shares": [
- [
- "4e64e5ed76c69ef68d3e144918a719986e40ab82f34bd30298b0085a3265d16988b8f646731ef47cb2fb1598e4cb817747623f1cc70ee7843ce1a9d6e3cf5c456801c9a3ae0c7c7663349a3daaf8fb51d165085c751e5bdd4e800df9e1e0193e",
- "fcc6b1e1a01ead1bdc47b23004a9bcb80fa80cc9494d30b95bd808c78909380b2937bc9145833e3bf4ce8e5355e0a943147af6f93cebb7f394c54bcf12465e470d182be229a6ced7e4a5ad950d4d8e4a2c7ce000f126d83b5476c744e229e776"
- ],
- [
- "003c39f76240f6f9bcc6065a247b4432a651d5d72a35aff45928eec28c8a9d07",
- "edc3c6089dbf09064339f9a5db84bbcd59ae2a28d5ca500ba6d7113d73756278"
- ]
- ],
- "public_share": "b2c16aa5676c3188a74dff403c179dfb28c515d5a9892f38e5eb7be1c96bfdb0ebf761e6500e206a4ce363d09ab0a1d9b225e51798fd599f9dcd204058958c2d625646e5662534ff6650a9af834a248d46304f6d7a3b845f46c71433c833a86846147e264aaee1eb3e0bb19e53cd521e92ab9991265b731bfdb508fb164cd9d48d2c43953e7144a8b97e395bdd8aa2db7a1088f3bf8d245e15172e88764bba8271f6a19f70dc47a279e899394ea8658958",
- "rand": "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f"
- }
- ],
- "shares": 2,
- "verify_key": "000102030405060708090a0b0c0d0e0f"
-}
diff --git a/third_party/rust/prio/src/vdaf/test_vec/07/Prio3Count_0.json b/third_party/rust/prio/src/vdaf/test_vec/07/Prio3Count_0.json
deleted file mode 100644
index c27ad93435..0000000000
--- a/third_party/rust/prio/src/vdaf/test_vec/07/Prio3Count_0.json
+++ /dev/null
@@ -1,39 +0,0 @@
-{
- "agg_param": null,
- "agg_result": 1,
- "agg_shares": [
- "afead111dacc0c7e",
- "53152eee2433f381"
- ],
- "prep": [
- {
- "input_shares": [
- "afead111dacc0c7ec08c411babd6e2404df512ddfa0a81736b7607f4ccb3f39e414fdb4bc89a63569702c92aed6a6a96",
- "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f"
- ],
- "measurement": 1,
- "nonce": "000102030405060708090a0b0c0d0e0f",
- "out_shares": [
- [
- "afead111dacc0c7e"
- ],
- [
- "53152eee2433f381"
- ]
- ],
- "prep_messages": [
- ""
- ],
- "prep_shares": [
- [
- "123f23c117b7ed6099be9e6a31a42a9caa60882a3b4aa50303f8b588c9efe60b",
- "efc0dc3ee748129f2da661f47a625a57d64a5b62ab38647c34bb161c7576d721"
- ]
- ],
- "public_share": "",
- "rand": "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f"
- }
- ],
- "shares": 2,
- "verify_key": "000102030405060708090a0b0c0d0e0f"
-}
diff --git a/third_party/rust/prio/src/vdaf/test_vec/07/Prio3Count_1.json b/third_party/rust/prio/src/vdaf/test_vec/07/Prio3Count_1.json
deleted file mode 100644
index 148fe6df58..0000000000
--- a/third_party/rust/prio/src/vdaf/test_vec/07/Prio3Count_1.json
+++ /dev/null
@@ -1,45 +0,0 @@
-{
- "agg_param": null,
- "agg_result": 1,
- "agg_shares": [
- "c5647e016eea69f6",
- "53152eee2433f381",
- "eb8553106be2a287"
- ],
- "prep": [
- {
- "input_shares": [
- "c5647e016eea69f6d10e90d05e2ad8b402b8580f394a719b371ae8f1a364b280d08ca7177946a1a0b9643e2469b0a2e9",
- "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f",
- "202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f"
- ],
- "measurement": 1,
- "nonce": "000102030405060708090a0b0c0d0e0f",
- "out_shares": [
- [
- "c5647e016eea69f6"
- ],
- [
- "53152eee2433f381"
- ],
- [
- "eb8553106be2a287"
- ]
- ],
- "prep_messages": [
- ""
- ],
- "prep_shares": [
- [
- "5c8d00fd24e449d375581d6adbeaf9cf4bdface6d368fd7b1562e5bf47b9fa68",
- "efc0dc3ee748129f2da661f47a625a57d64a5b62ab38647c34bb161c7576d721",
- "b7b122c4f1d2a38df764c623c266f02f7b5178c3d64735ec06037585d643f528"
- ]
- ],
- "public_share": "",
- "rand": "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f"
- }
- ],
- "shares": 3,
- "verify_key": "000102030405060708090a0b0c0d0e0f"
-}
diff --git a/third_party/rust/prio/src/vdaf/test_vec/07/Prio3Histogram_0.json b/third_party/rust/prio/src/vdaf/test_vec/07/Prio3Histogram_0.json
deleted file mode 100644
index 099f786669..0000000000
--- a/third_party/rust/prio/src/vdaf/test_vec/07/Prio3Histogram_0.json
+++ /dev/null
@@ -1,52 +0,0 @@
-{
- "agg_param": null,
- "agg_result": [
- 0,
- 0,
- 1,
- 0
- ],
- "agg_shares": [
- "14be9c4ef7a6e12e963fdeac21cebdd4d36e13f4bc25306322e56303c62c90afd73f6b4aa9fdf33cb0afb55426d645ff8cd7e78cebf9d4f1087f6d4a033c8eae",
- "ed4163b108591ed14dc02153de31422b2e91ec0b43dacf9cc11a9cfc39d36f502bc094b556020cc333504aabd929ba007528187314062b0edb8092b5fcc37151"
- ],
- "chunk_length": 2,
- "length": 4,
- "prep": [
- {
- "input_shares": [
- "14be9c4ef7a6e12e963fdeac21cebdd4d36e13f4bc25306322e56303c62c90afd73f6b4aa9fdf33cb0afb55426d645ff8cd7e78cebf9d4f1087f6d4a033c8eaeec786d3b212d968c939de66318dbacafe73c1f5aa3e9078ba2f63ec5179e6b4694612c36f5d4d539d46dab1ac20e43963978d9dd36f19f31c83e58c903c2cd94215c68b15f5d6071e9e19fa973829dc71b536351b0db1072e77b7570e3e06c65fac248d21dd970f29640050e901d06775f05a897850cab5707ac25543ed6ce7061b9cd70c783e0483727236d0cbb05dafefd78ec4e6419efe93d6f82cdadbfd4e860661238040229f60205bbba983790303132333435363738393a3b3c3d3e3f",
- "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f"
- ],
- "measurement": 2,
- "nonce": "000102030405060708090a0b0c0d0e0f",
- "out_shares": [
- [
- "14be9c4ef7a6e12e963fdeac21cebdd4",
- "d36e13f4bc25306322e56303c62c90af",
- "d73f6b4aa9fdf33cb0afb55426d645ff",
- "8cd7e78cebf9d4f1087f6d4a033c8eae"
- ],
- [
- "ed4163b108591ed14dc02153de31422b",
- "2e91ec0b43dacf9cc11a9cfc39d36f50",
- "2bc094b556020cc333504aabd929ba00",
- "7528187314062b0edb8092b5fcc37151"
- ]
- ],
- "prep_messages": [
- "7556ccbddbd14d509ee89124d31d1feb"
- ],
- "prep_shares": [
- [
- "806b1f8537500ce0b4b501b0ae5ed8f82679ba11ad995d6f605b000e32c41afb6d0070287fe7b99b8304d264cba1e3c6f4456e1c06f3b9d3d4947b2041c86b020d26c74d7663817e6a91960489806931b304fcd3755b43b96c806d2bbeb0166bbec7c61c35f886f3f539890522388f43",
- "8194e07ac8aff31f2f4afe4f51a12707b692a56a1745315a1022b4eb257b2a8725c610416af7b0d1a296f409cdb3fbf4f4c0d488206d794254e4755fd124cdc9a67364ddc7865afe3554de5f52f1ac910f3f8e110cfbad4113861316dc73ec60de4f6c512adaa41de631eda8d6d8c189"
- ]
- ],
- "public_share": "bec7c61c35f886f3f539890522388f43de4f6c512adaa41de631eda8d6d8c189",
- "rand": "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f"
- }
- ],
- "shares": 2,
- "verify_key": "000102030405060708090a0b0c0d0e0f"
-}
diff --git a/third_party/rust/prio/src/vdaf/test_vec/07/Prio3Histogram_1.json b/third_party/rust/prio/src/vdaf/test_vec/07/Prio3Histogram_1.json
deleted file mode 100644
index 0b9a9b4d5d..0000000000
--- a/third_party/rust/prio/src/vdaf/test_vec/07/Prio3Histogram_1.json
+++ /dev/null
@@ -1,89 +0,0 @@
-{
- "agg_param": null,
- "agg_result": [
- 0,
- 0,
- 1,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0
- ],
- "agg_shares": [
- "a6d2b4756e63a10bf5f650e258c73b0ccb20bace98e225dea29d625d527fdd4ded86beb9a0a0ac5c4216f5add7a297cece34b479a568a327f1e259839f813df97b34de254be5b9b9c8d9e56dbff50b7a6bf1e5967686755a1dc42e0ab170add8c88f8ca68f945e768a5007c775fd27cfecb4495e257a2f2f94ca48830aa16ec0decaeee645e295c5dc2ebe491aae1a7f17b2807fcb33ee08127db466067bf84ec613dac9c93adbe73dd262c1859b2865",
- "ed4163b108591ed14dc02153de31422b2e91ec0b43dacf9cc11a9cfc39d36f502bc094b556020cc333504aabd929ba007528187314062b0edb8092b5fcc3715126e16ce274ad58caaa14d22608269a4c41a256d3c9e847c0a6ac1a4fbaf6309e9ccbe74a9442ca956d843d6bd5adf9797a84557597d9cc81ddfa281ae5048d686bdb289ec2f3c96cdfa79b6974e6d15aec047748636d4358226283e11a78e045f59db2dda566162a56c85936ac0f4696",
- "6eebe7d888434023a1488dcac80682c8084e592524430a857f4701a673adb261eab8ac90085d47e06d99c0a64e33ae30bfa23313469131cafb9b13c763ba50b560eab4f73f6ded7b7011486b38e45939566cc395bf9042e5038fb6a6949821899ea48b0edc28d7f3cf2abbcdb454deb69cc6602c43ac034f563a8e62105a04d7b859e87af729a0cd2729a64c716b1326fe480838d15ece9eaf20c8b7de0c276b464e7358905e0eee4f654308ce549104"
- ],
- "chunk_length": 3,
- "length": 11,
- "prep": [
- {
- "input_shares": [
- "a6d2b4756e63a10bf5f650e258c73b0ccb20bace98e225dea29d625d527fdd4ded86beb9a0a0ac5c4216f5add7a297cece34b479a568a327f1e259839f813df97b34de254be5b9b9c8d9e56dbff50b7a6bf1e5967686755a1dc42e0ab170add8c88f8ca68f945e768a5007c775fd27cfecb4495e257a2f2f94ca48830aa16ec0decaeee645e295c5dc2ebe491aae1a7f17b2807fcb33ee08127db466067bf84ec613dac9c93adbe73dd262c1859b2865508d344dda6c4339e650c401324c31481780ef7e7dcc07120ac004c05ab75ee5d22e2d0eb229dcdd3755fab49a1c2916e17c8ed2d975cfe76d576569bf05233c07f94417fccaf73d1cc33e17dae74650badffdd639a9b9f9e89de4b9fd13e258b90fbb2b3817b607dc14e6e5327746ca20d1f1918bce9714b135ffe01eb4e6aefab92b0462f7e676e26007e8c2e5a66e16f32f7c8457a6dfba39d9082f640006d560b4d64e86e2e2358c84e03b857c980f51b1a78b53f7cb44343ed184d8dc87ebf8698609eeefae5d8882224ebd28b9531015badea8ae9fe01c7495cafecdc4f13389ea4eb0bbce0a5ab85aa6fc06aabd96d28c84ecf039bfeb4c350049485f8a4c706a109164ff4c640edaedd0ad50820b1d1ed7ab08fc69c48b39aff1eebc02ef1ea40bd70784bfa50511c3dd64b107f4297842280c3cff8d94be202a0e2cb0090f3adb2189f445fcf291f452f162606162636465666768696a6b6c6d6e6f",
- "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f",
- "303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f"
- ],
- "measurement": 2,
- "nonce": "000102030405060708090a0b0c0d0e0f",
- "out_shares": [
- [
- "a6d2b4756e63a10bf5f650e258c73b0c",
- "cb20bace98e225dea29d625d527fdd4d",
- "ed86beb9a0a0ac5c4216f5add7a297ce",
- "ce34b479a568a327f1e259839f813df9",
- "7b34de254be5b9b9c8d9e56dbff50b7a",
- "6bf1e5967686755a1dc42e0ab170add8",
- "c88f8ca68f945e768a5007c775fd27cf",
- "ecb4495e257a2f2f94ca48830aa16ec0",
- "decaeee645e295c5dc2ebe491aae1a7f",
- "17b2807fcb33ee08127db466067bf84e",
- "c613dac9c93adbe73dd262c1859b2865"
- ],
- [
- "ed4163b108591ed14dc02153de31422b",
- "2e91ec0b43dacf9cc11a9cfc39d36f50",
- "2bc094b556020cc333504aabd929ba00",
- "7528187314062b0edb8092b5fcc37151",
- "26e16ce274ad58caaa14d22608269a4c",
- "41a256d3c9e847c0a6ac1a4fbaf6309e",
- "9ccbe74a9442ca956d843d6bd5adf979",
- "7a84557597d9cc81ddfa281ae5048d68",
- "6bdb289ec2f3c96cdfa79b6974e6d15a",
- "ec047748636d4358226283e11a78e045",
- "f59db2dda566162a56c85936ac0f4696"
- ],
- [
- "6eebe7d888434023a1488dcac80682c8",
- "084e592524430a857f4701a673adb261",
- "eab8ac90085d47e06d99c0a64e33ae30",
- "bfa23313469131cafb9b13c763ba50b5",
- "60eab4f73f6ded7b7011486b38e45939",
- "566cc395bf9042e5038fb6a694982189",
- "9ea48b0edc28d7f3cf2abbcdb454deb6",
- "9cc6602c43ac034f563a8e62105a04d7",
- "b859e87af729a0cd2729a64c716b1326",
- "fe480838d15ece9eaf20c8b7de0c276b",
- "464e7358905e0eee4f654308ce549104"
- ]
- ],
- "prep_messages": [
- "4b7dc5c1b2a08aec5dcfc13de800559b"
- ],
- "prep_shares": [
- [
- "e80c098526d9321dd0801f97a648722016fa117f10cb2b062fc5fb1e55705894007f838333ef348c6306e141369bd88d123c66d2faeb132e330a73882c38765d425847bd86e5f784b3348ee4840c5df103b49f04c4dcca4667abb956187da58c91c946d9d5fdf496d95428f8a625dddfc8b7bb469397ebd4b177f902896febdaac39a8d9ec0aa1a24132036c2430929c",
- "4f6d4137ddffd58b243b8f845a1684550b240ea3e91a68335f717b83056e9b45c5e62d7a24da54147fcb9260d023cb7f9c8d036f0100f5fea0ce22f49e3d7672bc83fd5c724f2684f3442e8c5291c41509151808d1da447cddc3fe11cf5cd8d7fe662cf035eff88b583f6b32499b332aa6dee37947ef482e15fcb3a7f04b20813162d162b9bf30eee4953b6fdabd10f1",
- "ca85b543fc26f756ef4351e4fea0098a73787eeab8b613029af310882b7e87d28fc5502fd76bd704626d9f0f662e531feaf1fa912cc209de6541401d8508a4788d92e549f58241334cfa29abc1fb80a28ae61d7a4060d9582e3e20f182e4519ab1bb9547c545aafc21416e779856c80cf3690155119111aebf3800757989229e4966453f7aa269163b272848de80227f"
- ]
- ],
- "public_share": "ac39a8d9ec0aa1a24132036c2430929c3162d162b9bf30eee4953b6fdabd10f14966453f7aa269163b272848de80227f",
- "rand": "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f"
- }
- ],
- "shares": 3,
- "verify_key": "000102030405060708090a0b0c0d0e0f"
-}
diff --git a/third_party/rust/prio/src/vdaf/test_vec/07/Prio3SumVec_0.json b/third_party/rust/prio/src/vdaf/test_vec/07/Prio3SumVec_0.json
deleted file mode 100644
index a7178fcfee..0000000000
--- a/third_party/rust/prio/src/vdaf/test_vec/07/Prio3SumVec_0.json
+++ /dev/null
@@ -1,194 +0,0 @@
-{
- "agg_param": null,
- "agg_result": [
- 256,
- 257,
- 258,
- 259,
- 260,
- 261,
- 262,
- 263,
- 264,
- 265
- ],
- "agg_shares": [
- "cdeb52d4615d1c718ef21a6560939efcb5024c89ea9b0f0018302087c0e978b5b5c84c8c4f217b14584cc3939963f56a2718c17af81d1f85129347fc73b2548262e047a67c3e0583eeef7c4a98a5da4ccdb558491081a00a8de5a46b8c2f299bc69162a7411b3ecf2b47670db337083dc50b8fc6d5c5d21da52fc7f538166b0e4564edd8fbb75bc8c4fdd0c02be2b6d11bc4a159297b72e2c635a9250feb2445",
- "3415ad2b9ea2e38e550de59a9f6c61034dfeb3761564f0ffcbcfdf783f16874a4e38b373b0de84eb8bb33c6c669c0a95dde83e8507e2e07ad16cb8038c4dab7da320b85983c1fa7cf50f83b5675a25b3394ba7b6ef7e5ff5561a5b9473d0d664416f9d58bee4c130b8b898f24cc8f7c243f570392a3a2de23ed0380ac7e994f1c49c12270448a4371f022f3fd41d492eef3c5ea6d6848d1d1dca56daf014dbba"
- ],
- "bits": 8,
- "chunk_length": 9,
- "length": 10,
- "prep": [
- {
- "input_shares": [
- "2451f59efba2edc493c9246ff1f0e0a7f8f6f22ee46e662c899e485d7ce288d6becdfee804a39618972fbaa595eeec25423e412cbe51d44a62747de627630302368ec3535a2545a2799e8a0b9a144c811158dda278865d834b34fbe77ad11dbb9fdcf0637c24e10d5ab36d03cdc5f6b95e400a0a81608d96c25733c376376de3927c3570e8ab671358a1686d0c44ac938368d5621cff66585454ef124daa5f18efd7e791a4bcb11caf74b378e2c4feff3e5bad16e7c3fab987eb4d4a0c675bb4f4e70e1373fb00a5dd30a1118355c20e2e4c3700be3d3c1cf25d3e4a729836ba564aa074f99be0d23d4cc0dc9f263c986988e0d16a3d28c262d34f220b1ed127cddea3e2a1bd075c653d4b6f1c3d35e25d2804e7960250dea42dc4a52c9545bedc182ee8391b4c6849366af8e15f30bd06872e5ed651ef7db0b0c442886de32eeeeacc5f2dfe87f9375b4774153fc9e442105b5f8e452e80874c84131400d4d588a1a5d94bac9e68dbf917ef6405b0bc13fa89daf46f84405aedb166ac93f6545256b1da6ac65e01d580bb26eef82c34b9d728fc0c96ff898ed46bd289abbec9917397552ebf6d1eb3f916f69ee9f80e9466512bff70af2d8f3a9ed599f24e33550a09304e1b4f51948e2d8cbf5a1bb14455b1786ae3af4670111bc3983293ad9ae029128efd86d0a05cb3f442b43f466cec5cc9c4989bf5a29eb5c2401bc8bba0d5b7487bc0bf010c968fe76e3a9924459dce6704528d56540081240ed0d2f301a8c9baca5c183b1b5c3a9c03dce5036926d06e1470c2e63d15fdc3a61056154fca9439c595098ff3794c7d7e62af5e3139b43e22a0f8864c254a069a083604762d77ea000177a7b908efe27f6e00db7ea25f573734af803044fb2dc333ed9ad589d7677e23614143fa6836d68ed311dcedf0ea031688b2cf8c5248f21be444f1c61b050a0ab7dca04992673afb737bd27526a72dda3b03dad4d3b0bb81f0887ee6f25ec4cf35d58ea5f085e97609cfb6a8e97d84fdf8755b8e81ff29614bf1b03bcd2b8d9ab06dc4d60785f83eb6ee4573859223214ecdad734d114e15e1971a8b82222910fd041a1123a4e792a9239f99252de3e3e8d5bb209e2c9bda506a79853c482546940364a8246392fb5e18e85847458445fe3a970b29db6d3d0e4a806cfec7c8538f24896d2d10669113f2b724161d2007ee75c0b651f4934046142b04b2015212997c609625bbeb81b9fa0249c167196557c08ae9ea2defcf7859eed4d35b2183c628cb82fe01255e558e7c8b13bded6ba43ed8b92f6ba7879b39932468260c5768ca0909aae899ad1252c5dbcd741d971f179bc36e88a0a10981f73202cb25db324da405fdd5ca5331431afe362c5f933b3c1216c3e19140cd27f7c2ef67898887856a46a518a3afec78ee0d9dce778289a38d2df906932c40019afadab12fe7d0695316e5a3c1e38aa630a44bc8cc01a5a8cae060b7de435e54963b9354182d64e340ec9dc3e37f8b2bbaaab23608b86827991df4367839f443c160c1eb77f41159f69592c3eb37c21a521afcd34036a13a145e9cb1039704b8e523359ea5c3a50f705118ea7d8b1063eb85bfcdc941e0235579e97856ee6f6bfe9c4d0d161b5662de26a2fbddc530ce918a98514903c63a3476d6ebe68e2503e6bf255691fbd8a006e9c77f5a4ad9e3e8d21a56bc4f7bc90d61ebb31eaa4dce48eb9a8069a584ae35266a4bc4af970860d2e9a0df7b87e8fc8b597e73a85d8eeb91def6057d7a77e8f859ee9ee07ef2fb2260660e59ee16458eafbd7bab979ed9bf72c1c27cadc9011f563aeed9a4b2f09ce5455857bcf3acbe0e1cf15537594469c777a885ad24ac5a8c894a8257c5212fb46184ad7f280bc25600129b25bf941460fcdd2e45a0216f1f2fec84d4792a15f877d15c649991ef998621a50a04251257ed6ccd803fdbc83ce4b5c4d7e8ee4487848768384e0b3970ec899dfb423560e755c4716deb3e188ca780cc7a97e8fb80076e9c44c6b7575725253ae4605844c3748bf90c14f17ee80a42fea450c05eb1f251eb09855f2ab368047d68cd7f4b8898d0113d52117375eed77707e7abff8554dc7da30cca674ac587198c0f165a47a5db79e9cc1c7bda9cdc36b94f14141a307850062f4d7208b8c612691699e3e3c16c3fc2dc6604e0fcb27acd6b5d326d2663a3f819589176c70423bc4d37d8c2a17e97468cf923a5388eb0d1de61358e9651a7e76b033d32d6c84e7ed5831a990b46e8228b6ef120643049645b82e100a7ed6ddd2ebfe2dcbd8b0e7ac1e5ee021d4279f164acc47875ade2c0acff5dbbf3a6eb0e8601632c926780be1660270420aa02c99fb39af1852b09904791e90cfa1f02aec0ab2de111524394819527819e52d495196ab3aff1e323dfec07af91e18b9a04e37552a23b13177bdcfc64ec7108e5e9b3679ccdf6b1e998e2bbcd5fbbbebf5ad8008e727cae6499cc06aa03809947e298683a4340f51d6eecad38d0a7a5437dd6e72bce6543b81fd3a438d71e232845cdb403f1011295f9aee5e33352b86e92343985884284c9646da13545f37b9d6da7d0cf902c19a5ca1f4f1818a2c2644807fcc54be35c29f96fb4fea5efdc88b270f1c5504bd8ba558834786020cc2f03ab5c56eaea38532b9faf6208f57d970b2e5ff92872713c9e0ad07b26e72dca6f9a9c02bad6c9db4d1d738f306292f14415d2856c2b073c5d8faf89e9713ceb375b6eefabc240bf6c6bf39cafb99993767dbaf5ee5f4b3f93e638e904fb55f443312c145b809fd203b5b3a16bd229b952e100bbfc0e49bbd05d54c3e5fa1a44fe55de16cfa52f3b169e0bfe95b1b8b6367f9309adfe3df079104fd720d46d772def3c0534d73615071fa22a79af875f796478d2f599dbb4c1ed303132333435363738393a3b3c3d3e3f",
- "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f"
- ],
- "measurement": [
- 0,
- 1,
- 2,
- 3,
- 4,
- 5,
- 6,
- 7,
- 8,
- 9
- ],
- "nonce": "000102030405060708090a0b0c0d0e0f",
- "out_shares": [
- [
- "9aa31b9c201fb42526a6b32120318aa9",
- "e8551983a3deafaafe0f608295f8d291",
- "3eed6ed96f607eb1be6e96868876fc78",
- "65b295d3525f0ad74886c2fe7b3b1cd6",
- "794a6d37d41457d6f04fd418888cf36e",
- "483cc86d052be058d0a1e12384ba0d89",
- "9c85cb376b5ebfeffb6c22af3bbd02bf",
- "9c0385979cecf00983ba97fc12b2235a",
- "c7cbf9f2533dc942eca94540b9a0e745",
- "0f418bc80d2926f6ec11e3615a4e0c17"
- ],
- [
- "675ce463dfe04bdabd594cdedfce7556",
- "1aaae67c5c215055e5ef9f7d6a072d6e",
- "c5129126909f814e2591697977890387",
- "9f4d6a2cada0f5289b793d0184c4e329",
- "8cb592c82beba829f3af2be777730c91",
- "bec33792fad41fa7135e1edc7b45f276",
- "6b7a34c894a14010e892dd50c442fd40",
- "6cfc7a6863130ff660456803ed4ddca5",
- "4234060dacc236bdf755babf465f18ba",
- "fbbe7437f2d6d909f7ed1c9ea5b1f3e8"
- ]
- ],
- "prep_messages": [
- "db085315822777376b4d0f962d8f06d9"
- ],
- "prep_shares": [
- [
- "e6a4fe7264f95c384446bd51db14f78e7f4133afed0604aeb3b87125fc076c7447d795723adfe93d85f9fe2993c52420e45694fd2ec164a54a7267ee5efc8cb40b6659ac81f2e850786218bcec469ec4f7bb28e875d75ee98d54d566186c61c35448a50cb11e195d886622861a78bbb74325b7972e7b4c47f0e2e10a15d7a33c3daecb2dfc507b1b6676c1e9bfc52a4873f408a5788e7b77ce6943e67f3f457280544d93b81b08e427f699ba54adcbb0ffab83366d9b336846c0c989f0bc25bdd14683f1a85e844b9dbac26daae84cc8d57ef6b0c340798ac5ade63150e8d7a9673b64d798a97cf2715f399fd371e342c1ad50e28431f54180ef63ad7dd21f3e5d8d67159cacfd56f5d99c39d53047c8d7bf11ad83a2e3e569e1393b12d87d01701fa71b50b51e092ca6b797bb97890efb6327f1c4e488663dca5f00675c2af7368a9ab95b3c4e9e1a8dd5430d336833",
- "1b5b018d9b06a3c79fb942ae24eb087131693625114418115cb3e54a45056eabd0f6e371501957e00796db78ea8f3388eb8345e938f5fbdd8b24c3a968276d7c457ff43ce93631942f823f5bb9c6d1335b8022e804072711cb8fa5fb3afb209e696c9cac47da44cdc3eb3874eb0d8c89692408b463df12bb2d6e8193d5829cce221e486a579b91cd10a0fb38fec7214a9008d574ba32615f6215aef827a2962a31df892814bd8b8f828d029f07f6acf490e7ecd3377f10b86ec2d5741ba37a3a9522b897e840e315a614a89d0bcf8296bdd45e330eaf3f34b3ce4e1dd41306eae92147fc6676eedff2cb239581f46750df341390e066dabb01ef6362694f923d5a65dbc5252a8da8702a979aca3e211af7124485c1c7dc68f6fb1bdfb9a4d0d993cece17c818d8fb1151f1ef1b32745f09c155f42259af588b424c1dafe8d0e90a3dfc6f55bb428773ce15071cb720fb"
- ]
- ],
- "public_share": "368a9ab95b3c4e9e1a8dd5430d3368330a3dfc6f55bb428773ce15071cb720fb",
- "rand": "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f"
- },
- {
- "input_shares": [
- "2551f59efba2edc493c9246ff1f0e0a7f8f6f22ee46e662c899e485d7ce288d6becdfee804a39618972fbaa595eeec25423e412cbe51d44a62747de627630302368ec3535a2545a2799e8a0b9a144c811158dda278865d834b34fbe77ad11dbb9fdcf0637c24e10d5ab36d03cdc5f6b95e400a0a81608d96c25733c376376de3927c3570e8ab671358a1686d0c44ac938368d5621cff66585454ef124daa5f18efd7e791a4bcb11caf74b378e2c4feff3e5bad16e7c3fab987eb4d4a0c675bb4f4e70e1373fb00a5dd30a1118355c20e2e4c3700be3d3c1cf25d3e4a729836ba564aa074f99be0d23d4cc0dc9f263c986988e0d16a3d28c262d34f220b1ed127cedea3e2a1bd075c653d4b6f1c3d35e25c2804e7960250dea42dc4a52c9545bedc182ee8391b4c6849366af8e15f30bd06872e5ed651ef7db0b0c442886de32eeeeacc5f2dfe87f9375b4774153fc9e442105b5f8e452e80874c84131400d4d588a1a5d94bac9e68dbf917ef6405b0bc13fa89daf46f84405aedb166ac93f6545256b1da6ac65e01d580bb26eef82c34b8d728fc0c96ff898ed46bd289abbec9917397552ebf6d1eb3f916f69ee9f80e9466512bff70af2d8f3a9ed599f24e33550a09304e1b4f51948e2d8cbf5a1bb14455b1786ae3af4670111bc3983293ad9ae029128efd86d0a05cb3f442b43f466cec5cc9c4989bf5a29eb5c2401bc8bba1d5b7487bc0bf010c968fe76e3a9924459dce6704528d56540081240ed0d2f300a8c9baca5c183b1b5c3a9c03dce5036926d06e1470c2e63d15fdc3a61056154fca9439c595098ff3794c7d7e62af5e3139b43e22a0f8864c254a069a083604762d77ea000177a7b908efe27f6e00db7ea25f573734af803044fb2dc333ed9ad589d7677e23614143fa6836d68ed311dcedf0ea031688b2cf8c5248f21be444f0c61b050a0ab7dca04992673afb737bd27526a72dda3b03dad4d3b0bb81f0887ee6f25ec4cf35d58ea5f085e97609cfb6a8e97d84fdf8755b8e81ff29614bf1b03bcd2b8d9ab06dc4d60785f83eb6ee4573859223214ecdad734d114e15e1971b8b82222910fd041a1123a4e792a9239e99252de3e3e8d5bb209e2c9bda506a78853c482546940364a8246392fb5e18e85847458445fe3a970b29db6d3d0e4a806cfec7c8538f24896d2d10669113f2b724161d2007ee75c0b651f4934046142b04b2015212997c609625bbeb81b9fa0249c167196557c08ae9ea2defcf7859eed4d35b2183c628cb82fe01255e558e7b8b13bded6ba43ed8b92f6ba7879b39922468260c5768ca0909aae899ad1252c5dbcd741d971f179bc36e88a0a10981f73202cb25db324da405fdd5ca5331431afe362c5f933b3c1216c3e19140cd27f7c2ef67898887856a46a518a3afec78ee0d9dce778289a38d2df906932c40019bfadab12fe7d0695316e5a3c1e38aa630a44bc8cc01a5a8cae060b7de435e54963b9354182d64e340ec9dc3e37f8b2bb9aab23608b86827991df4367839f443c160c1eb77f41159f69592c3eb37c21a521afcd34036a13a145e9cb1039704b8e523359ea5c3a50f705118ea7d8b1063eb85bfcdc941e0235579e97856ee6f6bfe9c4d0d161b5662de26a2fbddc530ce918a98514903c63a3476d6ebe68e2503e6bf255691fbd8a006e9c77f5a4ad9e3e7d21a56bc4f7bc90d61ebb31eaa4dce48eb9a8069a584ae35266a4bc4af970860d2e9a0df7b87e8fc8b597e73a85d8eeb91def6057d7a77e8f859ee9ee07ef2fb2260660e59ee16458eafbd7bab979ed9bf72c1c27cadc9011f563aeed9a4b2f09ce5455857bcf3acbe0e1cf15537594469c777a885ad24ac5a8c894a8257c5212fb46184ad7f280bc25600129b25bf941460fcdd2e45a0216f1f2fec84d4792a15f877d15c649991ef998621a50a04251257ed6ccd803fdbc83ce4b5c4d7e8ee4487848768384e0b3970ec899dfb423560e755c4716deb3e188ca780cc7a97e8fb80076e9c44c6b7575725253ae4605844c3748bf90c14f17ee80a42fea450c05eb1f251eb09855f2ab368047d68cd7f4b8898d0113d52117375eed77707e7abff8554dc7da30cca674ac587198c0f165a47a5db79e9cc1c7bda9cdc36b94f14141a307850062f4d7208b8c612691699e3e3c16c3fc2dc6604e0fcb27acd6b5d326d2663a3f819589176c70423bc4d42a21c0a30addfe4b4176740f9a418eca631cda9a8b94d20c7f9b834ed87751464dc5e5b446d920312003e4673b48c6c12b407af1ed90002507883f78d166f0b90bc14ed77d4aec6220cdd51948cdad29ab70513aadccd0e3c8c8108d3b0722602d9612aa6feb323a4ff3e8fe0e3d5701467491acdd3c71c34bc019047647779922216ccd61c47958461e3017adf446c4bd2ab7fbf70e41419679f6a9b3fa4c9aa5e9ef8469ace0d88bc35a3374f462573d2ba24b712359ef36e413006a9883bfa4fad43d89c7f1732725e3cad482d17a9499e1fb0f57d1ca93cafa7fd6d654a70cd7318bd7ace30e981217317105bcfe5e33352b86e92343985884284c9646d966beb8aca87d44e15dcce24aeb08312091cd98e6b52e2525409c58438f00131d33ce09fde0343f84db73369954f2d77a3a559189bc4dfd7e7c043b1364b36550595f624483c4eccccb1c4958a9284e43522dcc72ad9b01162d964605eab990dd1ddd25796f55991e1201f22526117662c0cad518f191effe5608b444b9e8973f5a11a8c154bc501bc47bb4fb5832d67f4c5ea5c221e64ff88ff5d5117aadac704a8b94beb036e87fc9a9462c355231b9bbe8a9122f12390073600f2d7f6262f1758eced79619900cad1910286c5bae553c6525c63c52ca97bf452957c5fc1a7d695dcb5ed0cf0004454c528d63960cd303132333435363738393a3b3c3d3e3f",
- "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f"
- ],
- "measurement": [
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1
- ],
- "nonce": "000102030405060708090a0b0c0d0e0f",
- "out_shares": [
- [
- "9ba31b9c201fb42526a6b32120318aa9",
- "e8551983a3deafaafe0f608295f8d291",
- "3ded6ed96f607eb1be6e96868876fc78",
- "63b295d3525f0ad74886c2fe7b3b1cd6",
- "764a6d37d41457d6f04fd418888cf36e",
- "443cc86d052be058d0a1e12384ba0d89",
- "9785cb376b5ebfeffb6c22af3bbd02bf",
- "960385979cecf00983ba97fc12b2235a",
- "c0cbf9f2533dc942eca94540b9a0e745",
- "07418bc80d2926f6ec11e3615a4e0c17"
- ],
- [
- "675ce463dfe04bdabd594cdedfce7556",
- "1aaae67c5c215055e5ef9f7d6a072d6e",
- "c5129126909f814e2591697977890387",
- "9f4d6a2cada0f5289b793d0184c4e329",
- "8cb592c82beba829f3af2be777730c91",
- "bec33792fad41fa7135e1edc7b45f276",
- "6b7a34c894a14010e892dd50c442fd40",
- "6cfc7a6863130ff660456803ed4ddca5",
- "4234060dacc236bdf755babf465f18ba",
- "fbbe7437f2d6d909f7ed1c9ea5b1f3e8"
- ]
- ],
- "prep_messages": [
- "fdecd6d197e824492dd550fcdd0aa3c7"
- ],
- "prep_shares": [
- [
- "e6a4fe7264f95c384446bd51db14f78eec654b5beb7d60677c0b8385ca51a5bf896c79a069b04f339fdcb675885a26f533ec0d6e805beef6d7683a8ecdfa46cb87fdbc532efa5b1041347ed94f54fbca15041d013729d5eb78dcb1a1c293e0035448a50cb11e195d886622861a78bbb7bccc68d521fac002ece757cc5d82afb3b0f9f8766a1714047b50417a8e7f63eacf222c675bdf1d3e8362806ef5f9c16c446a1e5e06ce539aa300bc68c837c9207c5dbc7d85f896fb1be725e461ceacd303716a2cd8005e370a8ac1062d966b5c1499813d0dc63d697c4fd44dcfe81b3cfc37952de43649650c52ca9f2044fd3dfc42cd08bf0659e6a7facee2468ad1b07903a933ec3cbd06a5f81461e434449c32ef6678f3c8fd250c0b3318e80235144a96f07af2169dfddb503b38a2039f80f6bdfbbec6b3ad1025a43a90249221d20e627a73e2ed92bf1920574f42775675",
- "1b5b018d9b06a3c79fb942ae24eb0871aba638b677efec2418d7921020c44ff8d0f6e371501957e00796db78ea8f338813d41fd058418e6056a93bb2785cec1d457ff43ce93631942f823f5bb9c6d133fbfbf9d10fa7922dccd1e570b0246775696c9cac47da44cdc3eb3874eb0d8c89fcdfd722a57116825749c8972129304c221e486a579b91cd10a0fb38fec7214af0fe63f4a24e9e189e180a8aaed3b22931df892814bd8b8f828d029f07f6acf402eb7c22aea07b55e871ebdf6475ae509522b897e840e315a614a89d0bcf8296c0b0d5b745f277689643e3da46c09a1ce92147fc6676eedff2cb239581f46750fa1947870c81f9d565f51ed7e09d86dc5a65dbc5252a8da8702a979aca3e211ae9def20e5f2fa85d16e3ccb0a917510793cece17c818d8fb1151f1ef1b32745f09c155f42259af588b424c1dafe8d0e90a3dfc6f55bb428773ce15071cb720fb"
- ]
- ],
- "public_share": "0e627a73e2ed92bf1920574f427756750a3dfc6f55bb428773ce15071cb720fb",
- "rand": "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f"
- },
- {
- "input_shares": [
- "2551f59efba2edc493c9246ff1f0e0a7f9f6f22ee46e662c899e485d7ce288d6bfcdfee804a39618972fbaa595eeec25433e412cbe51d44a62747de627630302378ec3535a2545a2799e8a0b9a144c811258dda278865d834b34fbe77ad11dbba0dcf0637c24e10d5ab36d03cdc5f6b95f400a0a81608d96c25733c376376de3927c3570e8ab671358a1686d0c44ac938468d5621cff66585454ef124daa5f18f0d7e791a4bcb11caf74b378e2c4feff3f5bad16e7c3fab987eb4d4a0c675bb4f5e70e1373fb00a5dd30a1118355c20e2f4c3700be3d3c1cf25d3e4a729836ba574aa074f99be0d23d4cc0dc9f263c986a88e0d16a3d28c262d34f220b1ed127cedea3e2a1bd075c653d4b6f1c3d35e25d2804e7960250dea42dc4a52c9545bedd182ee8391b4c6849366af8e15f30bd07872e5ed651ef7db0b0c442886de32eefeacc5f2dfe87f9375b4774153fc9e443105b5f8e452e80874c84131400d4d589a1a5d94bac9e68dbf917ef6405b0bc14fa89daf46f84405aedb166ac93f6545256b1da6ac65e01d580bb26eef82c34b9d728fc0c96ff898ed46bd289abbec9927397552ebf6d1eb3f916f69ee9f80e9566512bff70af2d8f3a9ed599f24e33560a09304e1b4f51948e2d8cbf5a1bb14555b1786ae3af4670111bc3983293ad9be029128efd86d0a05cb3f442b43f466dec5cc9c4989bf5a29eb5c2401bc8bba1d5b7487bc0bf010c968fe76e3a9924469dce6704528d56540081240ed0d2f301a8c9baca5c183b1b5c3a9c03dce5036a26d06e1470c2e63d15fdc3a610561550ca9439c595098ff3794c7d7e62af5e3239b43e22a0f8864c254a069a083604772d77ea000177a7b908efe27f6e00db7fa25f573734af803044fb2dc333ed9ad589d7677e23614143fa6836d68ed311ddedf0ea031688b2cf8c5248f21be444f1c61b050a0ab7dca04992673afb737bd37526a72dda3b03dad4d3b0bb81f0887fe6f25ec4cf35d58ea5f085e97609cfb7a8e97d84fdf8755b8e81ff29614bf1b13bcd2b8d9ab06dc4d60785f83eb6ee4673859223214ecdad734d114e15e1971b8b82222910fd041a1123a4e792a9239f99252de3e3e8d5bb209e2c9bda506a79853c482546940364a8246392fb5e18e95847458445fe3a970b29db6d3d0e4a816cfec7c8538f24896d2d10669113f2b824161d2007ee75c0b651f4934046142c04b2015212997c609625bbeb81b9fa0349c167196557c08ae9ea2defcf7859eed4d35b2183c628cb82fe01255e558e7c8b13bded6ba43ed8b92f6ba7879b39932468260c5768ca0909aae899ad1252c6dbcd741d971f179bc36e88a0a10981f83202cb25db324da405fdd5ca5331431bfe362c5f933b3c1216c3e19140cd27f8c2ef67898887856a46a518a3afec78ef0d9dce778289a38d2df906932c40019bfadab12fe7d0695316e5a3c1e38aa631a44bc8cc01a5a8cae060b7de435e54973b9354182d64e340ec9dc3e37f8b2bbaaab23608b86827991df4367839f443c260c1eb77f41159f69592c3eb37c21a531afcd34036a13a145e9cb1039704b8e623359ea5c3a50f705118ea7d8b1063ec85bfcdc941e0235579e97856ee6f6bfe9c4d0d161b5662de26a2fbddc530ce928a98514903c63a3476d6ebe68e2503e7bf255691fbd8a006e9c77f5a4ad9e3e8d21a56bc4f7bc90d61ebb31eaa4dce49eb9a8069a584ae35266a4bc4af970861d2e9a0df7b87e8fc8b597e73a85d8eec91def6057d7a77e8f859ee9ee07ef2fc2260660e59ee16458eafbd7bab979ed9bf72c1c27cadc9011f563aeed9a4b2f09ce5455857bcf3acbe0e1cf15537594469c777a885ad24ac5a8c894a8257c5212fb46184ad7f280bc25600129b25bf941460fcdd2e45a0216f1f2fec84d4792a15f877d15c649991ef998621a50a04251257ed6ccd803fdbc83ce4b5c4d7e8ee4487848768384e0b3970ec899dfb423560e755c4716deb3e188ca780cc7a97e8fb80076e9c44c6b7575725253ae4605844c3748bf90c14f17ee80a42fea450c05eb1f251eb09855f2ab368047d68cd7f4b8898d0113d52117375eed77707e7abff8554dc7da30cca674ac587198c0f165a47a5db79e9cc1c7bda9cdc36b94f14141a307850062f4d7208b8c612691699e3e3c16c3fc2dc6604e0fcb27acd6b5d326d2663a3f819589176c70423bc4dc97f402ea5053f2aa068d42c371d327339bd8637472eb9be88e409688a53bff392a8891c96c7804998d761fcf34dbf8da8cb17567f75ab4be29ecb6c33c85bf572b645bb7b226e4b99ccc0d959e6d809ec45b70cefe5ada611ea14962c9788d3e15100872669baf3c07a424cc205db97c0e2f72880a40a48d3820f89a16c7ee9dbc44bea18d787e0b730093a7b1fe4f9fd3e50128c61f6d4179fde88b02629629bf9f56f15abe3860ad2c99eaee9eba2310ca898fee5103f7bcb11ec9f4154007cf7d2b51a173331576526665d9f90879a2122b2bdef3a2cff68e57b146ae6d99a4e247d0daa693ef0a07aadc1a4b25ce5e33352b86e92343985884284c9646d0f8ec766552f75092a8b613870386a8b77901f01cddd76b4761e74519b24b851a570b5de8ca954b2c7df0fb314b6fa550e8e49713a28358e399afb3b9199496b229bc55644ee8e4772f1e00dc53886ade4932acee5cfd079707bd1d204c58360f26434fb158b53c1c4a51b65703f123f8090fe42dc48dbd3469a7d4bf1958203adffe46dd39084b66c789517b4438ed9415946ca552d523fa6c71e3302c3552f140d62d41cf3580e5e8500674cbb7d9ddd849d1ddb1d48ef7fd92f363e5e5b6a95b0c67b37e7e5e6a4dec9d8d56e577562eecec955cb6f9925c81cc165634018ab142c519ddd54f358356cee2ba50840303132333435363738393a3b3c3d3e3f",
- "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f"
- ],
- "measurement": [
- 255,
- 255,
- 255,
- 255,
- 255,
- 255,
- 255,
- 255,
- 255,
- 255
- ],
- "nonce": "000102030405060708090a0b0c0d0e0f",
- "out_shares": [
- [
- "99a41b9c201fb42526a6b32120318aa9",
- "e6561983a3deafaafe0f608295f8d291",
- "3bee6ed96f607eb1be6e96868876fc78",
- "61b395d3525f0ad74886c2fe7b3b1cd6",
- "744b6d37d41457d6f04fd418888cf36e",
- "423dc86d052be058d0a1e12384ba0d89",
- "9586cb376b5ebfeffb6c22af3bbd02bf",
- "940485979cecf00983ba97fc12b2235a",
- "beccf9f2533dc942eca94540b9a0e745",
- "05428bc80d2926f6ec11e3615a4e0c17"
- ],
- [
- "675ce463dfe04bdabd594cdedfce7556",
- "1aaae67c5c215055e5ef9f7d6a072d6e",
- "c5129126909f814e2591697977890387",
- "9f4d6a2cada0f5289b793d0184c4e329",
- "8cb592c82beba829f3af2be777730c91",
- "bec33792fad41fa7135e1edc7b45f276",
- "6b7a34c894a14010e892dd50c442fd40",
- "6cfc7a6863130ff660456803ed4ddca5",
- "4234060dacc236bdf755babf465f18ba",
- "fbbe7437f2d6d909f7ed1c9ea5b1f3e8"
- ]
- ],
- "prep_messages": [
- "190c0ef07d6f2cbd1bed12d71b5f118d"
- ],
- "prep_shares": [
- [
- "e6a4fe7264f95c384446bd51db14f78ef1ffdfc96013014baff7bd0684b8ff3360f6a2a23b1d7b71796b845eeb21e7d1682128dc8b87837803fec0e3bd6c548d5cc9c041a482cbfc38120743a2f1a0985053eaeccc339c56c2edf76451e22c9a1bca6ab2181850f44d904964d1f227a970e70b59328028ddafdb1649a8c4f1f7cbeb366e42f8603a7b627f7519f25617a33726ede06ab438714b4bd3cda025dc2bcab64974eb02b9e2a23bf0cab4e5ef1e87bb1a72767098c768a20e1090a712ed38c1e8803fd18181cc0069355b40f5f98ff3cbd2b31022df719d9c660e7d5bab239819730ad9165a38641379444093ba148996166ccf5e2826bddb7a7dc8eda4dd5928b12e1ea715538788804b5ce231dfc98ff45027ff8cb1f92007f2339621201a7dc483c83bb6df082105cb5f5d9eda1f847b3d43b4e16502062d5a4a158f651439d7666c683a6283d308c91b25",
- "1b5b018d9b06a3c79fb942ae24eb08714d70b996c916bc83063fda0f9ec82780d0f6e371501957e00796db78ea8f338874640cdcd2ca1496ea55d62aa3709498457ff43ce93631942f823f5bb9c6d133b1f04db02cc745245af6a31e4dfe912a696c9cac47da44cdc3eb3874eb0d8c89cc603d2ceec1678996fe311424b56e65221e486a579b91cd10a0fb38fec7214a46c9ce7f890afed4efa31fb5ca8766ae31df892814bd8b8f828d029f07f6acf47620063e9fa98ab947b376e068b9be689522b897e840e315a614a89d0bcf8296332affc2e6b52204d1d7994260e415c6e92147fc6676eedff2cb239581f4675066213f3b302497abbf10c1729131a0125a65dbc5252a8da8702a979aca3e211afb99a0edb76c92f2bd5941c6071db19d93cece17c818d8fb1151f1ef1b32745f09c155f42259af588b424c1dafe8d0e90a3dfc6f55bb428773ce15071cb720fb"
- ]
- ],
- "public_share": "8f651439d7666c683a6283d308c91b250a3dfc6f55bb428773ce15071cb720fb",
- "rand": "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f"
- }
- ],
- "shares": 2,
- "verify_key": "000102030405060708090a0b0c0d0e0f"
-}
diff --git a/third_party/rust/prio/src/vdaf/test_vec/07/Prio3SumVec_1.json b/third_party/rust/prio/src/vdaf/test_vec/07/Prio3SumVec_1.json
deleted file mode 100644
index af95aac5a0..0000000000
--- a/third_party/rust/prio/src/vdaf/test_vec/07/Prio3SumVec_1.json
+++ /dev/null
@@ -1,146 +0,0 @@
-{
- "agg_param": null,
- "agg_result": [
- 45328,
- 76286,
- 26980
- ],
- "agg_shares": [
- "598a4207618eab7bd108c110106e84cd9498b18b79cace4b383274cef0ab280eae74b07f9a7f087a89a4f51f3adb97ed",
- "ea61abdf14b8477f6de1b47a18ac778ad0149cb235e666ccce92a9246a2858403e5903013ab179dcf6719d10fccdf589",
- "cfc412198ab90c0589158a74d7e503a89b7cb3c1504fcae7dc3ae20ca52b7fb17a9b4c7f2bcf7da947e96ccfc9567288"
- ],
- "bits": 16,
- "chunk_length": 7,
- "length": 3,
- "prep": [
- {
- "input_shares": [
- "db3fe5357f56f6cfe9a0a34ed08e231765b423d5670741c151f7bc28cb15c4c8678df838b6ef52d74c5bb5e8c8c607b2674c024da705b558163e3127ae09f4a5c061dc6129d71755ec77b5d5a2fc088541fa612bf1273d94718e0d28b654ea9524148bf910a5c6d55b596e323d4f55ab62b0851e0985987ea39cf500bfd4d5faed37f519120b574aead76d706e149c54b6e790f7c35553f830f67553ff3f08db0f5d8a2e157f9c1ef6eedcb845a19fffd3f9c6e705b035c95f3ebe51219a91c6ffff33c52b8fd7e90417636bb443c98c3e6933b1599c09151095fff99d7af43d327fcf2afdc50144e5b8f5b1ff1f8cc8d442613dc76dd48100dd4637b38fc5fa239333c6d1e2bec2132a3e3cf5fd11f7e823fbf275071a71535740ac64de88b83ba002bd4490de5c7540e454331d46ebb825725b964ecfcc5c3bb076bf57fd819c0bd788b4495da456594503c8f5b618c4713e957a7589b151ead3a27ae80153b0fbc219f5524eec22dc91aa56ed87a71d2b6e6b857ee03a700fb5af5b23513fb73023c2764f74b40f00e44e2e7acd463e7f38c783a898015b51863659502645e7d7fdf14abf76c605d42e523a540f40e816db420d599cea502baa131d6b61b8aed86a09b9f7587e107c6fc9043d72644153b54234146535e9ec25223d293f4a2a4481b5649a7625116aef735ecbbdd9e99076985e1c424e91c29ae231c01f2b12007c81a9b3c72a84522014f4cdcb949bb9850b62b1c9c5d35f0fc3dbf4f637ae85d3082ffd15890041a455a5dd38efca02eb415afcd2c93a2b6ab46c88847f380affbc3a9af4745718044c9f23978026af66871e610e1beee21360fc5ae4f05dd32689328216db3c512fddacefb2713187f4f5069170db246ae0cb13b3b88f8c832d11ae6b26fe6f0f89b9a9056c28ac6160134ab1af4be606a2ca7d1256cfc223c823ae4921ba11aab9e4f8104885b2d17ac7826ad06b0fd0e54397e67179755b29c6d724f3e9d9a6934619ef0bfee72cdcf0031672bb6e55be53d3ef0fccf7beba7dea636eff7fdecee99f60a0bc5d5cb11e24683ca8085cf218a3607c3f5a051c33717f39834435c5c542f42bd9c9d9103173cb11436e2a626e228415924037ee4a4078f0d9a5bd0fef1dc9415740c4b32f51d199d912907a103c7e25928acadfb4dc1e8d32c34b4f0100bfe95feb850e0d7b359aae9a332913d1f8eca0d1cd93dee2f4b75076536037ca2b6bec5003ae89e03db9813d0dd2165bf50a836ca492f05750a3b5fff4d089fc54fdf225aa112d72ab021b0cef1b8d31c852133fae501406668db0cb4c3589934bde5ec218876b0dc4087b61d706234635d5d9065787a21ed895fb7c05902a554f879dae44d0905292815c5ae2338be1faa9249c7a0530623084f3a7c8bdddf0cf0123597127f9416dcad20f71bb98bf0078d9d20d4ae09c46fc1882cae650f48bebfcc443dfd7963c9944f0ce0a9bda91fe8b8f307fb3da48e573224324c35e867599262fa281ee6bc537928747dd4a1370440bda92e28eb5ba088481e476f19e2a03a7c7619eb79e2184afff7bb585319fa6a58dbfb8862f5d193ccfe0e4aeb58c1633d9e983861d4976615b11514160e5d77ed9a3e2179893c65d9de03813d27aec3485d96098764ee1e7779d47850e6b96ba064b4b913da8390416afb16719a38b725d5b27db351049bdb322cfc93a905a108d07e49764eb5f3f66fe8f3aec7580606162636465666768696a6b6c6d6e6f",
- "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f",
- "303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f"
- ],
- "measurement": [
- 10000,
- 32000,
- 9
- ],
- "nonce": "000102030405060708090a0b0c0d0e0f",
- "out_shares": [
- [
- "7e6f6b02cb848e7e3c5840b05acfd699",
- "dda1902ed398efc35ebb269aa58e0d5a",
- "cd03902ade7fad281b8cfc5f1349ddf9"
- ],
- [
- "f9758e4a5c3d6d2a1b4b3c7e5d397d83",
- "9bb1de90bc4c2244e630e3b6780dc86a",
- "15735600bee57d499ed0890554ef5183"
- ],
- [
- "9b4106b3d83d0457705c83d147f7abe2",
- "89299140701aeef79e13f6aee1632a3b",
- "298919d5639ad48d0ea3799a98c7d082"
- ]
- ],
- "prep_messages": [
- "429a80b8b2f73ce00d066d0c0e540cfb"
- ],
- "prep_shares": [
- [
- "574ce7d79da173f0652f7d1e699d5fe756c90210a093e0c893b2b7510374465c35014cdcef24d6044e63ece20db245a982c5a00f16227c6530ade1e5fd4e925f8505da8add8b97fa3216790b11b46ad76bec9b6b3f0c1e9b8284f81f0c83bb690033a6c4a8e962d34b51e27aeaa33a0d41e852a78af96c6dfba1d36364996df4eaaacc993e5633528fb0d106753112ecbfe7fec74ea75d2d1b16267ee1b3d6145e746f19d0840be93d38baa3a5c7d42c6a05311092b4fe05e38aa9e24fb9c99a5aa4bc485752d049703409ccb6656150eeb34048030f19b5353df1e23b376b1c4be2925034d8b7a847690ca7f0c4f338c30b461d9e8c1a1de094fea67efdc4d3da6e96a43cd51241f828f01028e5b0e9",
- "21c1bcbdd38fa9e8d86272f8c66c2b16768d00a79945c6014bb55374174299e4e7967f80f8df630af6f5aac52647e36437d08d0aabfd406b0984557a1a69b28f3706033ed34cde0d6bfd39a81a0fca04117cd7ac37f06815b6dc1a356454d669b0e7871238066b280f7c09e0365214235dcd39dfdf6e46ad632d50101029ff490910f79b754d99088059cf1d5da8a791b1a51d8d96fe428bac8f547dc2e9632c4e00b3a6e95d36d03d83969de2989c120aa3c54040bc7f49f910df6c5e4003721a03a3f1d743c457d0cbadbc0bd25ca7f464f404a1f39f852872314ca44ea35a32c150fc25094cd2147739d1a1e03e8f6e636170867687f1c511dbb936fb521b6639ebc145f03b6d1751fcdf14c5108e",
- "89f25b6a8ecee226a56d10e9cff57402c3198e7629d8c4152d9319172f0df07727e57ad2e170a0a32cf748f9dc0fe45597d26743a7254aebceb106f0f172a5f2aecf563787471334096bb202a07696b7e0cf22d7dda51e1cf0fcc3d0d5d0a9f4c7ea8999a3f4edb4bd7d3ecb26f2137fe9d443f34248265c25a12290866130c9ccd2dd263bce8b78c14ddbc0c94ed85da0c401ac614c789711c0e2db27ad6ef59aabfdbb6bf174fff2358c4a8d6b7e6cd2a0d41883f3563506755a920aaa7695cf35ffecb0b195d01d1d86ee1a015df5de2f145b61ef3bc5fff1634d911a69540c03444dcb256fa982b24cf064dd6e4dffe71f8d5648cf336acd9485f9d70e24f2ad6b4aa14511e7b660c0866f73672a"
- ]
- ],
- "public_share": "da6e96a43cd51241f828f01028e5b0e96639ebc145f03b6d1751fcdf14c5108ef2ad6b4aa14511e7b660c0866f73672a",
- "rand": "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f"
- },
- {
- "input_shares": [
- "db3fe5357f56f6cfe9a0a34ed08e231766b423d5670741c151f7bc28cb15c4c8688df838b6ef52d74c5bb5e8c8c607b2684c024da705b558163e3127ae09f4a5bf61dc6129d71755ec77b5d5a2fc088541fa612bf1273d94718e0d28b654ea9524148bf910a5c6d55b596e323d4f55ab63b0851e0985987ea39cf500bfd4d5faed37f519120b574aead76d706e149c54b6e790f7c35553f830f67553ff3f08db0e5d8a2e157f9c1ef6eedcb845a19fffd4f9c6e705b035c95f3ebe51219a91c6ffff33c52b8fd7e90417636bb443c98c3d6933b1599c09151095fff99d7af43d337fcf2afdc50144e5b8f5b1ff1f8cc8d442613dc76dd48100dd4637b38fc5fa249333c6d1e2bec2132a3e3cf5fd11f7e923fbf275071a71535740ac64de88b83ca002bd4490de5c7540e454331d46ebb925725b964ecfcc5c3bb076bf57fd819d0bd788b4495da456594503c8f5b618c4713e957a7589b151ead3a27ae80153b0fbc219f5524eec22dc91aa56ed87a71e2b6e6b857ee03a700fb5af5b23513fb63023c2764f74b40f00e44e2e7acd463e7f38c783a898015b51863659502645e7d7fdf14abf76c605d42e523a540f40e816db420d599cea502baa131d6b61b8add86a09b9f7587e107c6fc9043d72644053b54234146535e9ec25223d293f4a2a4481b5649a7625116aef735ecbbdd9e99076985e1c424e91c29ae231c01f2b12007c81a9b3c72a84522014f4cdcb949bb9850b62b1c9c5d35f0fc3dbf4f637af85d3082ffd15890041a455a5dd38efc902eb415afcd2c93a2b6ab46c88847f390affbc3a9af4745718044c9f23978027af66871e610e1beee21360fc5ae4f05ed32689328216db3c512fddacefb2713287f4f5069170db246ae0cb13b3b88f8d832d11ae6b26fe6f0f89b9a9056c28ad6160134ab1af4be606a2ca7d1256cfc223c823ae4921ba11aab9e4f8104885b3d17ac7826ad06b0fd0e54397e67179755b29c6d724f3e9d9a6934619ef0bfee72cdcf0031672bb6e55be53d3ef0fccf7beba7dea636eff7fdecee99f60a0bc5d5cb11e24683ca8085cf218a3607c3f5a051c33717f39834435c5c542f42bd9c9d9103173cb11436e2a626e228415924037ee4a4078f0d9a5bd0fef1dc9415740c4b32f51d199d912907a103c7e25928acadfb4dc1e8d32c34b4f0100bfe95feb850e0d7b359aae9a332913d1f8eca0d1cd93dee2f4b75076536037ca2b6bec5003ae89e03db9813d0dd2165bf50a836ca492f05750a3b5fff4d089fc54fdf225aa112d72ab021b0cef1b8d31c852133fae501406668db0cb4c3589934bde5ec218876b0dc4087b61d706234635d5d9065787a21ed895fb7c05902a554f879dae44d0905292815c5ae2338be1faa924d95673e4d904cc4215bfda1c9c0ca55fa38af6b696ef4f1a452d6870c1d82fa311cee716b00a11313a0ba7c4038e5e195b5e1d3502a44d9a9ab1636394821eaf157e6c77316f6e26b98ca81220752396890cce205581aead60bfcc3916a6c2d6d360c7e845e70c8c68e4acb5eb2877a9a7c7619eb79e2184afff7bb585319fa669b151040f5b15cab2d8c3a50379e9d9e8bf1ac6319bc32e489f64793f882d0e3e1906ac04d47eaec15c20c503d007d09d6a9b032d0f9a8b3d95447fcb1d4b7334b95d873a171f876dcc2a62a62af58e10802f88742027d3d27b9d72fea73dc84906d3dde03299dc3e033651406229da606162636465666768696a6b6c6d6e6f",
- "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f",
- "303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f"
- ],
- "measurement": [
- 19342,
- 19615,
- 3061
- ],
- "nonce": "000102030405060708090a0b0c0d0e0f",
- "out_shares": [
- [
- "fc936b02cb848e7e3c5840b05acfd699",
- "7c71902ed398efc35ebb269aa58e0d5a",
- "b90f902ade7fad281b8cfc5f1349ddf9"
- ],
- [
- "f9758e4a5c3d6d2a1b4b3c7e5d397d83",
- "9bb1de90bc4c2244e630e3b6780dc86a",
- "15735600bee57d499ed0890554ef5183"
- ],
- [
- "9b4106b3d83d0457705c83d147f7abe2",
- "89299140701aeef79e13f6aee1632a3b",
- "298919d5639ad48d0ea3799a98c7d082"
- ]
- ],
- "prep_messages": [
- "e129a25d4bb45ae8f5ff9d97d72f6d86"
- ],
- "prep_shares": [
- [
- "574ce7d79da173f0652f7d1e699d5fe7865e23ddbe20c3646ca1d41f8d0d123a831f3b90d5b917779d25ca7aafd5c903b4b996399d29d3af9fcb1c6549c36a639e45759c53b3bf6a1014fbdf7ea4d5d3726af036968d80aed52a7e48dc0a06ee66a6e34bf38ce1083cb56057cfbe98ae9138b635f2b64b60daf151ce214d33b99062b201463033142fc734e4c163fd8a5d2ea4503567c0a9739027883ab0b37ece24259b5ddcc88b3e272bbad93857a52a48abf5eb9fb135ccaf27fc0379f49f203cc0f5a4f14183ef3b935076893f0bc56dcd9b0ffbf8f711039bfd3fe894c0c007d8702db35ded99e2605fa3d9d4b70f6dfcdea9883c839e2a91aa358a38359e2d3cb20272a3ecb52e1edc17a48940",
- "21c1bcbdd38fa9e8d86272f8c66c2b167ab67945b007b46536ece1073c4ac681e7967f80f8df630af6f5aac52647e36454b87d9c2d6aa2d4c2186b47a6bef8153706033ed34cde0d6bfd39a81a0fca04618cc495486eccfbcba29099fb101871b0e7871238066b280f7c09e0365214230a741f21625c730fae5e37a7a3cbe0c00910f79b754d99088059cf1d5da8a7911221c38f8a6f79877dd34cb4fd2990744e00b3a6e95d36d03d83969de2989c12e44eb18d466e8954631aa1dbe84e78111a03a3f1d743c457d0cbadbc0bd25ca7de998de032e28d1a8ca88d584ad7a64032c150fc25094cd2147739d1a1e03e8f6e636170867687f1c511dbb936fb521b6639ebc145f03b6d1751fcdf14c5108e",
- "89f25b6a8ecee226a56d10e9cff57402a204a4e83b6b78a5aa32317f68443eac27e57ad2e170a0a32cf748f9dc0fe45524ab48c23361b4b327d498fd702f23b6aecf563787471334096bb202a07696b7eb8d79193777673f93547e14b15adb2ac7ea8999a3f4edb4bd7d3ecb26f2137f5e2881b52fd4d3ec538b978ebba54312ccd2dd263bce8b78c14ddbc0c94ed85d38fdf5fb7ee2eeb21ef066fdde8a94f89aabfdbb6bf174fff2358c4a8d6b7e6cdb080672d15b2ae06d6ca64387b56c00cf35ffecb0b195d01d1d86ee1a015df53e771738ec1faca3fcdfe4f033977dd50c03444dcb256fa982b24cf064dd6e4dffe71f8d5648cf336acd9485f9d70e24f2ad6b4aa14511e7b660c0866f73672a"
- ]
- ],
- "public_share": "9e2d3cb20272a3ecb52e1edc17a489406639ebc145f03b6d1751fcdf14c5108ef2ad6b4aa14511e7b660c0866f73672a",
- "rand": "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f"
- },
- {
- "input_shares": [
- "db3fe5357f56f6cfe9a0a34ed08e231766b423d5670741c151f7bc28cb15c4c8678df838b6ef52d74c5bb5e8c8c607b2674c024da705b558163e3127ae09f4a5c061dc6129d71755ec77b5d5a2fc088542fa612bf1273d94718e0d28b654ea9525148bf910a5c6d55b596e323d4f55ab62b0851e0985987ea39cf500bfd4d5faec37f519120b574aead76d706e149c54b6e790f7c35553f830f67553ff3f08db0f5d8a2e157f9c1ef6eedcb845a19fffd4f9c6e705b035c95f3ebe51219a91c6000034c52b8fd7e90417636bb443c98c3e6933b1599c09151095fff99d7af43d327fcf2afdc50144e5b8f5b1ff1f8cc8d442613dc76dd48100dd4637b38fc5fa249333c6d1e2bec2132a3e3cf5fd11f7e923fbf275071a71535740ac64de88b83ca002bd4490de5c7540e454331d46ebb925725b964ecfcc5c3bb076bf57fd819d0bd788b4495da456594503c8f5b618c4713e957a7589b151ead3a27ae80153b1fbc219f5524eec22dc91aa56ed87a71d2b6e6b857ee03a700fb5af5b23513fb63023c2764f74b40f00e44e2e7acd463e7f38c783a898015b51863659502645e6d7fdf14abf76c605d42e523a540f40e716db420d599cea502baa131d6b61b8add86a09b9f7587e107c6fc9043d72644153b54234146535e9ec25223d293f4a2a4481b5649a7625116aef735ecbbdd9e99076985e1c424e91c29ae231c01f2b11007c81a9b3c72a84522014f4cdcb949cb9850b62b1c9c5d35f0fc3dbf4f637af85d3082ffd15890041a455a5dd38efc902eb415afcd2c93a2b6ab46c88847f380affbc3a9af4745718044c9f23978027af66871e610e1beee21360fc5ae4f05ed32689328216db3c512fddacefb2713187f4f5069170db246ae0cb13b3b88f8d832d11ae6b26fe6f0f89b9a9056c28ac6160134ab1af4be606a2ca7d1256cfc323c823ae4921ba11aab9e4f8104885b3d17ac7826ad06b0fd0e54397e67179765b29c6d724f3e9d9a6934619ef0bfee72cdcf0031672bb6e55be53d3ef0fccf8beba7dea636eff7fdecee99f60a0bc5d5cb11e24683ca8085cf218a3607c3f5a051c33717f39834435c5c542f42bd9c9d9103173cb11436e2a626e228415924037ee4a4078f0d9a5bd0fef1dc9415740c4b32f51d199d912907a103c7e25928acadfb4dc1e8d32c34b4f0100bfe95feb850e0d7b359aae9a332913d1f8eca0d1cd93dee2f4b75076536037ca2b6bec5003ae89e03db9813d0dd2165bf50a836ca492f05750a3b5fff4d089fc54fdf225aa112d72ab021b0cef1b8d31c852133fae501406668db0cb4c3589934bde5ec218876b0dc4087b61d706234635d5d9065787a21ed895fb7c05902a554f879dae44d0905292815c5ae2338be1faa924c67468654e6880c69828616e9d011132b27aa457c6dcbd554ec4374ec882357626d6f323bfadc3b23ac6d390e40f8f2008e462458194a1f9d63e0b977f4be907f34aecb0a12ad13b95bfc858c412abab064106faf149e9b25cb557c12a54e6ae957097b8b11f174094d134cc213bf98da7c7619eb79e2184afff7bb585319fa67b935c839af760464b6f3d5402847d07d9cf6c2502ae55f33e08959b38de273b2911fa9ef530cc2cc1a1f3f8224ed7c8efe455f3ad1e462c1d089d4be054801a56ecdd4dca5bbc7191990a1c028d6d79934bf7aed757eccdd68512ebe9f919f087f6020e75fa8e281316ae3a0a50a7f5606162636465666768696a6b6c6d6e6f",
- "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f",
- "303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f"
- ],
- "measurement": [
- 15986,
- 24671,
- 23910
- ],
- "nonce": "000102030405060708090a0b0c0d0e0f",
- "out_shares": [
- [
- "e0866b02cb848e7e3c5840b05acfd699",
- "3c85902ed398efc35ebb269aa58e0d5a",
- "2a61902ade7fad281b8cfc5f1349ddf9"
- ],
- [
- "f9758e4a5c3d6d2a1b4b3c7e5d397d83",
- "9bb1de90bc4c2244e630e3b6780dc86a",
- "15735600bee57d499ed0890554ef5183"
- ],
- [
- "9b4106b3d83d0457705c83d147f7abe2",
- "89299140701aeef79e13f6aee1632a3b",
- "298919d5639ad48d0ea3799a98c7d082"
- ]
- ],
- "prep_messages": [
- "62b225fa36c2cbc5896a40b1360f0ce0"
- ],
- "prep_shares": [
- [
- "574ce7d79da173f0652f7d1e699d5fe74186663960507c6ac01fafa7046bc88a5c4146feb2861bcb9f3ad8bb294028812c631ce293cde53b6fc09c6bdbcb839ede24393da7141c26a1a594ccdab1fba7ed2b2e38faf952343a2871b854699ff9533b4f88f9bc7e935cc62e3dea6efff7e2d396d8276281db4e789dc30d3fe01c397b64d685e87e7dccae1b7636b1a1486293f29e5c3433ee211e1f66ec5a7a0f1d79ed261735f53fdb51cbd51c1a6b057bf2845e34bfa091f0f8fd7565242c8b247064dfac759c1c646d085bca6ad0845b9cc2093fd49d493ebf2d48a90b99815f0bd165f56453c6b27dff04d3a161d9fc0bc4177e423791d4064faccfbbd3218c6815a24e38fb752efc839e59043cbb",
- "21c1bcbdd38fa9e8d86272f8c66c2b16ce028e4f460022aed5c3e47011081a9ce7967f80f8df630af6f5aac52647e36481e9f91e23071ea7d98af1e76a9dd5823706033ed34cde0d6bfd39a81a0fca048271f4696baf9fd2e8a37e7b5e1be75eb0e7871238066b280f7c09e036521423abafe75c716165e86a573bab2e46efda0910f79b754d99088059cf1d5da8a79146cedb83d4b00d96b9871a66d73147984e00b3a6e95d36d03d83969de2989c12e222e1015cad12a219308643f8e1c1511a03a3f1d743c457d0cbadbc0bd25ca7cb9908430d0604df4468ab54b36f81ef32c150fc25094cd2147739d1a1e03e8f6e636170867687f1c511dbb936fb521b6639ebc145f03b6d1751fcdf14c5108e",
- "89f25b6a8ecee226a56d10e9cff5740294125c8939f32731654a11d38906f94a27e57ad2e170a0a32cf748f9dc0fe45503b71c971d945163a09158bc06295e77aecf563787471334096bb202a07696b7f7c98da9fca5e00ff5ce6eb4b9d52274c7ea8999a3f4edb4bd7d3ecb26f2137fbd6dc71ed450947219eef408d88af7dbccd2dd263bce8b78c14ddbc0c94ed85db3255ece317e82a0f3b4a873e9b72b949aabfdbb6bf174fff2358c4a8d6b7e6c545473085c7c9b5c2aa9d290b01670ffcf35ffecb0b195d01d1d86ee1a015df56465c0991dd00dfda6948958c3ff38510c03444dcb256fa982b24cf064dd6e4dffe71f8d5648cf336acd9485f9d70e24f2ad6b4aa14511e7b660c0866f73672a"
- ]
- ],
- "public_share": "8c6815a24e38fb752efc839e59043cbb6639ebc145f03b6d1751fcdf14c5108ef2ad6b4aa14511e7b660c0866f73672a",
- "rand": "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f"
- }
- ],
- "shares": 3,
- "verify_key": "000102030405060708090a0b0c0d0e0f"
-}
diff --git a/third_party/rust/prio/src/vdaf/test_vec/07/Prio3Sum_0.json b/third_party/rust/prio/src/vdaf/test_vec/07/Prio3Sum_0.json
deleted file mode 100644
index 4dd3798668..0000000000
--- a/third_party/rust/prio/src/vdaf/test_vec/07/Prio3Sum_0.json
+++ /dev/null
@@ -1,40 +0,0 @@
-{
- "agg_param": null,
- "agg_result": 100,
- "agg_shares": [
- "0467d4fd6a7ec85386c9f3ef0790dc10",
- "61992b02958137ac5d360c10f86f23ef"
- ],
- "bits": 8,
- "prep": [
- {
- "input_shares": [
- "1ac8a54e6804d575f85957d45c728487722ad069fc1ed413da970ea56ae482d81057f898a367319a14f402d072c24bb71aa13cf4f9cdcd731e779aaa4a5d561ff40e41797cf2d43308849ff9080f846c2e78e2736a1d3cdaa68f3ec890d633cc13f5bf96466d3f02f93612bc827ff53357d52ae00dd234b9758f2cbb7aa9682d06041da1507aa12446de554a945924f445d3715279ef00f4c55ae987cec4bb9f1316efdc8737b7f924d046a6b8ef222b0dc1205ce9b464076fa80d2dfe37af4d836d597ade7d51e18e9c95d13158942d249efd0a1a226759e4bc1d46d3a41bdb227703fe0a7554cf4769935bc99cd1f35b274ecec240816af4915c7abe3e16b7be5ab5e105f9ae7b2e683191c9400cf99ab0c687e4929f87e6e64f712ca02f07a1b29fcebdbfde7655797f9c1b6b3114420d8a19736ae614116782278b7a71f9ef6928ad44ce588644886523d6fbe0b7bbb47248edbaa0b5ce33f74a07005e2a6842eb2c05778e170112f6e6a5f206d7830aa122e29069dcb4a4c064e63c29b3c6e2b22dfb5ab344ca0f1be8e8ce36d26435413de2dc4f53e158ebb8478b4a98de014a688db9470106fd7e73a65c2e656b5a627b5584ca0594ba10cc39c5612bcef576625c37c5249ad5c04e42c66d6a9653c4ec47e2bcd860870bef64f812974654f17f77c08eaa395803d33bdf31db17d76dbb9d2407d7c4f9efbce274542ff6aa0dcf188803eb586108317db430ad517ce7cb0f56d225c835161eb348949ebe253bedc338c6b939ce837561f01d7f0304963eab2a28b38c36bb169a4ee0637635818bd5e4798a8319152a2678b0aa7b837cb0f24df6148ae2c84b78db8892f4415f90f3804e7a29cdcd32a0a8625fd20aca47ee0ef12ebd6138b3534a1b42303132333435363738393a3b3c3d3e3f",
- "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f"
- ],
- "measurement": 100,
- "nonce": "000102030405060708090a0b0c0d0e0f",
- "out_shares": [
- [
- "0467d4fd6a7ec85386c9f3ef0790dc10"
- ],
- [
- "61992b02958137ac5d360c10f86f23ef"
- ]
- ],
- "prep_messages": [
- "0fd2bb14ac123437f6520fdc4a817934"
- ],
- "prep_shares": [
- [
- "61428b8d7e326827ac832bc4074ad61652efcfdb8d95b6f06b83dd9f5d55ce9f142d1a1fd437eb8c84581ad15dcd9a57417942e63a1a46e6b0ffc8b6d6300f7d",
- "a0bd747281cd97d8377cd43bf8b529e9eb5e4b1153111bd6cd06aa3a5493a6da4470f696b9afff52ec10fc00040e4538470fdb8d3e05e188aba2b16e24c71b69"
- ]
- ],
- "public_share": "417942e63a1a46e6b0ffc8b6d6300f7d470fdb8d3e05e188aba2b16e24c71b69",
- "rand": "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f"
- }
- ],
- "shares": 2,
- "verify_key": "000102030405060708090a0b0c0d0e0f"
-}
diff --git a/third_party/rust/prio/src/vdaf/test_vec/07/Prio3Sum_1.json b/third_party/rust/prio/src/vdaf/test_vec/07/Prio3Sum_1.json
deleted file mode 100644
index 8e7163ae2a..0000000000
--- a/third_party/rust/prio/src/vdaf/test_vec/07/Prio3Sum_1.json
+++ /dev/null
@@ -1,46 +0,0 @@
-{
- "agg_param": null,
- "agg_result": 100,
- "agg_shares": [
- "b3916e4086c52aa0439356b05082885a",
- "61992b02958137ac5d360c10f86f23ef",
- "52d565bde4b89db326369d3fb70d54b6"
- ],
- "bits": 8,
- "prep": [
- {
- "input_shares": [
- "ec863a16981eee70b71dc7d396a85ba412dcb4e86769d6db0c60f668456f5d6fbb844d9503580fb7b662bbb2ed7d92002e6ab4a2d31a6f611cbb5c48ca6df69811d536f74a3ff61eb29bd9b9f1b64c35eddd5c4ac97376057883a317f2989b545a682775f948f28f80f366f36b4eb90f931bca79e229eae377102295d9c46da2e239f74f045084747039c0a955726b4258bc0d14da7474bea6cd136eb5e55e9531e6a68703003a64943a5650b16674c82d9c4b526a7ed3d69f8f13ae83609cf056f3fed8d6593fdad7b367d2d248413072651073ea91b8162d42af168698f0f0928c8238b2df218e26d004d2bdb5f9f20d0a43c0286d08cfc26971f282992f82ff14d51cee3e0f3fc7411869c2176cabc6b1a68e33ff5eb217490de9f0d85cb84e9115bb7e208a190d25bf9cc138485892802a50b790ba6f45804de487a3353e54b5471adb5ab612d9ee6416649e136456215503637e0daab367149bc5cdf02a2dabc2790f84cadec1510263fe6aa27df5df395b7a241777a8ed28da27276b48f599dd895a005746cfd1f3c874e6f52407f4c417934d7091685c0b38b1d76b398ad263ec73f4f811aed38febf67a19a001a2c7ab8071f986939713cccd146c7a049c5129783359fcf86410765028fbfbbe62c2474a6b75de0ba49c037e07946deae971207f4f74b8b1d6a7b225eb0b66ed1f3878bc14d9d7a38b2162247b7ed9ac3df6fd2a98a3e4bf2855c8fb13f39487481fe03f5b5cb5123d11aaef180ff8ae69709322459a01a72e9304295ae5721d6eac6dae140677d0dd60f192f0475bacfd131d4ff3393238caa00fe0847c3a43c97a31f84f58b3c7487c5c0a09e85b39ed4b69fcdfa071da15216fd5f1fad125328e40689acce1a6cb113c2a16f599606162636465666768696a6b6c6d6e6f",
- "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f",
- "303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f"
- ],
- "measurement": 100,
- "nonce": "000102030405060708090a0b0c0d0e0f",
- "out_shares": [
- [
- "b3916e4086c52aa0439356b05082885a"
- ],
- [
- "61992b02958137ac5d360c10f86f23ef"
- ],
- [
- "52d565bde4b89db326369d3fb70d54b6"
- ]
- ],
- "prep_messages": [
- "e385da3bc2246be76ff12a7093ecb45e"
- ],
- "prep_shares": [
- [
- "7b6a9ad01449ec86dc6736dced3ecd24b47ab2a3768908b10696d537f2b02c98cf3314686f94ac37c7d81b14fea51f784e037bbdd56b2ee8486757acad61db1e",
- "40a478cd7376c1e9ea339ddcf96ab1a7eb5e4b1153111bd6cd06aa3a5493a6da4470f696b9afff52ec10fc00040e4538470fdb8d3e05e188aba2b16e24c71b69",
- "46f1ec617740528f1c642c47185681331adc83aace0cc5ddd256cf295c93c64d207d424f5056a8d59748ba9e423c4cf5f560fb4c6505c9a773629e12f21ee230"
- ]
- ],
- "public_share": "4e037bbdd56b2ee8486757acad61db1e470fdb8d3e05e188aba2b16e24c71b69f560fb4c6505c9a773629e12f21ee230",
- "rand": "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f"
- }
- ],
- "shares": 3,
- "verify_key": "000102030405060708090a0b0c0d0e0f"
-}
diff --git a/third_party/rust/prio/src/vdaf/test_vec/07/XofFixedKeyAes128.json b/third_party/rust/prio/src/vdaf/test_vec/07/XofFixedKeyAes128.json
deleted file mode 100644
index ea76c50ff8..0000000000
--- a/third_party/rust/prio/src/vdaf/test_vec/07/XofFixedKeyAes128.json
+++ /dev/null
@@ -1,8 +0,0 @@
-{
- "binder": "62696e64657220737472696e67",
- "derived_seed": "9cb53deb2feda2f9a7f34fde29a833f4",
- "dst": "646f6d61696e2073657061726174696f6e20746167",
- "expanded_vec_field128": "9cb53deb2feda2f9a7f34fde29a833f44ade288b2f55f2cd257e5f40595b5069543b40b740dfcf8ab5c863924f4510716b625f633a2f7e55a50b24a5fec9155dec199170f9ebe46768e9d120f7e8f62840441ef53dd5d2ba2d3fd39032e2da99498f4abf815b09c667cef08f0882fa945ba3335d2c7407de1b1650a5f4fe52884caf3ef1f5802eabb8f238c4d9d419bed904dcf79b22da49f68fb547c287a9cd4a38d58017eb2031a6bf1b4defb8905c3b777e9287f62a7fb0f97e4d8a26c4e5b909958bc73a6f7512b5b845488d98a7fcedf711ada6972f4c06818d3c3e7a070a88af60dc0323b59f304935fbbbd3792e590c9b6bce7459deba3599c7f30fe64a638219dde4bde4b1a51df8d85c2f36604c44f5f188148e3ba1dca3fd8073240ee577ef322df19a13d9ffa486a6833f4eb2838a58746707b8bf531cc86098f43809276b5f02914b26cb75938ca16eafa73397920a2f5e607af30e62ff60b83e15699d4d0265affe185b307ed330941a41b2b628e44d9a19412f7d9513cacd7b1fd740b7708e3bc764a0cf2146bca7c94d1901c43f509d7dcc9dfec54476789284e53f3760610a0ac5fce205e9b9aa0355c29702a5c9395bf1de8c974c800e1037a6bf5e0bd2af7d96b7f000ff6ab93299966b6832c493b600f2595a3db99353d2f8889019cd3ec5a73fa457f5442ed5edf349e78c9cf0cbf4f65aea03754c381c3efc206b7f17447cc51ac68eceacab9d92b13b0bc700c99a26ce2b6c3271f7639aa72dc27bbd54984907abb10ef1047ef352d378ddae48bf381804c89aa1847f5027537cf6af1b30aa44cead6495e98ca5b3205d39beb49d2db6752a4e57158e8c83464002b0b4a9838bc381c1dbdc3e9a584554fb76671a15f907c0b395a5",
- "length": 40,
- "seed": "000102030405060708090a0b0c0d0e0f"
-}
diff --git a/third_party/rust/prio/src/vdaf/test_vec/07/XofShake128.json b/third_party/rust/prio/src/vdaf/test_vec/07/XofShake128.json
deleted file mode 100644
index edafb1bd4d..0000000000
--- a/third_party/rust/prio/src/vdaf/test_vec/07/XofShake128.json
+++ /dev/null
@@ -1,8 +0,0 @@
-{
- "binder": "62696e64657220737472696e67",
- "derived_seed": "87c4d0dd654bf8eec8805c68b5eb0182",
- "dst": "646f6d61696e2073657061726174696f6e20746167",
- "expanded_vec_field128": "87c4d0dd654bf8eec8805c68b5eb0182b1b8ede598cfb8d8b234038fd0492eb14268bbb2ac15a55d463c8227c2d4fae8607631d13157c4935c5d2d56e4b1e2bdfe0f80b286d82e631704acee29ab6f7acaa316d3623cc3371297604caf57bc2eafe72056143971345901b9fb9f95b6a7384c6a88143124ff693ce9e453675f87a6b6338a1e1c9f72d19e32b51f60a1d7469de1fbe25407cc338d896b34c5fc437d2551297027eeefca9aaccdb78d655a6c220cbc2d76cc4a64b04806ae893c952996abb91f6ec32b6de27fe51be59514352d31af4967c0a85c5823ff73be7f15b9c0769321e4b69cb931a4e88f9da1fde1c5df9d84a7eadb41cf25681fc64a84a1c4accded794c1e6fec1fb26a286712425bfc29521273dcfc76cbab9b3c3c2b840ab6a4f9fd73ea434fc1c22a91943ed38fef0136f0f18f680c191978ab77c750d577c3526a327564da05cfc7bb9ef52c140d9e63b1f39761648772eaa61e2efb15890aed8340e6854b428f16dff5654c8a0852d46e817b49bbe91db3c46620adbd009a0d7d40843c1b6b7786833d3c1ae097b4fa35815dbcfca78e00a34f15936ed6d0f5bf50fc25adbecd3adfa55ba6bc7052f0662595cf7a933dfcc3d0ad5d825ec3bc191586a1c36a037d1c9e73c24777825d6afe59774abdb2918c2147a0436b17bafd967e07c46c3d6240c771f4fd4f9b3fff38b294508b8af5a1b71385f90f407620b7aa636fd2b55435b3688fc26ad3c23b2ad48158c4c475c07eb58569a8d1a906452b82d582397c4c69f5e79d3082d03b4dd85b5277a8b44c933d52d168caae8c602376f5487670a172d138364cb975c569c9c2d79506746090ea8102907c91b66764fd8740ca7bd3acb59173df29b5fa7542e51bce67b97c9ee2",
- "length": 40,
- "seed": "000102030405060708090a0b0c0d0e0f"
-}
diff --git a/third_party/rust/prio/src/vdaf/test_vec/08/IdpfPoplar_0.json b/third_party/rust/prio/src/vdaf/test_vec/08/IdpfPoplar_0.json
new file mode 100644
index 0000000000..68f3159234
--- /dev/null
+++ b/third_party/rust/prio/src/vdaf/test_vec/08/IdpfPoplar_0.json
@@ -0,0 +1,52 @@
+{
+ "alpha": "0",
+ "beta_inner": [
+ [
+ "0",
+ "0"
+ ],
+ [
+ "1",
+ "1"
+ ],
+ [
+ "2",
+ "2"
+ ],
+ [
+ "3",
+ "3"
+ ],
+ [
+ "4",
+ "4"
+ ],
+ [
+ "5",
+ "5"
+ ],
+ [
+ "6",
+ "6"
+ ],
+ [
+ "7",
+ "7"
+ ],
+ [
+ "8",
+ "8"
+ ]
+ ],
+ "beta_leaf": [
+ "9",
+ "9"
+ ],
+ "binder": "736f6d65206e6f6e6365",
+ "bits": 10,
+ "keys": [
+ "000102030405060708090a0b0c0d0e0f",
+ "101112131415161718191a1b1c1d1e1f"
+ ],
+ "public_share": "18850fb4933f36be2d456c4e2477baf2c9a4a7204fb09ae3e3ff925ecfe07a297b07b1980635d1e1f512afbd6388c98f5bf076cc5fe746282e59b81e51bffd6699fac7ec2dab3e9dd2c60d896beb64131d73b8abd7b2f0b327e5d91b42c677468048180e55bd80946611101ff01cb82022f7aecbe1db443499a311b7b9ee114acc16ae30d73d77ab2995eef0d536c26753647394f24d0c7b6db95b0eda08056b919e862c373e9c7a1e17590e5d5f250e56249ad28f9c13a8b57dfd7dcd05d78d49640d0aa35173cb4a659ada59f57d0c408edf52cb16d8bfb5c5d56d0c28a1aa7d96054c848cfeb0eeb6576b7c8c5328dfe502bc5eef4f1c6f58abe9ad37b448995e2b584cdb5f3a94f056ca7b868ad8f593f07c73f88596398fb4f13c5a7393b8fb0d2c76076132f54484f5f18209f42e4fe98ba2b9b1d1d19c139dc4520ada547ddbb70baecf1bba61a7b3cbb4648a7235142e201a173038dac559940a55d29a68cc87298d722b6644fa445460ddb9938c64"
+}
diff --git a/third_party/rust/prio/src/vdaf/test_vec/08/Poplar1_0.json b/third_party/rust/prio/src/vdaf/test_vec/08/Poplar1_0.json
new file mode 100644
index 0000000000..c4056a156a
--- /dev/null
+++ b/third_party/rust/prio/src/vdaf/test_vec/08/Poplar1_0.json
@@ -0,0 +1,56 @@
+{
+ "agg_param": [
+ 0,
+ [
+ 0,
+ 1
+ ]
+ ],
+ "agg_result": [
+ 0,
+ 1
+ ],
+ "agg_shares": [
+ "42417a6b9fd228e050220f57293f7555",
+ "bfbe85945f2dd71fb2ddf0a8d5c08aaa"
+ ],
+ "bits": 4,
+ "prep": [
+ {
+ "input_shares": [
+ "000102030405060708090a0b0c0d0e0f202122232425262728292a2b2c2d2e2f53a9af607a9ba90a1d3f318b8c32b858b3d50db495dd0cea621fc5acb48f197bd4e873a62181a039dda958c94fddf92a8c77579c03c6dfc230f22f48f76c4f904d2b114e3c8289045ca768975bbede4b411e83158149e59dcbccf8746fd6c3e46d02f6c1d55b61707cf072837674ce53",
+ "101112131415161718191a1b1c1d1e1f303132333435363738393a3b3c3d3e3ff353dae51a27e776577e4452505c1be72ff784ff29b113a7d382ed46393d577cbd67fe52d4b6de1db2e204d4a6eaca3e7cee015d5fe92a830800f01375b8b9e799ac36fc76ae347a6478dad319ed9e59a21d8102ae380d8462c88d5b5bdf438b46dfec7042682ff4ac55fb9e516d1721"
+ ],
+ "measurement": 13,
+ "nonce": "000102030405060708090a0b0c0d0e0f",
+ "out_shares": [
+ [
+ "42417a6b9fd228e0",
+ "50220f57293f7555"
+ ],
+ [
+ "bfbe85945f2dd71f",
+ "b2ddf0a8d5c08aaa"
+ ]
+ ],
+ "prep_messages": [
+ "f7c882b687b7bd461fb1f898356db5fa88833cdaa1e26a71",
+ ""
+ ],
+ "prep_shares": [
+ [
+ "029b574f4e07246cb5b90e90207a148abb7dfba2efb9a32a",
+ "f62d2b6738b099da6af7e90815f3a070cd054137b228c746"
+ ],
+ [
+ "264531e72e56a380",
+ "dbbace18d0a95c7f"
+ ]
+ ],
+ "public_share": "dfe8ba3fa8bf0b8340a577388d7f4537bc2ed02a8b8c11e498d8ffdf6eae85c76f1c8c890ad535ba72d385b77962a0a8dbb59836381fbd9d80814b2b0d95948d11ee55bcd51bece3c27a76ad9aa132f4dfe46ee0783cdf650b6276ffda3830a7f61a859d311aa38580829ef9097c0a5032d798b8a28a17869323b84f36f0e6fe82ed6bc5bff3ae8cc4d32d25ff56e9af6da83c2943b41bb4a49555dcdc76033c31ec7098db3274261f3b50d3335fc1474e",
+ "rand": "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f"
+ }
+ ],
+ "shares": 2,
+ "verify_key": "000102030405060708090a0b0c0d0e0f"
+}
diff --git a/third_party/rust/prio/src/vdaf/test_vec/08/Poplar1_1.json b/third_party/rust/prio/src/vdaf/test_vec/08/Poplar1_1.json
new file mode 100644
index 0000000000..ea8bbfea10
--- /dev/null
+++ b/third_party/rust/prio/src/vdaf/test_vec/08/Poplar1_1.json
@@ -0,0 +1,64 @@
+{
+ "agg_param": [
+ 1,
+ [
+ 0,
+ 1,
+ 2,
+ 3
+ ]
+ ],
+ "agg_result": [
+ 0,
+ 0,
+ 0,
+ 1
+ ],
+ "agg_shares": [
+ "f4265a0ff9c4f0d1f068b522d608c1a38cde98228531a78ccb74919ef72f5051",
+ "0dd9a5f0053b0f2e11974add28f73e5c752167dd79ce5873378b6e6107d0afae"
+ ],
+ "bits": 4,
+ "prep": [
+ {
+ "input_shares": [
+ "000102030405060708090a0b0c0d0e0f202122232425262728292a2b2c2d2e2f53a9af607a9ba90a1d3f318b8c32b858b3d50db495dd0cea621fc5acb48f197bd4e873a62181a039dda958c94fddf92a8c77579c03c6dfc230f22f48f76c4f904d2b114e3c8289045ca768975bbede4b411e83158149e59dcbccf8746fd6c3e46d02f6c1d55b61707cf072837674ce53",
+ "101112131415161718191a1b1c1d1e1f303132333435363738393a3b3c3d3e3ff353dae51a27e776577e4452505c1be72ff784ff29b113a7d382ed46393d577cbd67fe52d4b6de1db2e204d4a6eaca3e7cee015d5fe92a830800f01375b8b9e799ac36fc76ae347a6478dad319ed9e59a21d8102ae380d8462c88d5b5bdf438b46dfec7042682ff4ac55fb9e516d1721"
+ ],
+ "measurement": 13,
+ "nonce": "000102030405060708090a0b0c0d0e0f",
+ "out_shares": [
+ [
+ "f4265a0ff9c4f0d1",
+ "f068b522d608c1a3",
+ "8cde98228531a78c",
+ "cb74919ef72f5051"
+ ],
+ [
+ "0dd9a5f0053b0f2e",
+ "11974add28f73e5c",
+ "752167dd79ce5873",
+ "378b6e6107d0afae"
+ ]
+ ],
+ "prep_messages": [
+ "d2ca8d38065df3047d92ebacf9c366b83ad81d98fb17356a",
+ ""
+ ],
+ "prep_shares": [
+ [
+ "4c00ed0607d7702352c8786bb90f360edd89e3c8507274b1",
+ "87caa031fe8582e12bca724140b430aa5e4e3acfa9a5c0b8"
+ ],
+ [
+ "1ed0621986d79f57",
+ "e32f9de6782860a8"
+ ]
+ ],
+ "public_share": "dfe8ba3fa8bf0b8340a577388d7f4537bc2ed02a8b8c11e498d8ffdf6eae85c76f1c8c890ad535ba72d385b77962a0a8dbb59836381fbd9d80814b2b0d95948d11ee55bcd51bece3c27a76ad9aa132f4dfe46ee0783cdf650b6276ffda3830a7f61a859d311aa38580829ef9097c0a5032d798b8a28a17869323b84f36f0e6fe82ed6bc5bff3ae8cc4d32d25ff56e9af6da83c2943b41bb4a49555dcdc76033c31ec7098db3274261f3b50d3335fc1474e",
+ "rand": "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f"
+ }
+ ],
+ "shares": 2,
+ "verify_key": "000102030405060708090a0b0c0d0e0f"
+}
diff --git a/third_party/rust/prio/src/vdaf/test_vec/08/Poplar1_2.json b/third_party/rust/prio/src/vdaf/test_vec/08/Poplar1_2.json
new file mode 100644
index 0000000000..9b4fd0bc70
--- /dev/null
+++ b/third_party/rust/prio/src/vdaf/test_vec/08/Poplar1_2.json
@@ -0,0 +1,64 @@
+{
+ "agg_param": [
+ 2,
+ [
+ 0,
+ 2,
+ 4,
+ 6
+ ]
+ ],
+ "agg_result": [
+ 0,
+ 0,
+ 0,
+ 1
+ ],
+ "agg_shares": [
+ "6bc200377c0ebf33de6ac488c1427b38bea3859050a09e19208319b3875c5099",
+ "963dffc882f140cc23953b773dbd84c7435c7a6fae5f61e6e27ce64c77a3af66"
+ ],
+ "bits": 4,
+ "prep": [
+ {
+ "input_shares": [
+ "000102030405060708090a0b0c0d0e0f202122232425262728292a2b2c2d2e2f53a9af607a9ba90a1d3f318b8c32b858b3d50db495dd0cea621fc5acb48f197bd4e873a62181a039dda958c94fddf92a8c77579c03c6dfc230f22f48f76c4f904d2b114e3c8289045ca768975bbede4b411e83158149e59dcbccf8746fd6c3e46d02f6c1d55b61707cf072837674ce53",
+ "101112131415161718191a1b1c1d1e1f303132333435363738393a3b3c3d3e3ff353dae51a27e776577e4452505c1be72ff784ff29b113a7d382ed46393d577cbd67fe52d4b6de1db2e204d4a6eaca3e7cee015d5fe92a830800f01375b8b9e799ac36fc76ae347a6478dad319ed9e59a21d8102ae380d8462c88d5b5bdf438b46dfec7042682ff4ac55fb9e516d1721"
+ ],
+ "measurement": 13,
+ "nonce": "000102030405060708090a0b0c0d0e0f",
+ "out_shares": [
+ [
+ "6bc200377c0ebf33",
+ "de6ac488c1427b38",
+ "bea3859050a09e19",
+ "208319b3875c5099"
+ ],
+ [
+ "963dffc882f140cc",
+ "23953b773dbd84c7",
+ "435c7a6fae5f61e6",
+ "e27ce64c77a3af66"
+ ]
+ ],
+ "prep_messages": [
+ "453405bb632d670892ddc291c4d886ce098d206debd7e121",
+ ""
+ ],
+ "prep_shares": [
+ [
+ "bd7d6befff9982c88c631d4c593d754f4b817e23f0faf751",
+ "89b699cb6293e43f067aa5456b9b117fbf0ba249fadce9cf"
+ ],
+ [
+ "c36085ecec965e1f",
+ "3e9f7a131269a1e0"
+ ]
+ ],
+ "public_share": "dfe8ba3fa8bf0b8340a577388d7f4537bc2ed02a8b8c11e498d8ffdf6eae85c76f1c8c890ad535ba72d385b77962a0a8dbb59836381fbd9d80814b2b0d95948d11ee55bcd51bece3c27a76ad9aa132f4dfe46ee0783cdf650b6276ffda3830a7f61a859d311aa38580829ef9097c0a5032d798b8a28a17869323b84f36f0e6fe82ed6bc5bff3ae8cc4d32d25ff56e9af6da83c2943b41bb4a49555dcdc76033c31ec7098db3274261f3b50d3335fc1474e",
+ "rand": "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f"
+ }
+ ],
+ "shares": 2,
+ "verify_key": "000102030405060708090a0b0c0d0e0f"
+}
diff --git a/third_party/rust/prio/src/vdaf/test_vec/08/Poplar1_3.json b/third_party/rust/prio/src/vdaf/test_vec/08/Poplar1_3.json
new file mode 100644
index 0000000000..f280aedebc
--- /dev/null
+++ b/third_party/rust/prio/src/vdaf/test_vec/08/Poplar1_3.json
@@ -0,0 +1,76 @@
+{
+ "agg_param": [
+ 3,
+ [
+ 1,
+ 3,
+ 5,
+ 7,
+ 9,
+ 13,
+ 15
+ ]
+ ],
+ "agg_result": [
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 1,
+ 0
+ ],
+ "agg_shares": [
+ "7e787b132dfe4dfcf9f8cab505a6133d30b7fd75f52a422d05ce25abe1b9cc5d3c4dce1f874d3e6bc4e9d9162ce3ae1e01da0581055c3d83de238e22b71bed1e8a69ed19cf9ccc49f2bb00c049d3153af4087218b63d6ae26ad30ca130641f50cb85fedfecf35fed0451625ebf2dac37281549b3cd8798fdd12d3eca3a68a17ec2c6f6086fca7b6dd59cd532e1b72bc95bedbfb4ce1dcc7cc873d989601e8a16ca1724e563a6c114b58e3bf58a65c621b00ebd22074223ec8e863c418a8ec83e0701d49174dab847df196325664790b6aba39c2d8ab74275b80ecc5d85c43c61",
+ "6f8784ecd201b2030607354afa59ecc2cf48028a0ad5bdd2fa31da541e463322b1b231e078b2c1943b1626e9d31c51e1fe25fa7efaa3c27c21dc71dd48e41261639612e6306333b60d44ff3fb62ceac50bf78de749c2951d952cf35ecf9be02f227a0120130ca012fbae9da140d253c8d7eab64c327867022ed2c135c5975e012b3909f7903584922a632acd1e48d436a412404b31e23383378c26769fe1756924e8db1a9c593eeb4a71c40a759a39de4ff142ddf8bddc137179c3be75713741e6fe2b6e8b2547b820e69cda99b86f49545c63d27548bd8a47f133a27a3bc31e"
+ ],
+ "bits": 4,
+ "prep": [
+ {
+ "input_shares": [
+ "000102030405060708090a0b0c0d0e0f202122232425262728292a2b2c2d2e2f53a9af607a9ba90a1d3f318b8c32b858b3d50db495dd0cea621fc5acb48f197bd4e873a62181a039dda958c94fddf92a8c77579c03c6dfc230f22f48f76c4f904d2b114e3c8289045ca768975bbede4b411e83158149e59dcbccf8746fd6c3e46d02f6c1d55b61707cf072837674ce53",
+ "101112131415161718191a1b1c1d1e1f303132333435363738393a3b3c3d3e3ff353dae51a27e776577e4452505c1be72ff784ff29b113a7d382ed46393d577cbd67fe52d4b6de1db2e204d4a6eaca3e7cee015d5fe92a830800f01375b8b9e799ac36fc76ae347a6478dad319ed9e59a21d8102ae380d8462c88d5b5bdf438b46dfec7042682ff4ac55fb9e516d1721"
+ ],
+ "measurement": 13,
+ "nonce": "000102030405060708090a0b0c0d0e0f",
+ "out_shares": [
+ [
+ "7e787b132dfe4dfcf9f8cab505a6133d30b7fd75f52a422d05ce25abe1b9cc5d",
+ "3c4dce1f874d3e6bc4e9d9162ce3ae1e01da0581055c3d83de238e22b71bed1e",
+ "8a69ed19cf9ccc49f2bb00c049d3153af4087218b63d6ae26ad30ca130641f50",
+ "cb85fedfecf35fed0451625ebf2dac37281549b3cd8798fdd12d3eca3a68a17e",
+ "c2c6f6086fca7b6dd59cd532e1b72bc95bedbfb4ce1dcc7cc873d989601e8a16",
+ "ca1724e563a6c114b58e3bf58a65c621b00ebd22074223ec8e863c418a8ec83e",
+ "0701d49174dab847df196325664790b6aba39c2d8ab74275b80ecc5d85c43c61"
+ ],
+ [
+ "6f8784ecd201b2030607354afa59ecc2cf48028a0ad5bdd2fa31da541e463322",
+ "b1b231e078b2c1943b1626e9d31c51e1fe25fa7efaa3c27c21dc71dd48e41261",
+ "639612e6306333b60d44ff3fb62ceac50bf78de749c2951d952cf35ecf9be02f",
+ "227a0120130ca012fbae9da140d253c8d7eab64c327867022ed2c135c5975e01",
+ "2b3909f7903584922a632acd1e48d436a412404b31e23383378c26769fe17569",
+ "24e8db1a9c593eeb4a71c40a759a39de4ff142ddf8bddc137179c3be75713741",
+ "e6fe2b6e8b2547b820e69cda99b86f49545c63d27548bd8a47f133a27a3bc31e"
+ ]
+ ],
+ "prep_messages": [
+ "d6ce08ae0327f913210f5e0701c594bf1baa15a33f6933f9b73787f73464db6a6a10f3c7e7e76a1844367d0091f16a7f090e7ed1fcc6f2a456e9e12daec41b18e08c45f8b9c5d20b02e8fecd25cb7fc05e98a6c79a1ee08da284161b3bd94d53",
+ ""
+ ],
+ "prep_shares": [
+ [
+ "b289bbdd941be53774dbb8177fd40ee4614c325d64ca211dee7268c34fd93c7855030fd22ac1db9e4760d9cd03a090b976b2b9a9bcef2e9f9affeb5cd6afe05423b5b3db766c04dc072864e1dd8b0d0fabf8b8add732c7eeff4ae5ba5fe0fc13",
+ "11454dd06e0b14dcac33a5ef81f085dbb95de345db9e11dcc9c41e34e58a9e72020de4f5bc268f79fcd5a3328d51dac5925bc42740d7c305bce9f5d0d7143b43bdd7911c4359ce2ffabf9aec473f72b1b39fed19c3eb189fa2393160dbf8503f"
+ ],
+ [
+ "b4fe321bd55f5135b7ebfda820401ad7b7fba83b65e68b8ede4b0a566a9f5629",
+ "3901cde42aa0aeca48140257dfbfe528480457c49a19747121b4f5a99560a956"
+ ]
+ ],
+ "public_share": "dfe8ba3fa8bf0b8340a577388d7f4537bc2ed02a8b8c11e498d8ffdf6eae85c76f1c8c890ad535ba72d385b77962a0a8dbb59836381fbd9d80814b2b0d95948d11ee55bcd51bece3c27a76ad9aa132f4dfe46ee0783cdf650b6276ffda3830a7f61a859d311aa38580829ef9097c0a5032d798b8a28a17869323b84f36f0e6fe82ed6bc5bff3ae8cc4d32d25ff56e9af6da83c2943b41bb4a49555dcdc76033c31ec7098db3274261f3b50d3335fc1474e",
+ "rand": "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f"
+ }
+ ],
+ "shares": 2,
+ "verify_key": "000102030405060708090a0b0c0d0e0f"
+}
diff --git a/third_party/rust/prio/src/vdaf/test_vec/08/Prio3Count_0.json b/third_party/rust/prio/src/vdaf/test_vec/08/Prio3Count_0.json
new file mode 100644
index 0000000000..c0336fa679
--- /dev/null
+++ b/third_party/rust/prio/src/vdaf/test_vec/08/Prio3Count_0.json
@@ -0,0 +1,39 @@
+{
+ "agg_param": null,
+ "agg_result": 1,
+ "agg_shares": [
+ "352c53cbc1f95eee",
+ "cdd3ac343d06a111"
+ ],
+ "prep": [
+ {
+ "input_shares": [
+ "352c53cbc1f95eee43253a8650e8ac18a5bd9c18b824886772947facdf1a413f1cf547cdb8c1ad4ed4c1294ccc856209",
+ "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f"
+ ],
+ "measurement": 1,
+ "nonce": "000102030405060708090a0b0c0d0e0f",
+ "out_shares": [
+ [
+ "352c53cbc1f95eee"
+ ],
+ [
+ "cdd3ac343d06a111"
+ ]
+ ],
+ "prep_messages": [
+ ""
+ ],
+ "prep_shares": [
+ [
+ "f6340e6030e5960b53ad59de202314363e6063ed75a89676e3b9635d397d650e",
+ "0bcbf19fce1a69f4b5de9ce10c9c671b9baa607f88bfa49de4367212193d9b3b"
+ ]
+ ],
+ "public_share": "",
+ "rand": "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f"
+ }
+ ],
+ "shares": 2,
+ "verify_key": "000102030405060708090a0b0c0d0e0f"
+}
diff --git a/third_party/rust/prio/src/vdaf/test_vec/08/Prio3Count_1.json b/third_party/rust/prio/src/vdaf/test_vec/08/Prio3Count_1.json
new file mode 100644
index 0000000000..6731f2a13b
--- /dev/null
+++ b/third_party/rust/prio/src/vdaf/test_vec/08/Prio3Count_1.json
@@ -0,0 +1,45 @@
+{
+ "agg_param": null,
+ "agg_result": 1,
+ "agg_shares": [
+ "4eeea47bcff955f0",
+ "cdd3ac343d06a111",
+ "e83dae4ff1ff08fe"
+ ],
+ "prep": [
+ {
+ "input_shares": [
+ "4eeea47bcff955f08194b8660a6bb007a346b42952b2298158c165d94c1c40979e10b54ae7092a5a14b325df003a6f9d",
+ "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f",
+ "202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f"
+ ],
+ "measurement": 1,
+ "nonce": "000102030405060708090a0b0c0d0e0f",
+ "out_shares": [
+ [
+ "4eeea47bcff955f0"
+ ],
+ [
+ "cdd3ac343d06a111"
+ ],
+ [
+ "e83dae4ff1ff08fe"
+ ]
+ ],
+ "prep_messages": [
+ ""
+ ],
+ "prep_shares": [
+ [
+ "817531f295522feac2551124114fdc827bfda7719fb1eb33b0b4e1c49761f62f",
+ "0bcbf19fce1a69f4b5de9ce10c9c671b9baa607f88bfa49de4367212193d9b3b",
+ "76bfdc6d999267219aa129cccf1e2459cf93ae20bf886d0d22fe0f5fcded28e6"
+ ]
+ ],
+ "public_share": "",
+ "rand": "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f"
+ }
+ ],
+ "shares": 3,
+ "verify_key": "000102030405060708090a0b0c0d0e0f"
+}
diff --git a/third_party/rust/prio/src/vdaf/test_vec/08/Prio3Histogram_0.json b/third_party/rust/prio/src/vdaf/test_vec/08/Prio3Histogram_0.json
new file mode 100644
index 0000000000..b39dc2838d
--- /dev/null
+++ b/third_party/rust/prio/src/vdaf/test_vec/08/Prio3Histogram_0.json
@@ -0,0 +1,52 @@
+{
+ "agg_param": null,
+ "agg_result": [
+ 0,
+ 0,
+ 1,
+ 0
+ ],
+ "agg_shares": [
+ "ac3ba28d7f5649e6b3932251da118acf6740508adaf7837c87cd0574c48a00ea2ba59154eff2921c69cdeb23276510d3758486d91898690c4ba0fd3e6e149956",
+ "55c45d7280a9b619306cddae25ee75309abfaf7525087c835c32fa8b3b75ff15d75a6eab100d6de37a3214dcd89aef2c8c7b7926e76796f3985f02c191eb66a9"
+ ],
+ "chunk_length": 2,
+ "length": 4,
+ "prep": [
+ {
+ "input_shares": [
+ "ac3ba28d7f5649e6b3932251da118acf6740508adaf7837c87cd0574c48a00ea2ba59154eff2921c69cdeb23276510d3758486d91898690c4ba0fd3e6e149956aaa0fbc70889fae40bf0b8873db6f2c2c26ef6772e0dd8d091e12a1dbe4388bbc88819a887c53a4afa8e3e35b0c00100af9000ad245790e71c322e5c252e25a25514ccc4ebeb9b9f47a98223b2d04d44f94a2cb4791ff9a056eca2a0c74ab11f08d41d917cdaa2858d372c08339c414559066eb7be61cf2b5bb36c7c598a97b19802fead02586c39b001c18b5ff36e66d9ab75d6e9c6c0c0eaae66b1014ba2645047801054acea9f87404cc2749584db303132333435363738393a3b3c3d3e3f",
+ "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f"
+ ],
+ "measurement": 2,
+ "nonce": "000102030405060708090a0b0c0d0e0f",
+ "out_shares": [
+ [
+ "ac3ba28d7f5649e6b3932251da118acf",
+ "6740508adaf7837c87cd0574c48a00ea",
+ "2ba59154eff2921c69cdeb23276510d3",
+ "758486d91898690c4ba0fd3e6e149956"
+ ],
+ [
+ "55c45d7280a9b619306cddae25ee7530",
+ "9abfaf7525087c835c32fa8b3b75ff15",
+ "d75a6eab100d6de37a3214dcd89aef2c",
+ "8c7b7926e76796f3985f02c191eb66a9"
+ ]
+ ],
+ "prep_messages": [
+ "1acd91a20b79e95050d47db9bf4b1ed5"
+ ],
+ "prep_shares": [
+ [
+ "aaf0cada92114681d890231d05395ea51dcf30c4fa042de2f21b10d3126976a4565c5032534c5af98418b0bf0647dddada1e47da1c608f0d03070d5baf530d1e52b4ace95d26bdc41c0bf64068880a5bcbf5ab84954e1087ff8721b600477c48bc82ef4255afbf48216c910cd76ca594",
+ "570f35256deeb97e0b6fdce2fac6a15a8d4d3367a586ac831119c6edeefb5ab1d4a2ad70c499a97f61b3eb86717264b1a941e67b26a189ff84bc81c89edafd3187e190bacd40bfa5813ccbd77338c7eedb90e273a045b29382cdddc5571e35de1da4a26362199818038b8624ba1ea4a9"
+ ]
+ ],
+ "public_share": "bc82ef4255afbf48216c910cd76ca5941da4a26362199818038b8624ba1ea4a9",
+ "rand": "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f"
+ }
+ ],
+ "shares": 2,
+ "verify_key": "000102030405060708090a0b0c0d0e0f"
+}
diff --git a/third_party/rust/prio/src/vdaf/test_vec/08/Prio3Histogram_1.json b/third_party/rust/prio/src/vdaf/test_vec/08/Prio3Histogram_1.json
new file mode 100644
index 0000000000..512b2aca98
--- /dev/null
+++ b/third_party/rust/prio/src/vdaf/test_vec/08/Prio3Histogram_1.json
@@ -0,0 +1,89 @@
+{
+ "agg_param": null,
+ "agg_result": [
+ 0,
+ 0,
+ 1,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0
+ ],
+ "agg_shares": [
+ "6ef23fd4b5f5502e5c215848c3703c1ac06dbc83cebd2ebb78b8549c64cf10b6a709f226d0e6aadbaac7c1512dce7f44e0715547855fae84e0a1f1fe7612423940c18ce556a3754c64b46de79038603b2ffae8c57346b7a9385f34f084d8f62d8e145aab9b0f1c038ed9f7b94d82a6cc7d32743c367987da80859005285a4b2f41e62177eead51b17bae964e100bd7408688c19870104fddb90ed31a0065a92f870079891c2ccc659a2a2cf3cb424cc3",
+ "55c45d7280a9b619306cddae25ee75309abfaf7525087c835c32fa8b3b75ff15d75a6eab100d6de37a3214dcd89aef2c8c7b7926e76796f3985f02c191eb66a970fd5de8e08724782338a0d5e77d181f61a976f8712fccdde127760cb8056d105e3d2f6c325607ab4a9a3ce791283b3af006fd1a4aa66fbfb30ade0e81c5d226e5c8ad6b7e4bdd02db51d98a13f5cf81d7797d2adb9c59afef3378108eec9ad02f4bddb5208b11cdd02e159b36eddd76",
+ "3e4962b9c960f8b75772ca0817a14db5a7d293060c3a55c10e15b1d75fbbef33849b9f2d1f0ce840be052ad2f996908e951231929338bb876afe0b40f701571d51411532c8d4653b5c13f242874987a5715ca0411a8a7c78c9785503c3219cc116ae76e8319adc51ef8bcb5e20551ef994c68ea87fe00866af6f91eb56e0e1a9db50301d9306d14b8dff8f26dcff583da5fdc03cb45257731ebdb4d471aebbff4cb4a9c0c24822cd5ca6be71fdcfd5c5"
+ ],
+ "chunk_length": 3,
+ "length": 11,
+ "prep": [
+ {
+ "input_shares": [
+ "6ef23fd4b5f5502e5c215848c3703c1ac06dbc83cebd2ebb78b8549c64cf10b6a709f226d0e6aadbaac7c1512dce7f44e0715547855fae84e0a1f1fe7612423940c18ce556a3754c64b46de79038603b2ffae8c57346b7a9385f34f084d8f62d8e145aab9b0f1c038ed9f7b94d82a6cc7d32743c367987da80859005285a4b2f41e62177eead51b17bae964e100bd7408688c19870104fddb90ed31a0065a92f870079891c2ccc659a2a2cf3cb424cc31d60b4e3908aa656e527d0a66eaeaaf493bde0a7a86be4ed3145a5596fab04256c95611675891b234a939c91215ec467aa9a516cd6a9a7b8d1a4ddb91e8dbfbcc8d9a45d8792f9d56a68061809b7ef4963736c20e3cb8ce6a95e1bd84c7ae51ccb14192b3101ac85a5a3a62415fb516df685b9313b53f39bc6a74062a55435f9c35f50ffd660a6d7e0e9365128bf6d87e52358afe563bc1bdce119291c611597889d36caf3247f61821eb596b089dddaf32359b12e74260a24d816335a2bf1aa93dbd84dd31773f2795ee931187525a570589f31e66a0e0d8a92370c3458fb00b2afb3e3d98f142cf9606d47d28a75caa8b4ee730e1ff3faf0aed3a154887dceaa6dfad49582d4a560b0d6599e0cbab2b36f20b8ca497f6540ca17f69595c695c2c6e0e00956acca22c71fab529936c47ad8de0e09f39d41a3b0469edcbfea242b20cd6a4748d4075ffb9a755b297902606162636465666768696a6b6c6d6e6f",
+ "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f",
+ "303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f"
+ ],
+ "measurement": 2,
+ "nonce": "000102030405060708090a0b0c0d0e0f",
+ "out_shares": [
+ [
+ "6ef23fd4b5f5502e5c215848c3703c1a",
+ "c06dbc83cebd2ebb78b8549c64cf10b6",
+ "a709f226d0e6aadbaac7c1512dce7f44",
+ "e0715547855fae84e0a1f1fe76124239",
+ "40c18ce556a3754c64b46de79038603b",
+ "2ffae8c57346b7a9385f34f084d8f62d",
+ "8e145aab9b0f1c038ed9f7b94d82a6cc",
+ "7d32743c367987da80859005285a4b2f",
+ "41e62177eead51b17bae964e100bd740",
+ "8688c19870104fddb90ed31a0065a92f",
+ "870079891c2ccc659a2a2cf3cb424cc3"
+ ],
+ [
+ "55c45d7280a9b619306cddae25ee7530",
+ "9abfaf7525087c835c32fa8b3b75ff15",
+ "d75a6eab100d6de37a3214dcd89aef2c",
+ "8c7b7926e76796f3985f02c191eb66a9",
+ "70fd5de8e08724782338a0d5e77d181f",
+ "61a976f8712fccdde127760cb8056d10",
+ "5e3d2f6c325607ab4a9a3ce791283b3a",
+ "f006fd1a4aa66fbfb30ade0e81c5d226",
+ "e5c8ad6b7e4bdd02db51d98a13f5cf81",
+ "d7797d2adb9c59afef3378108eec9ad0",
+ "2f4bddb5208b11cdd02e159b36eddd76"
+ ],
+ [
+ "3e4962b9c960f8b75772ca0817a14db5",
+ "a7d293060c3a55c10e15b1d75fbbef33",
+ "849b9f2d1f0ce840be052ad2f996908e",
+ "951231929338bb876afe0b40f701571d",
+ "51411532c8d4653b5c13f242874987a5",
+ "715ca0411a8a7c78c9785503c3219cc1",
+ "16ae76e8319adc51ef8bcb5e20551ef9",
+ "94c68ea87fe00866af6f91eb56e0e1a9",
+ "db50301d9306d14b8dff8f26dcff583d",
+ "a5fdc03cb45257731ebdb4d471aebbff",
+ "4cb4a9c0c24822cd5ca6be71fdcfd5c5"
+ ]
+ ],
+ "prep_messages": [
+ "1b2dc3cedc43f65731985f19081f490a"
+ ],
+ "prep_shares": [
+ [
+ "cd5978e237aafb0552d6f2614be379176c256bd1bb2d3fa71ec64fcf5e64b6baf5c530e6c828d5be1468539c16917e08f6cc5d754b81f6ea05ed0747377a2dbb5a731ed05a41704a11aea67a37c668810c7fbee6ef543f6a757ffa07f22a6fdc6c37173af38746dcd7ef1f2cb0f555d13b999f3ef6a282b6649c29878349c501711da5ad2a4ac3de6fccb15c803f918a",
+ "87cd13bcc0f7bb62542f40b8a480db80fca16e26264525b236a3664c792009277d9133d4ff0df494d18758677dbea683d9be082297301d1db87b6a345f74f07a3e268fd6e440eec02b3d4109b30d9c680c18d29df84586f30d30a2cf2419471d2b45845e9a4ba9f1c835ef577bcfa710e9d907592e678fa3a225e115cac914fde07e503edb901812725c6f25d7585fb2",
+ "add87361075e48973dfacce50f9caa67077de5a0a3d6e85b8b04772423132387fb2732f839d0de182c65e61553e08af6fa237248acc8e6cfad227ed43c8eed56bd3c1ae929a7c2bc1c5b47dfd2d57a56fd8f3a4f2187c7f94ae1dd203aa9e3bc20a53b7ada0b4f545e0c7a8370be163a582fb321c11446cb9f3b65dc2979f432236aba9b84dbe8182bce25a97ad12186"
+ ]
+ ],
+ "public_share": "711da5ad2a4ac3de6fccb15c803f918ae07e503edb901812725c6f25d7585fb2236aba9b84dbe8182bce25a97ad12186",
+ "rand": "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f"
+ }
+ ],
+ "shares": 3,
+ "verify_key": "000102030405060708090a0b0c0d0e0f"
+}
diff --git a/third_party/rust/prio/src/vdaf/test_vec/08/Prio3SumVec_0.json b/third_party/rust/prio/src/vdaf/test_vec/08/Prio3SumVec_0.json
new file mode 100644
index 0000000000..f18f47d506
--- /dev/null
+++ b/third_party/rust/prio/src/vdaf/test_vec/08/Prio3SumVec_0.json
@@ -0,0 +1,194 @@
+{
+ "agg_param": null,
+ "agg_result": [
+ 256,
+ 257,
+ 258,
+ 259,
+ 260,
+ 261,
+ 262,
+ 263,
+ 264,
+ 265
+ ],
+ "agg_shares": [
+ "b43a2f79240602a73fafe498f4596524e2d16ccd2a68978aa0fc3b08cb757afa0e634bcf86a6f9f6066716d8d6ff6fc5d8323c1f04aa8b08948ef2e9e7a7a10e3be55e452c536f004da7d3502d93f9ef835b59067c8de2bec68afff55e15d4923cdab73e57ea28b90b70d15dc110dac2ab8c34f509842b025606222ee32ce920b14cc3ccabdfc4f1f743b9ef3ca0c2b5bd715085b0d76c95daeecfad16278bb6",
+ "4dc6d086dbf9fd58a4501b670ba69adb202f9332d59768754303c4f7348a8505f59db43079590609dd98e9272900903a2ccec3e0fb5574f74f710d1618585ef1ca1ba1bad3ac90ff96582cafd26c061083a5a6f983721d411d75000aa1ea2b6dcb2648c1a815d746d88f2ea23eef253d5d74cb0af67bd4fd8df9ddd11cd316df58b43c3354203b0eecbb4610c35f3d4a4d8faf7a4f28936a09113052e9d87449"
+ ],
+ "bits": 8,
+ "chunk_length": 9,
+ "length": 10,
+ "prep": [
+ {
+ "input_shares": [
+ "43118698b73a59751812aa20a73ae412766ef3c4c7559adaf4f08d6d73fbe01849ac4f0da41a26f10b1709d08f56da39953a74ee5cca941b880a5857b143cdeb7065b4b8f6b13b474040cd9e5307fd42850c79e49dc4808a8bf2d976223522179142c2cce38fce9218a371029ac88597283e246464233e9d7cf7048bbe3d18d369dfb8d462dddbe94e33f7ebc07bf0cbe8ecf9e42a156f1fd2b6c434eb62813c0929e78c86cf9bcfad5d54287598c986364fcb6fbbfa0db79dc0f4c1dbaebed54201c88b9e1f93a7fcabc0137d2b6c8ec6f423d7aeeced8f7dbd4c64e7ed595b6e5d76034a16c5686a8982397ef1e882232a95e11e7377d5b758015b716472c4dfaa9021bf2f861e18507f7f8435b55a4a3c8f7357e245596c08975169be3fdf4f2bc8600e680b9013f52b67000959ce3a588caaabdedb7d6201210902695051d808571846039dc672be3d2a7d2d25137baf47f5b71d1d907c9db4d3c20045cb32bdcf9c0094bce467da04ed90e885c9e0765a41d98cc0cc454d1d97efe2255eed21c3b2297d9d0717f8d46d1a016ab89afabd89620aa6090d21ad7226d173f23cbdd31702582ca06b336d277c4f39903414ab2baddfa578bce3be8ba27d68651d720b8401a4ffc61c999f628cdc71c058767c63f23e8b933add17cd3e50ab8540c9ebf935b2912fa26d68e2cc9289e4f894b8d03a81b8d306cadabb209de35c980d4ceea42abc4a0581b6114c77e4cc66c01be07deb7bdb8db23df5d67398497b30ea78518ff759304b5269502f93848838ba2d3e1737aadbbcbd4cde25689fff7a738df9017a4f2986c8fe8b8ba6b6f87b4dd6ec84876ba076c31039cf59b695313060ca1dfdb288c8924ebcaddddf9d067f2be6033af80313292c03996a39281c78299d8549d12cd8427104783575ec604930ab55e288606fdeb863afbeb9df6a009694c055c34d68e19c19ef3fa851363493cdf197c201958449e57e327b15eb5e25d2d347374a85e4685b432a15f4f768fa0b180f6db9f0af65cbbcb0c137a2e12cbb0aadf81e78244e2b8855634a9d0014005d9c9209381943f019df54769b4452a47ce0f223ae52a4d28d725d97e40b37b250499508838bc8a7ccb133f7a02fbfc91fa1c27685786808ae4a45e08cf841c79f3a61b58ae87005dd4e43920089fc2bc23b8c6ac3aaf2081a14edf30a0299f3094410689ec026a8bf8ba2b1c470583987c30d5d8ca6e7ea605d0c7661dba95beef2f4b94f5306317ecfa60010d6b18c2aebb994a4559fad9f3538ef7eaaf35761f7640b807483793ed8ab3ae20672da387979a8171eb1425700e257a912e645a80739e5d494ba6d419dcd4fec13aa806fcfcc84480d7e0e676916aded6f1cf9d69f7e958dceae1edaa11b2569954b7689e647906cccbdcbc2897f139356d9c85168f08ed8990aefc891158a1b89d7c19d3c56ad2a91d3de46ada48ec6338d13efb16c4cb49acd981a044c335240ce7d1db84fde51058290cae528cc7dc5794daa652268d9e5d0fa639a8549c9fdcd3fd126f653f9b970d804fdd4f420e473a31410fe9a84fc43ae415d008ac86ca0881f737382196cd5b6dd4b8673cb515ef70c4624bea32c22a7b72c2f8e1c2fc693a4905215e10580aef647be4bd36baab91c2867bcec745bc5334ce8cda1a0d77f6bb5f1838c60904f8ba7aec00d2529e87c41702b774c6f11c632d35f477988847de39626fd7e83b07ca2de2d7dbd68d07617dc590e00684c79ff1d8ff484a31056b53b29cbe470c8bf99515d7ad2939120d3b9b9ebabfb29d0e7b77cc7bb5ab97fc44591ee036de0206b8331c99c75e8bcc50ac1cb75fec3fb640318010d3ddeaaf423d14d2d715e7cf81ee4d01ad0c0f09c66b2e0b396b93c2bc97b21a42cdafe748aa4b59c250e4639be7173f4cff260339d2797e402653a3bef19a0a17763395889c4269679f6bd0289a356eaf0f06b409d24d4c112ff8f60b9383669677635f20d8eeed5c38d9500e39dca878f578b4980f374ee556aa3458b551628ff9f110d11b7f2497195d9bf3c9557e6f3d11c05f52158aab8f6485cdecfa158e592453351f1866faed652e75b37562a4c696867a89ed8b55355c82c6b571918d3995cb6516f00742a7f0974f62ca846d1306422176a204627930693eaf08951f082629d0a5537aea1d8729693798896fb16830a7cc7b29737f29637308283d5577ee3ea54987f14e4b1b4a51a17f7426a1ea86b42db1410a05064dd773bb5dacdf49702f7cf3ee9695f82fe881ef34c52e8d46e1e415989a757ec94cdd07294a2290e19749606638ed7ab2138cb9f7769a75b169f02dded1bb93c70095ef01be80b96b0ec21588146c8a238abd2bc14a170c5a024fe683c809ff478def04de33f353111c054ff502e7fad8e768bde39cfe419373b0bd40f1ae943d61b6fb824ac689955567fb7526f05d4db0c32f0e7b76cadb917ce200edfda6065129e19fa38ba3855586913baee0bbbade97144bac9c4763c95278f90bcaaa42fbbbfac31fcba0b8291025dbfd1a3660a60cc97763672331ee7db22c0932f46dfc313e7bd60ee86b7e3b4c11b5daaf8cf3e35fcaa124ae0a05bd063ff4944364ee16326b6131422bf08803aa713c771377f5f47cc940f879b2a1763110c22867c7a704c970163b15f702757d87e6e24a4474865877352ecef45294ef3bb7ec9e45f8609da982a161f89a8a9c2a6cf56fc9e8a2d9396fccf4bdd7b8aaf370f4478cb45bd5773f2a5af3d6149b4e41e364cf87c771848716998b070fe95d1d74c9d77466eae8efe0d5a0435de53d50d562c611ed8a2145c752ea54b31101db21f2688fefac5a3df5fc8163f134e5bcfcfcb2106a642ae3e6bcbd15654f09546ccb8c48d84d3bc7d0a18900dba3d66cb02ec33303132333435363738393a3b3c3d3e3f",
+ "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f"
+ ],
+ "measurement": [
+ 0,
+ 1,
+ 2,
+ 3,
+ 4,
+ 5,
+ 6,
+ 7,
+ 8,
+ 9
+ ],
+ "nonce": "000102030405060708090a0b0c0d0e0f",
+ "out_shares": [
+ [
+ "3c1365280c0256e2bf8fa1dda6c8210c",
+ "4cf0ce9963cd8783355469ad43277e53",
+ "5ccbc3ef2ce2fdfc4422b2f29caa7aec",
+ "f565690aac38d90228da50a3a2e2355a",
+ "c1f6746cb91b25006fe29bc5b9dbfd4f",
+ "2f1e7357292ff6949783aafc745cf130",
+ "c39d92bfc7f862e84f259b7440b04896",
+ "932ebc51032cb90072570bba4b64f80a",
+ "966e96998e4aeca59e1693fabe8aeb91",
+ "9b25702c90f2ce3136faef39b2b783e7"
+ ],
+ [
+ "c5ec9ad7f3fda91d24705e225937def3",
+ "b60f31669c32787caeab9652bcd881ac",
+ "a7343c10d31d02039fdd4d0d63558513",
+ "0f9a96f553c726fdbb25af5c5d1dcaa5",
+ "44098b9346e4daff741d643a462402b0",
+ "d7e18ca8d6d0096b4c7c55038ba30ecf",
+ "44626d4038079d1794da648bbf4fb769",
+ "75d143aefcd346ff71a8f445b49b07f5",
+ "7391696671b5135a45e96c054175146e",
+ "6fda8fd36f0d31cead0510c64d487c18"
+ ]
+ ],
+ "prep_messages": [
+ "faa44093d924dc5a7a7964fd9c8ec82b"
+ ],
+ "prep_shares": [
+ [
+ "f9ab3aa30354eb87abdd838ca558b6cbf26345360ccb2dea7deffb9e075c54b422f03470466c54abee94d25dd57eff3a073bf64fcf5eb3d7334b815115b39e6b16ea9cd0bd90f550dd701f3bf288451f17d4c7a3adc44ef5ad49663dfa2e95250320cb7d3fa0323ddcddcdb0d628146f48f6b53badd73c5333fe30cefbca3badd9a688c628f9df7129d7283772dfa0cc630e06a2795703ee70e9a01f64d3a704df997b7b6de7335aedbab9b3a1932989f93e66bb51c72416fc7f1c54bdf6f15d04c07dd5c8c2d5abea0921c5047299cd82f633af0f04fbde479b82628f0e446e781cca6b0548eaa34d8d1e5279078afe906905aa91922bf69977a92b586541d02a80245334e5321901ea62181f121f7aaaaf89061b36b0f9eb5c9ca22ddb5d09bca32696a262178178745830d0c0dee8fcc9033f8f5c98e5f3eaa91fded998019c068644495dcc3fad1eb4b63821a23b",
+ "0854c55cfcab147838227c735aa7493430369af6251b129c24fca111dc13d34678b16bc625356621f29ea8e47b665ab509578cae546f46e04b013376fc8439d5cde2eb50a36d1303c487fd8456539db6e653b588217b6b273b7b3d79de062a76332662a738cb172c781306cffa8b46f9aceaaf6b663a749763c9db91c5ebb62dd0f94a3d036b82c41b49709fe6c3815e215adf1c2ae55fd9d90f8186c07c37af26d2e0803bbda031317b76cdbcc7b6817529c92ef23b00db2243ffd4767f7c8e9d39781324cef39ddf613e24e4a6351037d62b77ff946d119fb2da47fd757e16d34aa0c53bd7d6fb53472d84ca55f554638e2529702522faa8c177d51394a89bbd4cec850ee6ff565296aad4f2cd6b9f35ad7ff7b7b494b97248e3a894dce393259fa038f067fb28655b6e18edc9a032053e900a2e3d07f7ca52461922710f91f4ec2449a30929eb714d75d9db74f3a7"
+ ]
+ ],
+ "public_share": "9c068644495dcc3fad1eb4b63821a23bf4ec2449a30929eb714d75d9db74f3a7",
+ "rand": "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f"
+ },
+ {
+ "input_shares": [
+ "44118698b73a59751812aa20a73ae412766ef3c4c7559adaf4f08d6d73fbe01849ac4f0da41a26f10b1709d08f56da39953a74ee5cca941b880a5857b143cdeb7065b4b8f6b13b474040cd9e5307fd42850c79e49dc4808a8bf2d976223522179142c2cce38fce9218a371029ac88597283e246464233e9d7cf7048bbe3d18d369dfb8d462dddbe94e33f7ebc07bf0cbe8ecf9e42a156f1fd2b6c434eb62813c0929e78c86cf9bcfad5d54287598c986364fcb6fbbfa0db79dc0f4c1dbaebed54201c88b9e1f93a7fcabc0137d2b6c8ec6f423d7aeeced8f7dbd4c64e7ed595b6e5d76034a16c5686a8982397ef1e882232a95e11e7377d5b758015b716472c4e0aa9021bf2f861e18507f7f8435b55a493c8f7357e245596c08975169be3fdf4f2bc8600e680b9013f52b67000959ce3a588caaabdedb7d6201210902695051d808571846039dc672be3d2a7d2d25137baf47f5b71d1d907c9db4d3c20045cb32bdcf9c0094bce467da04ed90e885c9e0765a41d98cc0cc454d1d97efe2255eed21c3b2297d9d0717f8d46d1a016ab899fabd89620aa6090d21ad7226d173f23cbdd31702582ca06b336d277c4f39903414ab2baddfa578bce3be8ba27d68651d720b8401a4ffc61c999f628cdc71c058767c63f23e8b933add17cd3e50ab8540c9ebf935b2912fa26d68e2cc9289e4f894b8d03a81b8d306cadabb209de35c990d4ceea42abc4a0581b6114c77e4cc66c01be07deb7bdb8db23df5d67398497a30ea78518ff759304b5269502f93848838ba2d3e1737aadbbcbd4cde25689fff7a738df9017a4f2986c8fe8b8ba6b6f87b4dd6ec84876ba076c31039cf59b695313060ca1dfdb288c8924ebcaddddf9d067f2be6033af80313292c03996a39281c78299d8549d12cd8427104783575ec604930ab55e288606fdeb863afbeb9de6a009694c055c34d68e19c19ef3fa851363493cdf197c201958449e57e327b15eb5e25d2d347374a85e4685b432a15f4f768fa0b180f6db9f0af65cbbcb0c137a2e12cbb0aadf81e78244e2b8855634a9d0014005d9c9209381943f019df54779b4452a47ce0f223ae52a4d28d725d96e40b37b250499508838bc8a7ccb133f6a02fbfc91fa1c27685786808ae4a45e08cf841c79f3a61b58ae87005dd4e43920089fc2bc23b8c6ac3aaf2081a14edf30a0299f3094410689ec026a8bf8ba2b1c470583987c30d5d8ca6e7ea605d0c7661dba95beef2f4b94f5306317ecfa60010d6b18c2aebb994a4559fad9f3538ee7eaaf35761f7640b807483793ed8ab39e20672da387979a8171eb1425700e257a912e645a80739e5d494ba6d419dcd4fec13aa806fcfcc84480d7e0e676916aded6f1cf9d69f7e958dceae1edaa11b2569954b7689e647906cccbdcbc2897f139356d9c85168f08ed8990aefc891158b1b89d7c19d3c56ad2a91d3de46ada48ec6338d13efb16c4cb49acd981a044c335240ce7d1db84fde51058290cae528cb7dc5794daa652268d9e5d0fa639a8549c9fdcd3fd126f653f9b970d804fdd4f420e473a31410fe9a84fc43ae415d008ac86ca0881f737382196cd5b6dd4b8673cb515ef70c4624bea32c22a7b72c2f8e1c2fc693a4905215e10580aef647be4bd36baab91c2867bcec745bc5334ce8cda1a0d77f6bb5f1838c60904f8ba7aebf0d2529e87c41702b774c6f11c632d35f477988847de39626fd7e83b07ca2de2d7dbd68d07617dc590e00684c79ff1d8ff484a31056b53b29cbe470c8bf99515d7ad2939120d3b9b9ebabfb29d0e7b77cc7bb5ab97fc44591ee036de0206b8331c99c75e8bcc50ac1cb75fec3fb640318010d3ddeaaf423d14d2d715e7cf81ee4d01ad0c0f09c66b2e0b396b93c2bc97b21a42cdafe748aa4b59c250e4639be7173f4cff260339d2797e402653a3bef19a0a17763395889c4269679f6bd0289a356eaf0f06b409d24d4c112ff8f60b9383669677635f20d8eeed5c38d9500e39dca878f578b4980f374ee556aa3458b551628ff9f110d11b7f2497195d9bf3c9557e6f3d11c05f52158aab8f6485cdecfa158e592453351f1866faed652e75b37562a4c696867a89ed8b55355c82c6b571918d3995cb6516f00742a7f0974f62ca846d1306422176a204627930693eaf08951f082629d0a5537aea1d8729693798896fb16830a7cc7b29737f296373045c4b3272022ca8eba72c601043d08da35f439bc7d0100d6aeb7c2a7cb74a82c9abf8982362807bed855c50ebe0e571d2624f06387b4439e7580af40033dccb657fea66e721e9b2c20cdd3dba93c3261c4ec327a89ed4007b7393820f46a60ace5876392117b97b9a358a1286944bcf0e7cf4f471d46694dc37fc670aee1d4cd7fa002020f5c7ea0bc65d0ca4e42729107abeab7a2f7b86d9f663a73485f54c4870609a0789554bd2f623176f563b8d577965464bc1d7ecca70103d13c963f741f6981cb1d83a7eb09878d39d5ec7e007d390fd93c9dba87670e981d6e21069f72602526625fd88a5cafc400b01720fccc97763672331ee7db22c0932f46dfc351a6df904c48d8a976ce693f58706d7f16ffb3c0ea860cc818c14c42c925832c041c075fd291ba417723cb6e68e5deea5716298370a7c6aae23beb7276354591e9c084351aa1ddb79d9067319c93931e5018cc62705ac5dd58f1a8b7439bf4bcff7192ee243138bc26a9a2c42eb57859751a58f04f4f83b4b673254700571cdcb66a38b1187b425df9e234484fa168dd01ab675fb38b167ec06b6b7878311fcf2f20ca9aee115b9d683375ce1dc64f98d93136680c056af071501b2b50ea4b267cab3e117c157683ba9f7a10069efa0afab0ed9ec6444ddf16d5e834834fe2e0dbd0df92d6b6c19697673837bf51d697303132333435363738393a3b3c3d3e3f",
+ "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f"
+ ],
+ "measurement": [
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1
+ ],
+ "nonce": "000102030405060708090a0b0c0d0e0f",
+ "out_shares": [
+ [
+ "3d1365280c0256e2bf8fa1dda6c8210c",
+ "4cf0ce9963cd8783355469ad43277e53",
+ "5bcbc3ef2ce2fdfc4422b2f29caa7aec",
+ "f365690aac38d90228da50a3a2e2355a",
+ "bef6746cb91b25006fe29bc5b9dbfd4f",
+ "2b1e7357292ff6949783aafc745cf130",
+ "be9d92bfc7f862e84f259b7440b04896",
+ "8d2ebc51032cb90072570bba4b64f80a",
+ "8f6e96998e4aeca59e1693fabe8aeb91",
+ "9325702c90f2ce3136faef39b2b783e7"
+ ],
+ [
+ "c5ec9ad7f3fda91d24705e225937def3",
+ "b60f31669c32787caeab9652bcd881ac",
+ "a7343c10d31d02039fdd4d0d63558513",
+ "0f9a96f553c726fdbb25af5c5d1dcaa5",
+ "44098b9346e4daff741d643a462402b0",
+ "d7e18ca8d6d0096b4c7c55038ba30ecf",
+ "44626d4038079d1794da648bbf4fb769",
+ "75d143aefcd346ff71a8f445b49b07f5",
+ "7391696671b5135a45e96c054175146e",
+ "6fda8fd36f0d31cead0510c64d487c18"
+ ]
+ ],
+ "prep_messages": [
+ "22b05b9abf6f7798c91fb089ec73d79c"
+ ],
+ "prep_shares": [
+ [
+ "f9ab3aa30354eb87abdd838ca558b6cba06d3c978291ea82c4c856026ce4a3cb3dec40f98bf1cf3db33e3a736043891abbb4629ed714cfb72b9a70be2083cc84c41c02e448c46154ed923d78db089e67c7bbe0ef236ecd77f99c8d5e5272f4aa0320cb7d3fa0323ddcddcdb0d628146f3a94850ce63a023fa1ec776f6082d00e5fef53097f1b9a562fe9c3c4b1d9b03a87131642b49c990eb174e205bf6d68af4248001090e9ee0c2c52614d1778ac60eaf3003e3714c6ef5c99442ad527fb434fea0dce4d6fe6cd3de25237bf75d34a3b619efbec942fe7f466c96521a9672a1b8773d0a3c0009b8020cc9719ddae7aee79d2a751e4405c17493fb96c28b9dfd90c135f76582ed5f72b0867cf2276d0aee16e5c44d6ac86eff63369b58b79fd5f34e68b4406f78664224591044c64f776d62683c1ad354cfd588c2168df20c6374a2b13433b05ee12db5fdd45070eac",
+ "0854c55cfcab147838227c735aa74934a0198736b579cfe4f87a1ab05d6cecc278b16bc625356621f29ea8e47b665ab59a91a8a0b72799489818a54757992f45cde2eb50a36d1303c487fd8456539db688dec5f51c76fdade09bf05bb59d8f82332662a738cb172c781306cffa8b46f986b9544adb196632fd3464f73faa14d8d0f94a3d036b82c41b49709fe6c3815ee39a9e9f46241986e33eb72c43757e3d26d2e0803bbda031317b76cdbcc7b681efe9a68224da578206e4518bbd64e9b69d39781324cef39ddf613e24e4a6351009ef3a1ca5f6d5b556077ed9c6e12b98d34aa0c53bd7d6fb53472d84ca55f554bff591feeca2f8c458b72bc0dd4a9dc4bd4cec850ee6ff565296aad4f2cd6b9fe2ca244753a83522e0d4496a1c66cdb8259fa038f067fb28655b6e18edc9a032053e900a2e3d07f7ca52461922710f91f4ec2449a30929eb714d75d9db74f3a7"
+ ]
+ ],
+ "public_share": "374a2b13433b05ee12db5fdd45070eacf4ec2449a30929eb714d75d9db74f3a7",
+ "rand": "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f"
+ },
+ {
+ "input_shares": [
+ "44118698b73a59751812aa20a73ae412776ef3c4c7559adaf4f08d6d73fbe0184aac4f0da41a26f10b1709d08f56da39963a74ee5cca941b880a5857b143cdeb7165b4b8f6b13b474040cd9e5307fd42860c79e49dc4808a8bf2d976223522179242c2cce38fce9218a371029ac88597293e246464233e9d7cf7048bbe3d18d369dfb8d462dddbe94e33f7ebc07bf0cbe9ecf9e42a156f1fd2b6c434eb62813c0a29e78c86cf9bcfad5d54287598c986374fcb6fbbfa0db79dc0f4c1dbaebed54301c88b9e1f93a7fcabc0137d2b6c8ec7f423d7aeeced8f7dbd4c64e7ed595b6f5d76034a16c5686a8982397ef1e882242a95e11e7377d5b758015b716472c4e0aa9021bf2f861e18507f7f8435b55a4a3c8f7357e245596c08975169be3fdf502bc8600e680b9013f52b67000959ce3b588caaabdedb7d6201210902695051d908571846039dc672be3d2a7d2d25137caf47f5b71d1d907c9db4d3c20045cb33bdcf9c0094bce467da04ed90e885c9e1765a41d98cc0cc454d1d97efe2255eed21c3b2297d9d0717f8d46d1a016ab89afabd89620aa6090d21ad7226d173f23dbdd31702582ca06b336d277c4f39903514ab2baddfa578bce3be8ba27d68651e720b8401a4ffc61c999f628cdc71c059767c63f23e8b933add17cd3e50ab8541c9ebf935b2912fa26d68e2cc9289e4f994b8d03a81b8d306cadabb209de35c990d4ceea42abc4a0581b6114c77e4cc67c01be07deb7bdb8db23df5d67398497b30ea78518ff759304b5269502f93848938ba2d3e1737aadbbcbd4cde25689f007b738df9017a4f2986c8fe8b8ba6b6f97b4dd6ec84876ba076c31039cf59b696313060ca1dfdb288c8924ebcaddddf9e067f2be6033af80313292c03996a39281c78299d8549d12cd8427104783575ed604930ab55e288606fdeb863afbeb9df6a009694c055c34d68e19c19ef3fa852363493cdf197c201958449e57e327b16eb5e25d2d347374a85e4685b432a15f5f768fa0b180f6db9f0af65cbbcb0c138a2e12cbb0aadf81e78244e2b8855634b9d0014005d9c9209381943f019df54779b4452a47ce0f223ae52a4d28d725d97e40b37b250499508838bc8a7ccb133f7a02fbfc91fa1c27685786808ae4a45e18cf841c79f3a61b58ae87005dd4e43930089fc2bc23b8c6ac3aaf2081a14edf40a0299f3094410689ec026a8bf8ba2b2c470583987c30d5d8ca6e7ea605d0c7761dba95beef2f4b94f5306317ecfa60010d6b18c2aebb994a4559fad9f3538ef7eaaf35761f7640b807483793ed8ab3ae20672da387979a8171eb1425700e258a912e645a80739e5d494ba6d419dcd50ec13aa806fcfcc84480d7e0e676916aeed6f1cf9d69f7e958dceae1edaa11b2669954b7689e647906cccbdcbc2897f149356d9c85168f08ed8990aefc891158b1b89d7c19d3c56ad2a91d3de46ada48fc6338d13efb16c4cb49acd981a044c345240ce7d1db84fde51058290cae528cc7dc5794daa652268d9e5d0fa639a854ac9fdcd3fd126f653f9b970d804fdd4f520e473a31410fe9a84fc43ae415d008bc86ca0881f737382196cd5b6dd4b8674cb515ef70c4624bea32c22a7b72c2f8e1c2fc693a4905215e10580aef647be4cd36baab91c2867bcec745bc5334ce8cea1a0d77f6bb5f1838c60904f8ba7aec00d2529e87c41702b774c6f11c632d360477988847de39626fd7e83b07ca2de2e7dbd68d07617dc590e00684c79ff1d90f484a31056b53b29cbe470c8bf99515e7ad2939120d3b9b9ebabfb29d0e7b77cc7bb5ab97fc44591ee036de0206b8331c99c75e8bcc50ac1cb75fec3fb640318010d3ddeaaf423d14d2d715e7cf81ee4d01ad0c0f09c66b2e0b396b93c2bc97b21a42cdafe748aa4b59c250e4639be7173f4cff260339d2797e402653a3bef19a0a17763395889c4269679f6bd0289a356eaf0f06b409d24d4c112ff8f60b9383669677635f20d8eeed5c38d9500e39dca878f578b4980f374ee556aa3458b551628ff9f110d11b7f2497195d9bf3c9557e6f3d11c05f52158aab8f6485cdecfa158e592453351f1866faed652e75b37562a4c696867a89ed8b55355c82c6b571918d3995cb6516f00742a7f0974f62ca846d1306422176a204627930693eaf08951f082629d0a5537aea1d8729693798896fb16830a7cc7b29737f29637303d4b2d335a15f1c48ed11d7948cae1b1efcb5af7c398f535e799f58a13109605cc3afae7e08683e40b1d015cfb8de1f5ca44d2eaa0fbfa549b4aa3933de82380b81ddd451d5e44a8f7f456355dfa125c002c8c5e7b2697e33dbd5cc1ac7ac8bbdfcb08ed49999a24a72685a31cdc25e0c9a27be6eb32af2d260f6d60427108a552cbe2a99ad070aec066c78bbf260e49e7ead7646ddd80d2fd067e7361e83e23aa3df8810cb4a44ee4b1205ecc8c548c064345134bb02e081a65ade1d3ec4523448d81153fa692e852e443120c8aba426dbc11bcef30ab6de561000c5be09b10524cedfab2395b99861a6f0c7e9c820dcc97763672331ee7db22c0932f46dfc3591f66851255b173a26f12c813e393a75c279385a4ef1668e0de195f818a9553d2a096f927333e1b445c8f212b665412b3f546fc56600ff4bc71f71f3c8aedc788a14e5e6f61343cc668e4d7e8d5b22314d9727e7e216f01d26d84168b8b8cad052eed93ec12355123dbbe497b1d0f6a92472c5181623dd46fe47e576cc7e804e23f58098d06504f11e23d87debccc25206b7ab2e8a54e197ecb27785fa834700ce9dab85af30a0cb4e385e6469db3e14a8545b97d72b9b4ffec701ab993457758873ec75af28a865542c437cf00bfc8092eebbb13b15cf9b481804696904c6ffae417be85dc3e8889fc8d2bf1cc7386303132333435363738393a3b3c3d3e3f",
+ "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f"
+ ],
+ "measurement": [
+ 255,
+ 255,
+ 255,
+ 255,
+ 255,
+ 255,
+ 255,
+ 255,
+ 255,
+ 255
+ ],
+ "nonce": "000102030405060708090a0b0c0d0e0f",
+ "out_shares": [
+ [
+ "3b1465280c0256e2bf8fa1dda6c8210c",
+ "4af1ce9963cd8783355469ad43277e53",
+ "59ccc3ef2ce2fdfc4422b2f29caa7aec",
+ "f166690aac38d90228da50a3a2e2355a",
+ "bcf7746cb91b25006fe29bc5b9dbfd4f",
+ "291f7357292ff6949783aafc745cf130",
+ "bc9e92bfc7f862e84f259b7440b04896",
+ "8b2fbc51032cb90072570bba4b64f80a",
+ "8d6f96998e4aeca59e1693fabe8aeb91",
+ "9126702c90f2ce3136faef39b2b783e7"
+ ],
+ [
+ "c5ec9ad7f3fda91d24705e225937def3",
+ "b60f31669c32787caeab9652bcd881ac",
+ "a7343c10d31d02039fdd4d0d63558513",
+ "0f9a96f553c726fdbb25af5c5d1dcaa5",
+ "44098b9346e4daff741d643a462402b0",
+ "d7e18ca8d6d0096b4c7c55038ba30ecf",
+ "44626d4038079d1794da648bbf4fb769",
+ "75d143aefcd346ff71a8f445b49b07f5",
+ "7391696671b5135a45e96c054175146e",
+ "6fda8fd36f0d31cead0510c64d487c18"
+ ]
+ ],
+ "prep_messages": [
+ "4b28ca5fab189f5689d02be161fe25af"
+ ],
+ "prep_shares": [
+ [
+ "f9ab3aa30354eb87abdd838ca558b6cb4cd1280dfc7d2f12bcb14c5a38a5fa1e4225a50845bc43cc7276668331627f53e6d1debec49fc79a6e0a2382b73e01d1af45275c3e553e9f0df2dce1fb8adf9b7cc9862e001ad0d0059d27c68b40e998a4233df802cb98ef8c94504a86e9b0e423e0661acc82059937329f34832d079f0184e04d6aafecf62dee814f748123de797d05203e140ccc9be383de282e7d377e0e3400af264e528f66cc39c14f6b590939d50e82fe5df4fa1e0aa96c27af32a5540a1ab456284c050fdf4fc7190c71acfc9d952d03d4af955b8df3f10fc64b48f1399d22792b7b18e64c7c09d986b27c4874ee16fff4ecde9d89391d3ca98a14f95ce098c05629305bb26e0db0955be0bafa82ff2a6b48283de372c395862a636d4a9bfdd06a15405a71a1d56a5a30afa2bde6fc55d8a3386fe4bd3c08985014376e4adc53e094949d34b36f1e8b16",
+ "0854c55cfcab147838227c735aa7493459da23320d129aafa331318931d85cdd78b16bc625356621f29ea8e47b665ab5d29caacc5ba36200516852c360c0a2d9cde2eb50a36d1303c487fd8456539db613567966c72ef1b9f8b8f2e93aebdc1c332662a738cb172c781306cffa8b46f908c1bfd01acb45c5c06c9ecb16265a3fd0f94a3d036b82c41b49709fe6c3815e1af0509da314c9297ca795e4487c9cc326d2e0803bbda031317b76cdbcc7b6819dd6910f3002a99c7075366ab035710a9d39781324cef39ddf613e24e4a635108fbc5c1b9dada07dd81a620426914410d34aa0c53bd7d6fb53472d84ca55f554883acb353f6718ee88b8e595fe5b9373bd4cec850ee6ff565296aad4f2cd6b9f2bdf8fd9fae82be3d2039778cad3aa16259fa038f067fb28655b6e18edc9a032053e900a2e3d07f7ca52461922710f91f4ec2449a30929eb714d75d9db74f3a7"
+ ]
+ ],
+ "public_share": "14376e4adc53e094949d34b36f1e8b16f4ec2449a30929eb714d75d9db74f3a7",
+ "rand": "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f"
+ }
+ ],
+ "shares": 2,
+ "verify_key": "000102030405060708090a0b0c0d0e0f"
+}
diff --git a/third_party/rust/prio/src/vdaf/test_vec/08/Prio3SumVec_1.json b/third_party/rust/prio/src/vdaf/test_vec/08/Prio3SumVec_1.json
new file mode 100644
index 0000000000..21fcfa001b
--- /dev/null
+++ b/third_party/rust/prio/src/vdaf/test_vec/08/Prio3SumVec_1.json
@@ -0,0 +1,146 @@
+{
+ "agg_param": null,
+ "agg_result": [
+ 45328,
+ 76286,
+ 26980
+ ],
+ "agg_shares": [
+ "447fb76d69adab4dc1990d2289325675e67772e564baab6396c6b45c58a1c5febe9c72ab66aab2aab4b588ff774cb480",
+ "47e6ff190ecf95c1c1941e2b03db246104c982f459555c7d30035b353f18e8985d9e4661cd30031dc481a1afdc0df13b",
+ "864b49788883bef060d1d3b273f2842916e90b2641f0f71e0136f06d684652684a2e47f3cb244a386bc8d550aba55a43"
+ ],
+ "bits": 16,
+ "chunk_length": 7,
+ "length": 3,
+ "prep": [
+ {
+ "input_shares": [
+ "5d82bd1f81516122465f8a60a3209afef5a5c181fdfd80d20d280edb0ae8ccc4953eff5c0efe473d411cf4f3b2e3fd320c83c6b8f2c626a42d25f89594365561966e130ecf8a778e42ce7cca37b919eb9304560ba6a60a5e5b523f5ad397b378edff4b21af66fba2f59db74e46ffdfa077bcea50472d6e771640a71fa31dd96446a2d8ce308904ea0d94760e7f8721d1531754521de6b338a20bdc8eda1d1acb6f3407a9f6f9d6cf9ccc3696c4d3226e89cf3207643a12d8c30332a8d364c97aaee81f4dc31ad62d49506e422e146492bd92a5cc933532fbfc1ee2e8e33116414358edd4baf633cdd80856f8132124171d9a2d989d3a9cf5d1d2b27baf94a5c523cf7ae624b8fe1c8ffc2229bbeecfc18e91c8683df7c579390d8b31ca87372cb5ebbe716d0edc0fe8f10c54835396a68cbacc670eee07dffa3203f8b202dc414ccb317950b35d8f4da3f0bafe8f4b0d09b5103494ed9cf9075bfd19c47f8bdee607eccea1987b4bf6ba603e29043ef636b1b327e57adf1b29b098d4eadfebb737a5ea3558794f02b97f3611034adf002518d85e769210bb2ed2e4b4390433c55d6140ffda97a5018ee007adf5125f079bebdb6eba6c35d0504d8b7a9cbbf0bd9d57bd5b563fdc052a492a7dad4a3c782b69b711ac2969758cffc3d9089a34716517c45fbb164a6bd15a001d454dfd444becef4c4a7fdbc1aaf3b7e0983b900222674a726db2b1b155190cec29c6afefe3841924dd7b212437fb10bffc8a17cea09a97ec2dfafe897e8ad4c5418946525e0908ac8790580a47a17a8089e7b78498f2a54375778e387b0985293431e2103f51600211e6e9a3f388e53d2df072d486d4c4838d8d8601fad2bd86d51ad3a58aebc0d8f6bac048d77968b26826cf545b44f7513667ac696564df8113529415a6e467d3a9f6bda8630717be753a45b5d688bbc4b95712f3bec044eb26db66f23861bf870cfb30347361e81a451f7f17642f6cbd902e92cc063b7cd4cdffbec78cb3f1957d650f89be7798894f6594ae1965964b5968c67003b247c0e83d3cef1ba2feef4c5c59d42a3efa8309f0ec4e9497b1c5a7c6b72f341d4ce5950bd12be5b6b22f32eade71f969f4ee1c0a864741fb2b5b1ad278c5f2f27000e4237b71cc664a87c50a7088b36bab5ad5a5494d599407fda9df6c538ad53563c222d3242b635116f5246b9dd6b7aba1f5abda8fd607ba18a3155c6e6c877ba0965f4005c8f475e5116bd7f899ba48ad299e5007401e49b85abf0ad681cbad302393975d682f6fb5a0795702ada0cf559198efff5ed8a16b12d1e866545db67d13ea5b7e59557776d458f5872d20ab0a3f6c74d61345bb6cd1f2dec5ee4a8d1c96d22a7b3c8ef21c1284d0785a56143100639cbfc12d1a6582b16b4bf804f6503665f275e5de6c60aac82324be975fedb2dd651c1173635fde95660cc844d347d10f8a24586a75597b1c39e828063364e13921665af885b721addc72a72d9a23bb6aa7aa3169804cf944d523d855c97a71d723b464e3976d1264bef3c266ff630ac23753eb79ad90eb5593ce456db34e977dbb19cfb58c52cbaf4826858368c3cbd8863abb5b2b95c36a447b8a4eef73e276d8bc61be6a420a12dd507bc72ef767bf49ddc9a7dcf61290b191ca4c1444e4863f1438e480a661f860c6868256aa7390e1a5033292afdcb6da8c464298c1cf5bc86bac0ad5ee5f72219e33a356a4cc3bdefd606162636465666768696a6b6c6d6e6f",
+ "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f",
+ "303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f"
+ ],
+ "measurement": [
+ 10000,
+ 32000,
+ 9
+ ],
+ "nonce": "000102030405060708090a0b0c0d0e0f",
+ "out_shares": [
+ [
+ "22c1e77978e4e319838804b62d66c7d1",
+ "4eecd0a1213e3921caece61ec83597ff",
+ "27112639228e3b8e913cd8ff27c4e62a"
+ ],
+ [
+ "18a2aa085a9adc958c310ab9abf3b675",
+ "0243d6a6c871c929a8ab73bcbfb2a2dd",
+ "75df6c20efbaab098480e08f49afa5be"
+ ],
+ [
+ "d8c36d7d2d813f50b845f19026a681b8",
+ "b24d59b71550fdb45567a5247817c622",
+ "6e0f6da6eeb61868ce4247708e8c7316"
+ ]
+ ],
+ "prep_messages": [
+ "065f5893e9afb58b358f78e7ed2cc07c"
+ ],
+ "prep_shares": [
+ [
+ "fedaa3d68353f75a2db6a1e49b2397a2bed007840b0f6ccc5ff3d89835264b58afa1771f5d2a277b65bbc2190fcac717b4f07c6d7ac4c692ad519e8a33e6d22479dfdaa6e2d3eb787ff4c9cc9deb4638b69a422203daec5a3a9b28f4eaddda1eef0000c41066465d05570989f605ad679d3d6906a8eba159f5af3995de50bdd1068ba7c0556bbd0724ada90ce58efc5b7c24f02cbc919cdb90bd915098f1f7b4bbc85c69e091f780fd70df4abb883070d02d2e06f76874cd4496526ce4aad58adf2b97e7cfed76951b532ebde9a3518e407992b67cbc6f3ccef64065bc5c214973167fea3f7baea5bf44bc32b85e37fb1f12524e4f720b7d10547ea1b558c569220ea8f5008a9be1e061606e347c3c49",
+ "cb8307fb467bb023448e58c74d159bf4ed77785c059b1bfe3c5b36ab3bb46cc6051853dd2151e2cc480d5164567c8c41df857ef182519ceaf1c704a25e6c948712d4839078fa72b1e64e8531f3e54c090d01fcc6023c8dc28300ceb5fd722c80211848dd2c787bd764b2099de3139df3e7472bf3c98fc31f1d3e09b8deaada8bb19f2941d9f4660018a051ede752680aa6d05e91c0c2feb5199be821f7eba9e3abe594acb8e9611a81294b8ed708fa93caa4f00ab2df5a298a09a7d71924a9ea0b98b57a0d21fda8ff765c0394041a9a2fce409f56e24f387aba5eec7bb507d18f623f5f376d80e762ee64ef3db152a4eaa42964a69f705f15eb77df0cf6f81589a8eaa4f01fe1b5aa656a0919ae5449",
+ "39a1542e3531588156bb055416c7cd68c32c28a3ac4eed2bb0f0460d41e3634bc0746eb13013792fcc318698a96b1343b152abb747abd3245a70d95eaf31f330e9e844395897d8d5f475d4644149864ca15c31da48dce96e593075a17d4deff6ae67d137adc6f38ec943c596b6fec177e66c119988225c82ac239141c8448add3f9b5c6e59d9736159ede439854b0532d9253f45dd09cb6b800fab1308b1f265978eab94b6bf4105729f7da8eddcee387a2a1eac1c64418e342368a3478fa335500371d0434c5e6511da60302f9947e84a52c49e6dc731f79ca0543441bff7a4cd909fe76206570074fca8dd8cc511ed104a88289bd3cd4d9e34a6c9a50a03649a431dd8df92d78dd6c0d478dd93c0cb"
+ ]
+ ],
+ "public_share": "220ea8f5008a9be1e061606e347c3c4989a8eaa4f01fe1b5aa656a0919ae54499a431dd8df92d78dd6c0d478dd93c0cb",
+ "rand": "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f"
+ },
+ {
+ "input_shares": [
+ "5d82bd1f81516122465f8a60a3209afef6a5c181fdfd80d20d280edb0ae8ccc4963eff5c0efe473d411cf4f3b2e3fd320d83c6b8f2c626a42d25f89594365561956e130ecf8a778e42ce7cca37b919eb9304560ba6a60a5e5b523f5ad397b378edff4b21af66fba2f59db74e46ffdfa078bcea50472d6e771640a71fa31dd96446a2d8ce308904ea0d94760e7f8721d1531754521de6b338a20bdc8eda1d1acb6e3407a9f6f9d6cf9ccc3696c4d3226e8acf3207643a12d8c30332a8d364c97aaee81f4dc31ad62d49506e422e146492bc92a5cc933532fbfc1ee2e8e33116414458edd4baf633cdd80856f8132124171d9a2d989d3a9cf5d1d2b27baf94a5c524cf7ae624b8fe1c8ffc2229bbeecfc18f91c8683df7c579390d8b31ca87372cb6ebbe716d0edc0fe8f10c54835396a68dbacc670eee07dffa3203f8b202dc414dcb317950b35d8f4da3f0bafe8f4b0d09b5103494ed9cf9075bfd19c47f8bdee607eccea1987b4bf6ba603e29043ef637b1b327e57adf1b29b098d4eadfebb736a5ea3558794f02b97f3611034adf002518d85e769210bb2ed2e4b4390433c55d6140ffda97a5018ee007adf5125f079bebdb6eba6c35d0504d8b7a9cbbf0bd9c57bd5b563fdc052a492a7dad4a3c782a69b711ac2969758cffc3d9089a34716517c45fbb164a6bd15a001d454dfd444becef4c4a7fdbc1aaf3b7e0983b900222674a726db2b1b155190cec29c6afefe3841924dd7b212437fb10bffc8a17cea19a97ec2dfafe897e8ad4c5418946525d0908ac8790580a47a17a8089e7b78499f2a54375778e387b0985293431e2104051600211e6e9a3f388e53d2df072d487d4c4838d8d8601fad2bd86d51ad3a58bebc0d8f6bac048d77968b26826cf545c44f7513667ac696564df8113529415a7e467d3a9f6bda8630717be753a45b5d688bbc4b95712f3bec044eb26db66f23961bf870cfb30347361e81a451f7f17642f6cbd902e92cc063b7cd4cdffbec78cb3f1957d650f89be7798894f6594ae1965964b5968c67003b247c0e83d3cef1ba2feef4c5c59d42a3efa8309f0ec4e9497b1c5a7c6b72f341d4ce5950bd12be5b6b22f32eade71f969f4ee1c0a864741fb2b5b1ad278c5f2f27000e4237b71cc664a87c50a7088b36bab5ad5a5494d599407fda9df6c538ad53563c222d3242b635116f5246b9dd6b7aba1f5abda8fd607ba18a3155c6e6c877ba0965f4005c8f475e5116bd7f899ba48ad299e5007401e49b85abf0ad681cbad302393975d682f6fb5a0795702ada0cf559198efff5ed8a16b12d1e866545db67d13ea5b7e59557776d458f5872d20ab0a3f6c74d61345bb6cd1f2dec5ee4a8d1c96d22a7b3c8ef21c1284d0785a56143100639cbfaddd5e94884c05ad97bdc1b9878082a47662898f549754812b390a2bb02ba487c6791eb083959499d8c22ec4b79caf467542aa89e22d69fa2bea599ce1923cb05efda49baa01b0405db15d8cbfe774cf38d520cde78b817177df5ddfdd1b7c5b164c1955aadd97a8ee58a53940041a8feb79ad90eb5593ce456db34e977dbb19e3054823c514afc4e5ca9c5a7abdf60b2ad80e66199c131e1dad4436e5289a51acb7aff16412afc36a49d37a813224bbadcfa7c6ab7e817fab68ed0be42d24ca34df61c2d8a38df8d0fe92416f131481fcc5f12eee6f2e3fa7b8035d631770c4faa15307c8f847e907b1b0ce96f9fbc1606162636465666768696a6b6c6d6e6f",
+ "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f",
+ "303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f"
+ ],
+ "measurement": [
+ 19342,
+ 19615,
+ 3061
+ ],
+ "nonce": "000102030405060708090a0b0c0d0e0f",
+ "out_shares": [
+ [
+ "a0e5e77978e4e319838804b62d66c7d1",
+ "edbbd0a1213e3921caece61ec83597ff",
+ "131d2639228e3b8e913cd8ff27c4e62a"
+ ],
+ [
+ "18a2aa085a9adc958c310ab9abf3b675",
+ "0243d6a6c871c929a8ab73bcbfb2a2dd",
+ "75df6c20efbaab098480e08f49afa5be"
+ ],
+ [
+ "d8c36d7d2d813f50b845f19026a681b8",
+ "b24d59b71550fdb45567a5247817c622",
+ "6e0f6da6eeb61868ce4247708e8c7316"
+ ]
+ ],
+ "prep_messages": [
+ "25034fec369564c831e89105a21ed2c7"
+ ],
+ "prep_shares": [
+ [
+ "fedaa3d68353f75a2db6a1e49b2397a29e8bb52fe68533a6e7518d7c431765b09d9fb09303205bd20b7bad45f8ee66e18d4ff77adffd7c0b1990ba9c1c18c0d83c70aab9194ab6e494736b7521bff256e44fb48a11052214545c4fc23b0424f8965526d4d9d8d65bb919f8e823db52d0cd97bbb67e45ed5ae83205b3c379c8b72f4220e4407e1f46c60ea678ed8d47742d82abe8cc8b00055cbeb2bf9c5cf03ee851b53b57812560f8c16902a3ca3e54d95174e928fcb415d903ba75e20b5c824ad2d32f70d2375df7fd78e3a9da48d881c81e5a3126d013776adc18fa8ffbfa1ad84cc857cabdf17c81c8f08d04e9dcf11e92808e461939e811b768e5fd98c3186d21176ab71c0fd31e38c5ce590cae",
+ "cb8307fb467bb023448e58c74d159bf447187a131bca6a8f66f613129c42c481051853dd2151e2cc480d5164567c8c4164b4ac35f70fe6b64517e65804ca767a12d4839078fa72b1e64e8531f3e54c09efe5a1f7aca60dd9e174711c82596e04211848dd2c787bd764b2099de3139df35aacfef634fc7a8fd7d4cb8f68a8c4eab19f2941d9f4660018a051ede752680abcbc6d60afb6984df051b2a1940016a2abe594acb8e9611a81294b8ed708fa932e03ad037523630eff76925e1a8076900b98b57a0d21fda8ff765c0394041a9ac56ec6717034855e757728c6617c78e28f623f5f376d80e762ee64ef3db152a4eaa42964a69f705f15eb77df0cf6f81589a8eaa4f01fe1b5aa656a0919ae5449",
+ "39a1542e3531588156bb055416c7cd6884463d0b107893ff1174455e3c438265c0746eb13013792fcc318698a96b1343f33bbecee2d08efabd7facd829d80dafe9e844395897d8d5f475d4644149864c3faef9fbd6b690a3750c76e3721c6667ae67d137adc6f38ec943c596b6fec17750073dadaecc860ca8ce32846d68208c3f9b5c6e59d9736159ede439854b05328ab3d8b398c8d0d7401a8718d9aad830978eab94b6bf4105729f7da8eddcee386ddf59f7d19da2437c7656a1f3d873c2500371d0434c5e6511da60302f9947e8c857cee7aa680bb0dd711dfda75fe0a0cd909fe76206570074fca8dd8cc511ed104a88289bd3cd4d9e34a6c9a50a03649a431dd8df92d78dd6c0d478dd93c0cb"
+ ]
+ ],
+ "public_share": "186d21176ab71c0fd31e38c5ce590cae89a8eaa4f01fe1b5aa656a0919ae54499a431dd8df92d78dd6c0d478dd93c0cb",
+ "rand": "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f"
+ },
+ {
+ "input_shares": [
+ "5d82bd1f81516122465f8a60a3209afef6a5c181fdfd80d20d280edb0ae8ccc4953eff5c0efe473d411cf4f3b2e3fd320c83c6b8f2c626a42d25f89594365561966e130ecf8a778e42ce7cca37b919eb9404560ba6a60a5e5b523f5ad397b378eeff4b21af66fba2f59db74e46ffdfa077bcea50472d6e771640a71fa31dd96445a2d8ce308904ea0d94760e7f8721d1531754521de6b338a20bdc8eda1d1acb6f3407a9f6f9d6cf9ccc3696c4d3226e8acf3207643a12d8c30332a8d364c97aafe81f4dc31ad62d49506e422e146492bd92a5cc933532fbfc1ee2e8e33116414358edd4baf633cdd80856f8132124171d9a2d989d3a9cf5d1d2b27baf94a5c524cf7ae624b8fe1c8ffc2229bbeecfc18f91c8683df7c579390d8b31ca87372cb6ebbe716d0edc0fe8f10c54835396a68dbacc670eee07dffa3203f8b202dc414dcb317950b35d8f4da3f0bafe8f4b0d09b5103494ed9cf9075bfd19c47f8bdee707eccea1987b4bf6ba603e29043ef636b1b327e57adf1b29b098d4eadfebb736a5ea3558794f02b97f3611034adf002518d85e769210bb2ed2e4b4390433c55c6140ffda97a5018ee007adf5125f079aebdb6eba6c35d0504d8b7a9cbbf0bd9c57bd5b563fdc052a492a7dad4a3c782b69b711ac2969758cffc3d9089a34716517c45fbb164a6bd15a001d454dfd444becef4c4a7fdbc1aaf3b7e0983b900221674a726db2b1b155190cec29c6afefe4841924dd7b212437fb10bffc8a17cea19a97ec2dfafe897e8ad4c5418946525d0908ac8790580a47a17a8089e7b78498f2a54375778e387b0985293431e2104051600211e6e9a3f388e53d2df072d487d4c4838d8d8601fad2bd86d51ad3a58aebc0d8f6bac048d77968b26826cf545c44f7513667ac696564df8113529415a6e467d3a9f6bda8630717be753a45b5d788bbc4b95712f3bec044eb26db66f23961bf870cfb30347361e81a451f7f17652f6cbd902e92cc063b7cd4cdffbec78cb3f1957d650f89be7798894f6594ae1a65964b5968c67003b247c0e83d3cef1ba2feef4c5c59d42a3efa8309f0ec4e9497b1c5a7c6b72f341d4ce5950bd12be5b6b22f32eade71f969f4ee1c0a864741fb2b5b1ad278c5f2f27000e4237b71cc664a87c50a7088b36bab5ad5a5494d599407fda9df6c538ad53563c222d3242b635116f5246b9dd6b7aba1f5abda8fd607ba18a3155c6e6c877ba0965f4005c8f475e5116bd7f899ba48ad299e5007401e49b85abf0ad681cbad302393975d682f6fb5a0795702ada0cf559198efff5ed8a16b12d1e866545db67d13ea5b7e59557776d458f5872d20ab0a3f6c74d61345bb6cd1f2dec5ee4a8d1c96d22a7b3c8ef21c1284d0785a56143100639cbfc3289478e516bd187dc85011217df3d9cc14a8f70c84bbd98d3a48ee1708913c3bd3c479700f0d9a01bc20a88c2c74202d08300dd1b74ec473f59b9f837fa6643b9a7627923e328512a0d1eaaef78c6fdb44f2789df4d6fea8cd33877405fbb744d075db8e2ea1c6363e0cb892ee5f90eb79ad90eb5593ce456db34e977dbb19ceba123f684af758e4bf0d03e1c085d6d425f0fd60afacc5baab06737d4cad9c375e0928789836c34150e196aca25fe1f4092243bdf49bb57f5dab084241ba1557429036f1660bb41b101fe37f03fce0595620833807d9b175ca2db5cc2df167cc1df780e3a73ecbbfcb4950440fb6c0606162636465666768696a6b6c6d6e6f",
+ "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f",
+ "303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f"
+ ],
+ "measurement": [
+ 15986,
+ 24671,
+ 23910
+ ],
+ "nonce": "000102030405060708090a0b0c0d0e0f",
+ "out_shares": [
+ [
+ "84d8e77978e4e319838804b62d66c7d1",
+ "adcfd0a1213e3921caece61ec83597ff",
+ "846e2639228e3b8e913cd8ff27c4e62a"
+ ],
+ [
+ "18a2aa085a9adc958c310ab9abf3b675",
+ "0243d6a6c871c929a8ab73bcbfb2a2dd",
+ "75df6c20efbaab098480e08f49afa5be"
+ ],
+ [
+ "d8c36d7d2d813f50b845f19026a681b8",
+ "b24d59b71550fdb45567a5247817c622",
+ "6e0f6da6eeb61868ce4247708e8c7316"
+ ]
+ ],
+ "prep_messages": [
+ "164bb9a531ed86890f679cfee8e40bd7"
+ ],
+ "prep_shares": [
+ [
+ "fedaa3d68353f75a2db6a1e49b2397a2d951596ce321ca830642b1c9a71f119b750393c6c754d535696c304ff488bcc6977ced640b7644d68067fa674f608e0a5751aaca2e39d7e4f47bec846689f311124c532053e2285de1dd28c7430d205d7bef7f1ff5f36d363f8ca7cf16b9d28d7fe79342273ee2629adb1396910910d4f1243c6e17898c5de5b4e50915995e0ec6b2c92fd59cf001c32018e569d540e26a5512100c73b1dfb9e76c4865fb4c8a98d2382c1bd1bbef9cb6f8fee190a7b2c18bb9c694e107ede1966ba61589e8a1ee07c034878188043745d1a13e9d328c35ab0af3a25ad52a2941d5c87ef54e798f310d45c2a44eb9b8b484c4cf2cb11289979db009d84867e096271383f95f17",
+ "cb8307fb467bb023448e58c74d159bf49f9b010f8d3342eccac47f456395810c051853dd2151e2cc480d5164567c8c41b406b0bc3e39acaada3e1565084d70c512d4839078fa72b1e64e8531f3e54c09965aa5eacbdfd1c87023b5c2c1751952211848dd2c787bd764b2099de3139df3696d74860c683106e0ba03981fd175ceb19f2941d9f4660018a051ede752680a2e4d31fc97379acf03c3454eb29d0433abe594acb8e9611a81294b8ed708fa932cd4dc5aeb67e4082571e2c1a9e2e9370b98b57a0d21fda8ff765c0394041a9abc294b2171b29cdda805a50345b159548f623f5f376d80e762ee64ef3db152a4eaa42964a69f705f15eb77df0cf6f81589a8eaa4f01fe1b5aa656a0919ae5449",
+ "39a1542e3531588156bb055416c7cd68bc76b21ba7b0f0ee6be53024718f5ae0c0746eb13013792fcc318698a96b13435bf89e78f7ee3fd7e39a1fdab2ea808be9e844395897d8d5f475d4644149864c3768148cc4a96a193de9ea7fad3ee418ae67d137adc6f38ec943c596b6fec177dc960939e2aa0560144c058bc34cabcb3f9b5c6e59d9736159ede439854b053235b3543dd1ff08e9184d44c28b2e98c8978eab94b6bf4105729f7da8eddcee388df030cba4cd2df0eccbf799ad07d72e500371d0434c5e6511da60302f9947e8a9a78a25434f4d85ce460e1dc1446ea7cd909fe76206570074fca8dd8cc511ed104a88289bd3cd4d9e34a6c9a50a03649a431dd8df92d78dd6c0d478dd93c0cb"
+ ]
+ ],
+ "public_share": "89979db009d84867e096271383f95f1789a8eaa4f01fe1b5aa656a0919ae54499a431dd8df92d78dd6c0d478dd93c0cb",
+ "rand": "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f"
+ }
+ ],
+ "shares": 3,
+ "verify_key": "000102030405060708090a0b0c0d0e0f"
+}
diff --git a/third_party/rust/prio/src/vdaf/test_vec/08/Prio3Sum_0.json b/third_party/rust/prio/src/vdaf/test_vec/08/Prio3Sum_0.json
new file mode 100644
index 0000000000..040e3f1741
--- /dev/null
+++ b/third_party/rust/prio/src/vdaf/test_vec/08/Prio3Sum_0.json
@@ -0,0 +1,40 @@
+{
+ "agg_param": null,
+ "agg_result": 100,
+ "agg_shares": [
+ "f3d18d266d89cb425fd64a19a436e8bc",
+ "722e72d9927634bd8429b5e65bc91743"
+ ],
+ "bits": 8,
+ "prep": [
+ {
+ "input_shares": [
+ "6dc25550077a71c59f7020e3d0e7ac8da5809fa59c2a1c7da50f49f348a2dd8f46ac57b16cf3a153fb3aa17f19b651354b6e5e2666029f55a6e0d76f25269781bb4f7cf5e79ddd703d07a49094e878e48a68b2a4b901bceeb954375740d2385821e421c0d14a2246d80a4ef53b99eb6dac3738491e6a337c124d1bbdc0e1c752ee2e3b77c8f83cf734b152c7c93caab48127d1fcae79f5dc47d4e8f62463408f5c82435087d2a244e8b54a508f8474307003ff6d76327921cfc1b68e893f1eb8cbaf513ed61bbae3d3580c34c2dfae2ceb8a1120842f5db85c78c2f4225452a6f2b618972d56f013db62e73b92a8ec83107719d35a27f5cdc493d73a772c9f5c7bc67f4280e90dc1eadbe043546a8b5975976a00739136f5f4ab37b8d845f32db1c97a831b3a9d2d3bbec621146d5a5f8788d7e7a1958b2a9382c1d9f538b91d9582bab31f496c9ddc517ae206533a8b18e0b3854587379a3120970b0246aa13758de413cee5f99794170de0bbd7479bdf968c1db98d53b30bea4417d54c9cdcc5f5e71bd7367ad95aacfb02693f25bca1a5fd67cfb3ef6406607ecef3bbe052cab782eacce5d25f6589325d20a1d6f2d9beb14c3c89cb18d0042a5376907c057203feffcd8a36b24ecabc6fe4e0133ec68a1313b669c1771b91ffb86c284646ea5ad270c492b5d5d7a24b27655c2a715af2e797823fa97f87df42184add6f1cc26e9762159d43e9548a6a89da738a8a36159369e3aa7d3b2c25c8cf95b788bfd6293b9e66a42d3bde7b00a5822eb4f97347c91f9882d54a6279c22501ce4f3fa5ebca8fcbfd7baff84e687cb8d77b48e8b4026560d873e2b8c0529d02f3d4f1e5764e498cc9d22a5d64b50fb38edc42491e5f1571244bc6269a7fbbe64406b4303132333435363738393a3b3c3d3e3f",
+ "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f"
+ ],
+ "measurement": 100,
+ "nonce": "000102030405060708090a0b0c0d0e0f",
+ "out_shares": [
+ [
+ "f3d18d266d89cb425fd64a19a436e8bc"
+ ],
+ [
+ "722e72d9927634bd8429b5e65bc91743"
+ ]
+ ],
+ "prep_messages": [
+ "aac7d7306c0cdbbd7e23ef394322d54a"
+ ],
+ "prep_shares": [
+ [
+ "5e6f31522c0cb9b5107ad0c560b6ef9a69553124df856a84affd0a814674ea325a2f1c7fc62f1838a8d7aa8d4263ac0d86243c1f5c53992219ddfef99b94f76d",
+ "a390ceadd3f3464ad3852f3a9f49106571003e04a8d922570934a5812d4a8c45c1cf374cea16117767d4f4ee963acd756d42402e0f2b584af325b34eaa1615ad"
+ ]
+ ],
+ "public_share": "86243c1f5c53992219ddfef99b94f76d6d42402e0f2b584af325b34eaa1615ad",
+ "rand": "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f"
+ }
+ ],
+ "shares": 2,
+ "verify_key": "000102030405060708090a0b0c0d0e0f"
+}
diff --git a/third_party/rust/prio/src/vdaf/test_vec/08/Prio3Sum_1.json b/third_party/rust/prio/src/vdaf/test_vec/08/Prio3Sum_1.json
new file mode 100644
index 0000000000..8baf391f08
--- /dev/null
+++ b/third_party/rust/prio/src/vdaf/test_vec/08/Prio3Sum_1.json
@@ -0,0 +1,46 @@
+{
+ "agg_param": null,
+ "agg_result": 100,
+ "agg_shares": [
+ "f91bcafa315d7cfa26564999203babdc",
+ "722e72d9927634bd8429b5e65bc91743",
+ "fbb5c32b3b2c4f481c80018083fb3ce0"
+ ],
+ "bits": 8,
+ "prep": [
+ {
+ "input_shares": [
+ "a48f16f9472cb825154a980720bd436b62db8329758026ed40deaa18e9bccea80cc0d2e40164379e7498b61a280fa86e7080b53acd1baf84604c5270ba2e161b069c2f1187bbead120b10d073d3326c5da5edeca2a2e0322253face85a769c92155d2859b86caac4f2b25d8779b2a99de3af195b2be8a4e5923d2a566833f86a683fdd68189962ea14ca940bcae99c612ca93caf3ec9bfa9ca2bdc0adeb80dba90992e4ea878bd39e321fe43f0cc073d9b5a8f9ff7f38b333e907e510a04499dc78059a620bc2d7201e3c7a4545cb5066add82690fd25269e66e1cf4334211b5578dc556c377753a501da19da81e839e6f3b7f56724ad9ee5e6dbc0a1cdcd3fc36601586eca9a50a620ed1c8941379369ae3a72b13c11c76cbd1f69d5d5acca56da4d8567007cbba3da384aa2d73e1bfba7ff77864c3b508d5a5b69b69a0bc6c092fc84d564e8f9726686e13f32239912a8a0bd92a8849d81f30560618db3bbd7f8b14a68e8a4bb2f61db7fa471573a4bee095db799ff19407b22fd77ecd55206e85f36dabec6323d8aaea77e328a07e3ccbcb3c893f6522fd0aa39f09b79dd9167cb9bccc326e2aaf51cc0e187c46766ccbe75321deb403d470795926b6879f0398a996aa5330734a5f3fed8b0e69e3a2c8a4efcd739fbedda27ae086f7144e655cdc89b07183818b56ce01dddf691d2a57f846c77d8601b203a2caf8a9bb3ec4f340d68702bf320df74e304d2db24de0dd26a6346ccc9a65c6c24e45a31636efb0919a87c8b14c08226807807acb467c29481b03e541c3ad3b2512b89c794687f4dae6b4c5f7fef5b5c348e61cca26629f015fc7babc7e0261b477843df830057f7c69248b4493b2e7a9f5503ba3eee569fc9911b35d0dd6111e8985a42273606162636465666768696a6b6c6d6e6f",
+ "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f",
+ "303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f"
+ ],
+ "measurement": 100,
+ "nonce": "000102030405060708090a0b0c0d0e0f",
+ "out_shares": [
+ [
+ "f91bcafa315d7cfa26564999203babdc"
+ ],
+ [
+ "722e72d9927634bd8429b5e65bc91743"
+ ],
+ [
+ "fbb5c32b3b2c4f481c80018083fb3ce0"
+ ]
+ ],
+ "prep_messages": [
+ "215cd3acf2c12d42b2897cb57fb420a6"
+ ],
+ "prep_shares": [
+ [
+ "8a17e1ae7baf0fcb35b9d89394f8f34e5e965d98db9ffbe0867029fbbdfd7195d7fda8b597d471f0046bd4508be2e2abbf23e0b165f191b5165f0350ae251442",
+ "6c98be496224df8772c21173ad6fa2b271003e04a8d922570934a5812d4a8c45c1cf374cea16117767d4f4ee963acd756d42402e0f2b584af325b34eaa1615ad",
+ "0c506007222c11ad1f8415f9bd9769fe526f9e6835c5e2ce8c44b01f27cc5060c4c159a86eb48e1571437659eb32b3e8800a1a73b5ae07e45e4cc67555122b2d"
+ ]
+ ],
+ "public_share": "bf23e0b165f191b5165f0350ae2514426d42402e0f2b584af325b34eaa1615ad800a1a73b5ae07e45e4cc67555122b2d",
+ "rand": "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f"
+ }
+ ],
+ "shares": 3,
+ "verify_key": "000102030405060708090a0b0c0d0e0f"
+}
diff --git a/third_party/rust/prio/src/vdaf/test_vec/08/XofFixedKeyAes128.json b/third_party/rust/prio/src/vdaf/test_vec/08/XofFixedKeyAes128.json
new file mode 100644
index 0000000000..6a34d6e32e
--- /dev/null
+++ b/third_party/rust/prio/src/vdaf/test_vec/08/XofFixedKeyAes128.json
@@ -0,0 +1,8 @@
+{
+ "binder": "62696e64657220737472696e67",
+ "derived_seed": "3805276060157b7376b069305303669b",
+ "dst": "646f6d61696e2073657061726174696f6e20746167",
+ "expanded_vec_field128": "3805276060157b7376b069305303669b92beaaa4afa982314428494ba98f3595d49e76d1301b451d6fd79c9acbe9118717cfd0d4b9ef29806b4dce298a2d6aba17d7025e7964a2d7e24a263bd79d19edb11cd1db4bc07ce0ae1a9c6d1f59233e8d7065a66ce1b123ed773e4b370c9217c7032fc805f3a13f6fe2ef6f7961bf9d20fd22b8cd544cefe8e634d9245db7813ba43f630a123dfda73b6bbad8b11a916090a7d5ba8a4d20853f3f5c8222684050a53119e829313fa8de64f92553a44aa522fc90d9ec75f80547ec9637ce60e74afd51baa1d80b549444c5f0a6283ff494698ea6ffaea65964c4e0c2f9cf72a11310000261ddc85661f5068f505d34273295be9b8549b4c6278a80794929093a17cc017cf0b0e68e32e941708cfa58b9e598ac3d5d2ab4e9b33111c9c9fbc0a3682617d0ed1a0d15c9bfb9d5fd2889d1f56dd3a7f2e61ca59b0705d35f915349ffea0341816532bbdaa6dddba42bf27d1699d9e9ef580f3686ea42d687e54a87c3e6dab4f1ee5e1185faa6b809eb1a1e940692b3ba882684e8440b73e23088411000cf77ba69777b3bfa417050f0cef6cd0c9b6e7a47ab5c3da9a0e3de6ec323aed32f4cc3f51ac719e34f0bd9b0cc617e3034581a708f4a3bba587b4b4cb91529cfd47393893c3b5cd430d0456a245b0c45d4398fe423b67faa8682c764d92c514d7e34a89abc16353e71de7d49895527e632a6163d7362549a8e9ab12277460d30d7892e0a5993a4d3922738f07892764b0ceabf280779894ced52aa7fba94100c2ec0fa1973d2b11044e6844ddcdbd59f26e1b321d02c9189414cace4abece30878ca21d198f2e61b84e7cbebb6a0ad83e2abd5bf69d7f8eed193a8e141088a4b7d41fe23a939f678ba94a1d9c9c2",
+ "length": 40,
+ "seed": "000102030405060708090a0b0c0d0e0f"
+}
diff --git a/third_party/rust/prio/src/vdaf/test_vec/08/XofTurboShake128.json b/third_party/rust/prio/src/vdaf/test_vec/08/XofTurboShake128.json
new file mode 100644
index 0000000000..1e48d1f648
--- /dev/null
+++ b/third_party/rust/prio/src/vdaf/test_vec/08/XofTurboShake128.json
@@ -0,0 +1,8 @@
+{
+ "binder": "62696e64657220737472696e67",
+ "derived_seed": "8bac064e720bb1c413040a3f41990075",
+ "dst": "646f6d61696e2073657061726174696f6e20746167",
+ "expanded_vec_field128": "8bac064e720bb1c413040a3f419900750ce08494b0f4f2d95171dcf44255ef94606fd5e6ffe3735329f5550e34fe61f0d4704239c107e4beb6623e20cb2e2659662aef8409fcc162a01d2333fc8d8ee7bc31c394c88edeb5904d25bf851d30246d9bf4221a5aec6ff4cb2580dde88dfa726e21b35da18f5b1839a257482ab292615b094b092444013874fce11cbd293fc81fd9a00d1befca7b1aefa2324ad2c84a8d678b02973bd539021e18861647474211e99ccfff5e47483985b25257f83665f44ed3fbce4f5a2b20e5c54239653141f7d5132b255936d33327789e13b145362059f67bd8d5b240dfd1e525d6ac5c0bb6a5b4a0b7b7318a5e22fc91763d2eb9dbd5fd3a3665127ffa63ac5be71a0b67a5ce5ee158d902a4e3a4c580e734ee40682e471373b958853eddee1de30dda6e6f4a3e3a297a79bd7f332ce89b8f0cd50589f03b95408405df362a41f58688e1fb818deaccf36eedbabc1762215102de02125dc79450d47dc04ba88cd507bdf1690ae6c1dbb44352c29687e3f60e0d3d9ed8758aa1495f4976477bda7e3cdbf37078f615dfde8330df46aebe393a665fa3f9b906498ef59ac5a0da50ebeb91c80ac0d8ba3d9bcb4e23f37e416dbe679d633834b8351085a321314d8b0276b24de1dc41091f9bdf765f2879ef0d624927a649bb693386b5a22af2ec5b67b8298abadf1e4ffa10a794ebb9924761d08ad75b595ef11118b33a8f5e649e0b8351600be077a164c806a7ee2aba58de06177ccd18e8822d35c2d6843378f254d64e5a1ee52d9c5b3f63ae262c3d6d5b63baf4e2faf436d51d6318ac9d05cf4fe3e203b2b047bdb1b4f4f8d5645a5d59ab506afc423f3a0ae5691e7f755dc5bff3b6b4f08c61614b62f63b03ce30d35a2c0d",
+ "length": 40,
+ "seed": "000102030405060708090a0b0c0d0e0f"
+}
diff --git a/third_party/rust/prio/src/vdaf/test_vec/XofHmacSha256Aes128.json b/third_party/rust/prio/src/vdaf/test_vec/XofHmacSha256Aes128.json
new file mode 100644
index 0000000000..510cc539e1
--- /dev/null
+++ b/third_party/rust/prio/src/vdaf/test_vec/XofHmacSha256Aes128.json
@@ -0,0 +1,8 @@
+{
+ "binder": "62696e64657220737472696e67",
+ "derived_seed": "e826c9564c620fb63357fbee88dc9bb3de2c41764adb44bea344024e1da124c6",
+ "dst": "646f6d61696e2073657061726174696f6e20746167",
+ "expanded_vec_field128": "e826c9564c620fb63357fbee88dc9bb3de2c41764adb44bea344024e1da124c6172f208e79762fed92c73cea422b312860008ee80e30f31d2d87840890604f39db37983f5c3483407333cecdb1b9ea550c26bc4f2d999fda91963054c6cb35a8ad8d28ee74a48e28aa475d67124e7c4417149955e506690d62e17f0730b7d4db8a9754f80603b7720205819d26bcfe4a4663d05c98c12705ea7dc333d5746d9c8ba697bb3d5be95d26ccb73052cb8fb19edfc35eaebaa22779436d3015512c9b536003d98b04a0f46feddbff762007c377c28a04039f72657650885bd40ed37acea63facd3c33d1ecb5048641053af5b4018b0c373d9ed7440da9fc6c76666c2eb8ed2943a64bbf6dae93ac91fcc26d7225c2ae42349161522fcce0b92d209411af8566b0adbaa36a8479737017efd2c359ea43924cdf432650dcd742e358af55ff6c321d0ebaae2abf5812d58b060cc147395e8137f99db58d2c425f2704da067df3a41c0443918375c177fa53545d8190d828c6045bbe5930e4762588ea14dc0a9db6cd903216ccae968ca0b11f0ac04e4dfc69a99986841dc99c851e314c7d4b10f4ef72e1244b543465fed076a7e9f50baca4ad7dccc73bfc55310f2ae6eaeaf7ee7a4d41fec76bff3b04e67d1f83e4da59f1fcb45877adfc3e4a2b1d5e3f136131ca2a02f34bdba1c5d2dafb2178674dc002d247662497b7f5818880cff308e5222e6df0bcdf6f68ebfaa8d0551530fa00ec29646441961e33b50872ada911591e16e3021baa5e7869756d3d812a63e3c7fa2c0ec2dc4cabe11c0256829b360ad9431536ab96efbe5a364cd1c323de8fbe405a2c87b9c58e5740bfb118af0ca1a23afb4a04e9cec3b9d1e57834cbc0fa17d5d7285f1f013df05e92a7343",
+ "length": 40,
+ "seed": "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f"
+}
diff --git a/third_party/rust/prio/src/vdaf/xof.rs b/third_party/rust/prio/src/vdaf/xof.rs
index b38d176467..67881419df 100644
--- a/third_party/rust/prio/src/vdaf/xof.rs
+++ b/third_party/rust/prio/src/vdaf/xof.rs
@@ -1,8 +1,14 @@
// SPDX-License-Identifier: MPL-2.0
-//! Implementations of XOFs specified in [[draft-irtf-cfrg-vdaf-07]].
+//! Implementations of XOFs specified in [[draft-irtf-cfrg-vdaf-08]].
//!
-//! [draft-irtf-cfrg-vdaf-07]: https://datatracker.ietf.org/doc/draft-irtf-cfrg-vdaf/07/
+//! [draft-irtf-cfrg-vdaf-08]: https://datatracker.ietf.org/doc/draft-irtf-cfrg-vdaf/08/
+
+/// Value of the domain separation byte "D" used by XofTurboShake128 when invoking TurboSHAKE128.
+const XOF_TURBO_SHAKE_128_DOMAIN_SEPARATION: u8 = 1;
+/// Value of the domain separation byte "D" used by XofFixedKeyAes128 when invoking TurboSHAKE128.
+#[cfg(all(feature = "crypto-dependencies", feature = "experimental"))]
+const XOF_FIXED_KEY_AES_128_DOMAIN_SEPARATION: u8 = 2;
use crate::{
field::FieldElement,
@@ -21,13 +27,17 @@ use aes::{
};
#[cfg(feature = "crypto-dependencies")]
use ctr::Ctr64BE;
+#[cfg(feature = "crypto-dependencies")]
+use hmac::{Hmac, Mac};
use rand_core::{
impls::{next_u32_via_fill, next_u64_via_fill},
RngCore, SeedableRng,
};
+#[cfg(feature = "crypto-dependencies")]
+use sha2::Sha256;
use sha3::{
digest::{ExtendableOutput, Update, XofReader},
- Shake128, Shake128Core, Shake128Reader,
+ TurboShake128, TurboShake128Core, TurboShake128Reader,
};
#[cfg(feature = "crypto-dependencies")]
use std::fmt::Formatter;
@@ -76,8 +86,9 @@ impl<const SEED_SIZE: usize> ConstantTimeEq for Seed<SEED_SIZE> {
}
impl<const SEED_SIZE: usize> Encode for Seed<SEED_SIZE> {
- fn encode(&self, bytes: &mut Vec<u8>) {
+ fn encode(&self, bytes: &mut Vec<u8>) -> Result<(), CodecError> {
bytes.extend_from_slice(&self.0[..]);
+ Ok(())
}
fn encoded_len(&self) -> Option<usize> {
@@ -105,9 +116,9 @@ impl<S: RngCore> IntoFieldVec for S {
}
}
-/// An extendable output function (XOF) with the interface specified in [[draft-irtf-cfrg-vdaf-07]].
+/// An extendable output function (XOF) with the interface specified in [[draft-irtf-cfrg-vdaf-08]].
///
-/// [draft-irtf-cfrg-vdaf-07]: https://datatracker.ietf.org/doc/draft-irtf-cfrg-vdaf/07/
+/// [draft-irtf-cfrg-vdaf-08]: https://datatracker.ietf.org/doc/draft-irtf-cfrg-vdaf/08/
pub trait Xof<const SEED_SIZE: usize>: Clone + Debug {
/// The type of stream produced by this XOF.
type SeedStream: RngCore + Sized;
@@ -145,7 +156,9 @@ pub struct SeedStreamAes128(Ctr64BE<Aes128>);
#[cfg(feature = "crypto-dependencies")]
impl SeedStreamAes128 {
- pub(crate) fn new(key: &[u8], iv: &[u8]) -> Self {
+ /// Construct an instance of the seed stream with the given AES key `key` and initialization
+ /// vector `iv`.
+ pub fn new(key: &[u8], iv: &[u8]) -> Self {
SeedStreamAes128(<Ctr64BE<Aes128> as KeyIvInit>::new(key.into(), iv.into()))
}
@@ -187,17 +200,19 @@ impl Debug for SeedStreamAes128 {
}
}
-/// The XOF based on SHA-3 as specified in [[draft-irtf-cfrg-vdaf-07]].
+/// The XOF based on TurboSHAKE128 as specified in [[draft-irtf-cfrg-vdaf-08]].
///
-/// [draft-irtf-cfrg-vdaf-07]: https://datatracker.ietf.org/doc/draft-irtf-cfrg-vdaf/07/
+/// [draft-irtf-cfrg-vdaf-08]: https://datatracker.ietf.org/doc/draft-irtf-cfrg-vdaf/08/
#[derive(Clone, Debug)]
-pub struct XofShake128(Shake128);
+pub struct XofTurboShake128(TurboShake128);
-impl Xof<16> for XofShake128 {
- type SeedStream = SeedStreamSha3;
+impl Xof<16> for XofTurboShake128 {
+ type SeedStream = SeedStreamTurboShake128;
fn init(seed_bytes: &[u8; 16], dst: &[u8]) -> Self {
- let mut xof = Self(Shake128::from_core(Shake128Core::default()));
+ let mut xof = Self(TurboShake128::from_core(TurboShake128Core::new(
+ XOF_TURBO_SHAKE_128_DOMAIN_SEPARATION,
+ )));
Update::update(
&mut xof.0,
&[dst.len().try_into().expect("dst must be at most 255 bytes")],
@@ -211,21 +226,21 @@ impl Xof<16> for XofShake128 {
Update::update(&mut self.0, data);
}
- fn into_seed_stream(self) -> SeedStreamSha3 {
- SeedStreamSha3::new(self.0.finalize_xof())
+ fn into_seed_stream(self) -> SeedStreamTurboShake128 {
+ SeedStreamTurboShake128::new(self.0.finalize_xof())
}
}
-/// The seed stream produced by SHAKE128.
-pub struct SeedStreamSha3(Shake128Reader);
+/// The seed stream produced by TurboSHAKE128.
+pub struct SeedStreamTurboShake128(TurboShake128Reader);
-impl SeedStreamSha3 {
- pub(crate) fn new(reader: Shake128Reader) -> Self {
+impl SeedStreamTurboShake128 {
+ pub(crate) fn new(reader: TurboShake128Reader) -> Self {
Self(reader)
}
}
-impl RngCore for SeedStreamSha3 {
+impl RngCore for SeedStreamTurboShake128 {
fn fill_bytes(&mut self, dest: &mut [u8]) {
XofReader::read(&mut self.0, dest);
}
@@ -244,13 +259,13 @@ impl RngCore for SeedStreamSha3 {
}
}
-/// A `rand`-compatible interface to construct XofShake128 seed streams, with the domain separation tag
-/// and binder string both fixed as the empty string.
-impl SeedableRng for SeedStreamSha3 {
+/// A `rand`-compatible interface to construct XofTurboShake128 seed streams, with the domain
+/// separation tag and binder string both fixed as the empty string.
+impl SeedableRng for SeedStreamTurboShake128 {
type Seed = [u8; 16];
fn from_seed(seed: Self::Seed) -> Self {
- XofShake128::init(&seed, b"").into_seed_stream()
+ XofTurboShake128::init(&seed, b"").into_seed_stream()
}
}
@@ -269,7 +284,9 @@ pub struct XofFixedKeyAes128Key {
impl XofFixedKeyAes128Key {
/// Derive the fixed key from the domain separation tag and binder string.
pub fn new(dst: &[u8], binder: &[u8]) -> Self {
- let mut fixed_key_deriver = Shake128::from_core(Shake128Core::default());
+ let mut fixed_key_deriver = TurboShake128::from_core(TurboShake128Core::new(
+ XOF_FIXED_KEY_AES_128_DOMAIN_SEPARATION,
+ ));
Update::update(
&mut fixed_key_deriver,
&[dst.len().try_into().expect("dst must be at most 255 bytes")],
@@ -293,15 +310,15 @@ impl XofFixedKeyAes128Key {
}
}
-/// XofFixedKeyAes128 as specified in [[draft-irtf-cfrg-vdaf-07]]. This XOF is NOT RECOMMENDED for
+/// XofFixedKeyAes128 as specified in [[draft-irtf-cfrg-vdaf-08]]. This XOF is NOT RECOMMENDED for
/// general use; see Section 9 ("Security Considerations") for details.
///
-/// This XOF combines SHA-3 and a fixed-key mode of operation for AES-128. The key is "fixed" in
-/// the sense that it is derived (using SHAKE128) from the domain separation tag and binder
-/// strings, and depending on the application, these strings can be hard-coded. The seed is used to
-/// construct each block of input passed to a hash function built from AES-128.
+/// This XOF combines TurboSHAKE128 and a fixed-key mode of operation for AES-128. The key is
+/// "fixed" in the sense that it is derived (using TurboSHAKE128) from the domain separation tag and
+/// binder strings, and depending on the application, these strings can be hard-coded. The seed is
+/// used to construct each block of input passed to a hash function built from AES-128.
///
-/// [draft-irtf-cfrg-vdaf-07]: https://datatracker.ietf.org/doc/draft-irtf-cfrg-vdaf/07/
+/// [draft-irtf-cfrg-vdaf-08]: https://datatracker.ietf.org/doc/draft-irtf-cfrg-vdaf/08/
#[derive(Clone, Debug)]
#[cfg(all(feature = "crypto-dependencies", feature = "experimental"))]
#[cfg_attr(
@@ -309,7 +326,7 @@ impl XofFixedKeyAes128Key {
doc(cfg(all(feature = "crypto-dependencies", feature = "experimental")))
)]
pub struct XofFixedKeyAes128 {
- fixed_key_deriver: Shake128,
+ fixed_key_deriver: TurboShake128,
base_block: Block,
}
@@ -318,7 +335,7 @@ impl Xof<16> for XofFixedKeyAes128 {
type SeedStream = SeedStreamFixedKeyAes128;
fn init(seed_bytes: &[u8; 16], dst: &[u8]) -> Self {
- let mut fixed_key_deriver = Shake128::from_core(Shake128Core::default());
+ let mut fixed_key_deriver = TurboShake128::from_core(TurboShake128Core::new(2u8));
Update::update(
&mut fixed_key_deriver,
&[dst.len().try_into().expect("dst must be at most 255 bytes")],
@@ -433,6 +450,37 @@ impl RngCore for SeedStreamFixedKeyAes128 {
}
}
+/// XOF based on HMAC-SHA256 and AES128. This XOF is not part of the VDAF spec.
+#[cfg(feature = "crypto-dependencies")]
+#[cfg_attr(docsrs, doc(cfg(feature = "crypto-dependencies")))]
+#[derive(Clone, Debug)]
+pub struct XofHmacSha256Aes128(Hmac<Sha256>);
+
+#[cfg(feature = "crypto-dependencies")]
+impl Xof<32> for XofHmacSha256Aes128 {
+ type SeedStream = SeedStreamAes128;
+
+ fn init(seed_bytes: &[u8; 32], dst: &[u8]) -> Self {
+ let mut mac = <Hmac<Sha256> as Mac>::new_from_slice(seed_bytes).unwrap();
+ Mac::update(
+ &mut mac,
+ &[dst.len().try_into().expect("dst must be at most 255 bytes")],
+ );
+ Mac::update(&mut mac, dst);
+ Self(mac)
+ }
+
+ fn update(&mut self, data: &[u8]) {
+ Mac::update(&mut self.0, data);
+ }
+
+ fn into_seed_stream(self) -> SeedStreamAes128 {
+ let tag = Mac::finalize(self.0).into_bytes();
+ let (key, iv) = tag.split_at(16);
+ SeedStreamAes128::new(key, iv)
+ }
+}
+
#[cfg(test)]
mod tests {
use super::*;
@@ -480,10 +528,34 @@ mod tests {
}
#[test]
- fn xof_shake128() {
+ fn xof_turboshake128() {
let t: XofTestVector =
- serde_json::from_str(include_str!("test_vec/07/XofShake128.json")).unwrap();
- let mut xof = XofShake128::init(&t.seed.try_into().unwrap(), &t.dst);
+ serde_json::from_str(include_str!("test_vec/08/XofTurboShake128.json")).unwrap();
+ let mut xof = XofTurboShake128::init(&t.seed.try_into().unwrap(), &t.dst);
+ xof.update(&t.binder);
+
+ assert_eq!(
+ xof.clone().into_seed(),
+ Seed(t.derived_seed.try_into().unwrap())
+ );
+
+ let mut bytes = Cursor::new(t.expanded_vec_field128.as_slice());
+ let mut want = Vec::with_capacity(t.length);
+ while (bytes.position() as usize) < t.expanded_vec_field128.len() {
+ want.push(Field128::decode(&mut bytes).unwrap())
+ }
+ let got: Vec<Field128> = xof.clone().into_seed_stream().into_field_vec(t.length);
+ assert_eq!(got, want);
+
+ test_xof::<XofTurboShake128, 16>();
+ }
+
+ #[test]
+ fn xof_hmac_sha256_aes128() {
+ let t: XofTestVector =
+ serde_json::from_str(include_str!("test_vec/XofHmacSha256Aes128.json")).unwrap();
+
+ let mut xof = XofHmacSha256Aes128::init(&t.seed.try_into().unwrap(), &t.dst);
xof.update(&t.binder);
assert_eq!(
@@ -499,14 +571,14 @@ mod tests {
let got: Vec<Field128> = xof.clone().into_seed_stream().into_field_vec(t.length);
assert_eq!(got, want);
- test_xof::<XofShake128, 16>();
+ test_xof::<XofHmacSha256Aes128, 32>();
}
#[cfg(feature = "experimental")]
#[test]
fn xof_fixed_key_aes128() {
let t: XofTestVector =
- serde_json::from_str(include_str!("test_vec/07/XofFixedKeyAes128.json")).unwrap();
+ serde_json::from_str(include_str!("test_vec/08/XofFixedKeyAes128.json")).unwrap();
let mut xof = XofFixedKeyAes128::init(&t.seed.try_into().unwrap(), &t.dst);
xof.update(&t.binder);
diff --git a/third_party/rust/prio/src/vidpf.rs b/third_party/rust/prio/src/vidpf.rs
new file mode 100644
index 0000000000..c8ba5db22c
--- /dev/null
+++ b/third_party/rust/prio/src/vidpf.rs
@@ -0,0 +1,827 @@
+// SPDX-License-Identifier: MPL-2.0
+
+//! Verifiable Incremental Distributed Point Function (VIDPF).
+//!
+//! The VIDPF construction is specified in [[draft-mouris-cfrg-mastic]] and builds
+//! on techniques from [[MST23]] and [[CP22]] to lift an IDPF to a VIDPF.
+//!
+//! [CP22]: https://eprint.iacr.org/2021/580
+//! [MST23]: https://eprint.iacr.org/2023/080
+//! [draft-mouris-cfrg-mastic]: https://datatracker.ietf.org/doc/draft-mouris-cfrg-mastic/02/
+
+use core::{
+ iter::zip,
+ ops::{Add, AddAssign, BitXor, BitXorAssign, Index, Sub},
+};
+
+use bitvec::field::BitField;
+use rand_core::RngCore;
+use std::io::Cursor;
+use subtle::{Choice, ConditionallyNegatable, ConditionallySelectable};
+
+use crate::{
+ codec::{CodecError, Encode, ParameterizedDecode},
+ field::FieldElement,
+ idpf::{
+ conditional_select_seed, conditional_swap_seed, conditional_xor_seeds, xor_seeds,
+ IdpfInput, IdpfValue,
+ },
+ vdaf::xof::{Seed, Xof, XofFixedKeyAes128, XofTurboShake128},
+};
+
+/// VIDPF-related errors.
+#[derive(Debug, thiserror::Error)]
+#[non_exhaustive]
+pub enum VidpfError {
+ /// Error when key's identifier are equal.
+ #[error("key's identifier should be different")]
+ SameKeyId,
+
+ /// Error when level does not fit in a 32-bit number.
+ #[error("level is not representable as a 32-bit integer")]
+ LevelTooBig,
+
+ /// Error during VIDPF evaluation: tried to access a level index out of bounds.
+ #[error("level index out of bounds")]
+ IndexLevel,
+
+ /// Error when weight's length mismatches the length in weight's parameter.
+ #[error("invalid weight length")]
+ InvalidWeightLength,
+
+ /// Failure when calling getrandom().
+ #[error("getrandom: {0}")]
+ GetRandom(#[from] getrandom::Error),
+}
+
+/// Represents the domain of an incremental point function.
+pub type VidpfInput = IdpfInput;
+
+/// Represents the codomain of an incremental point function.
+pub trait VidpfValue: IdpfValue + Clone {}
+
+/// A VIDPF instance.
+pub struct Vidpf<W: VidpfValue, const NONCE_SIZE: usize> {
+ /// Any parameters required to instantiate a weight value.
+ weight_parameter: W::ValueParameter,
+}
+
+impl<W: VidpfValue, const NONCE_SIZE: usize> Vidpf<W, NONCE_SIZE> {
+ /// Creates a VIDPF instance.
+ ///
+ /// # Arguments
+ ///
+ /// * `weight_parameter`, any parameters required to instantiate a weight value.
+ pub const fn new(weight_parameter: W::ValueParameter) -> Self {
+ Self { weight_parameter }
+ }
+
+ /// The [`Vidpf::gen`] method splits an incremental point function `F` into two private keys
+ /// used by the aggregation servers, and a common public share.
+ ///
+ /// The incremental point function is defined as `F`: [`VidpfInput`] --> [`VidpfValue`]
+ /// such that:
+ ///
+ /// ```txt
+ /// F(x) = weight, if x is a prefix of the input.
+ /// F(x) = 0, if x is not a prefix of the input.
+ /// ```
+ ///
+ /// # Arguments
+ ///
+ /// * `input`, determines the input of the function.
+ /// * `weight`, determines the input's weight of the function.
+ /// * `nonce`, used to cryptographically bind some information.
+ pub fn gen(
+ &self,
+ input: &VidpfInput,
+ weight: &W,
+ nonce: &[u8; NONCE_SIZE],
+ ) -> Result<(VidpfPublicShare<W>, [VidpfKey; 2]), VidpfError> {
+ let keys = [
+ VidpfKey::gen(VidpfServerId::S0)?,
+ VidpfKey::gen(VidpfServerId::S1)?,
+ ];
+ let public = self.gen_with_keys(&keys, input, weight, nonce)?;
+ Ok((public, keys))
+ }
+
+ /// [`Vidpf::gen_with_keys`] works as the [`Vidpf::gen`] method, except that two different
+ /// keys must be provided.
+ fn gen_with_keys(
+ &self,
+ keys: &[VidpfKey; 2],
+ input: &VidpfInput,
+ weight: &W,
+ nonce: &[u8; NONCE_SIZE],
+ ) -> Result<VidpfPublicShare<W>, VidpfError> {
+ if keys[0].id == keys[1].id {
+ return Err(VidpfError::SameKeyId);
+ }
+
+ let mut s_i = [keys[0].value, keys[1].value];
+ let mut t_i = [Choice::from(keys[0].id), Choice::from(keys[1].id)];
+
+ let n = input.len();
+ let mut cw = Vec::with_capacity(n);
+ let mut cs = Vec::with_capacity(n);
+
+ for level in 0..n {
+ let alpha_i = Choice::from(u8::from(input.get(level).ok_or(VidpfError::IndexLevel)?));
+
+ // If alpha_i == 0 then
+ // (same_seed, diff_seed) = (right_seed, left_seed)
+ // else
+ // (same_seed, diff_seed) = (left_seed, right_seed)
+ let seq_0 = Self::prg(&s_i[0], nonce);
+ let (same_seed_0, diff_seed_0) = &mut (seq_0.right_seed, seq_0.left_seed);
+ conditional_swap_seed(same_seed_0, diff_seed_0, alpha_i);
+
+ let seq_1 = Self::prg(&s_i[1], nonce);
+ let (same_seed_1, diff_seed_1) = &mut (seq_1.right_seed, seq_1.left_seed);
+ conditional_swap_seed(same_seed_1, diff_seed_1, alpha_i);
+
+ // If alpha_i == 0 then
+ // diff_control_bit = left_control_bit
+ // else
+ // diff_control_bit = right_control_bit
+ let diff_control_bit_0 = Choice::conditional_select(
+ &seq_0.left_control_bit,
+ &seq_0.right_control_bit,
+ alpha_i,
+ );
+ let diff_control_bit_1 = Choice::conditional_select(
+ &seq_1.left_control_bit,
+ &seq_1.right_control_bit,
+ alpha_i,
+ );
+
+ let s_cw = xor_seeds(same_seed_0, same_seed_1);
+ let t_cw_l =
+ seq_0.left_control_bit ^ seq_1.left_control_bit ^ alpha_i ^ Choice::from(1);
+ let t_cw_r = seq_0.right_control_bit ^ seq_1.right_control_bit ^ alpha_i;
+ let t_cw_diff = Choice::conditional_select(&t_cw_l, &t_cw_r, alpha_i);
+
+ let s_tilde_i_0 = conditional_xor_seeds(diff_seed_0, &s_cw, t_i[0]);
+ let s_tilde_i_1 = conditional_xor_seeds(diff_seed_1, &s_cw, t_i[1]);
+
+ t_i[0] = diff_control_bit_0 ^ (t_i[0] & t_cw_diff);
+ t_i[1] = diff_control_bit_1 ^ (t_i[1] & t_cw_diff);
+
+ let w_i_0;
+ let w_i_1;
+ (s_i[0], w_i_0) = self.convert(s_tilde_i_0, nonce);
+ (s_i[1], w_i_1) = self.convert(s_tilde_i_1, nonce);
+
+ let mut w_cw = w_i_1 - w_i_0 + weight.clone();
+ w_cw.conditional_negate(t_i[1]);
+
+ let cw_i = VidpfCorrectionWord {
+ seed: s_cw,
+ left_control_bit: t_cw_l,
+ right_control_bit: t_cw_r,
+ weight: w_cw,
+ };
+ cw.push(cw_i);
+
+ let pi_tilde_0 = Self::node_proof(input, level, &s_i[0])?;
+ let pi_tilde_1 = Self::node_proof(input, level, &s_i[1])?;
+ let cs_i = xor_proof(pi_tilde_0, &pi_tilde_1);
+ cs.push(cs_i);
+ }
+
+ Ok(VidpfPublicShare { cw, cs })
+ }
+
+ /// [`Vidpf::eval`] evaluates the entire `input` and produces a share of the
+ /// input's weight.
+ pub fn eval(
+ &self,
+ key: &VidpfKey,
+ public: &VidpfPublicShare<W>,
+ input: &VidpfInput,
+ nonce: &[u8; NONCE_SIZE],
+ ) -> Result<VidpfValueShare<W>, VidpfError> {
+ let mut state = VidpfEvalState::init_from_key(key);
+ let mut share = W::zero(&self.weight_parameter);
+
+ let n = input.len();
+ for level in 0..n {
+ (state, share) = self.eval_next(key.id, public, input, level, &state, nonce)?;
+ }
+
+ Ok(VidpfValueShare {
+ share,
+ proof: state.proof,
+ })
+ }
+
+ /// [`Vidpf::eval_next`] evaluates the `input` at the given level using the provided initial
+ /// state, and returns a new state and a share of the input's weight at that level.
+ fn eval_next(
+ &self,
+ id: VidpfServerId,
+ public: &VidpfPublicShare<W>,
+ input: &VidpfInput,
+ level: usize,
+ state: &VidpfEvalState,
+ nonce: &[u8; NONCE_SIZE],
+ ) -> Result<(VidpfEvalState, W), VidpfError> {
+ let cw = public.cw.get(level).ok_or(VidpfError::IndexLevel)?;
+
+ let seq_tilde = Self::prg(&state.seed, nonce);
+
+ let t_i = state.control_bit;
+ let sl = conditional_xor_seeds(&seq_tilde.left_seed, &cw.seed, t_i);
+ let sr = conditional_xor_seeds(&seq_tilde.right_seed, &cw.seed, t_i);
+ let tl = seq_tilde.left_control_bit ^ (t_i & cw.left_control_bit);
+ let tr = seq_tilde.right_control_bit ^ (t_i & cw.right_control_bit);
+
+ let x_i = Choice::from(u8::from(input.get(level).ok_or(VidpfError::IndexLevel)?));
+ let s_tilde_i = conditional_select_seed(x_i, &[sl, sr]);
+
+ let next_control_bit = Choice::conditional_select(&tl, &tr, x_i);
+ let (next_seed, w_i) = self.convert(s_tilde_i, nonce);
+
+ let zero = <W as IdpfValue>::zero(&self.weight_parameter);
+ let mut y = <W as IdpfValue>::conditional_select(&zero, &cw.weight, next_control_bit);
+ y += w_i;
+ y.conditional_negate(Choice::from(id));
+
+ let pi_i = &state.proof;
+ let cs_i = public.cs.get(level).ok_or(VidpfError::IndexLevel)?;
+ let pi_tilde = Self::node_proof(input, level, &next_seed)?;
+ let h2_input = xor_proof(
+ conditional_xor_proof(pi_tilde, cs_i, next_control_bit),
+ pi_i,
+ );
+ let next_proof = xor_proof(Self::node_proof_adjustment(h2_input), pi_i);
+
+ let next_state = VidpfEvalState {
+ seed: next_seed,
+ control_bit: next_control_bit,
+ proof: next_proof,
+ };
+
+ Ok((next_state, y))
+ }
+
+ fn prg(seed: &VidpfSeed, nonce: &[u8]) -> VidpfPrgOutput {
+ let mut rng = XofFixedKeyAes128::seed_stream(&Seed(*seed), VidpfDomainSepTag::PRG, nonce);
+
+ let mut left_seed = VidpfSeed::default();
+ let mut right_seed = VidpfSeed::default();
+ rng.fill_bytes(&mut left_seed);
+ rng.fill_bytes(&mut right_seed);
+ // Use the LSB of seeds as control bits, and clears the bit,
+ // i.e., seeds produced by `prg` always have their LSB = 0.
+ // This ensures `prg` costs two AES calls only.
+ let left_control_bit = Choice::from(left_seed[0] & 0x01);
+ let right_control_bit = Choice::from(right_seed[0] & 0x01);
+ left_seed[0] &= 0xFE;
+ right_seed[0] &= 0xFE;
+
+ VidpfPrgOutput {
+ left_seed,
+ left_control_bit,
+ right_seed,
+ right_control_bit,
+ }
+ }
+
+ fn convert(&self, seed: VidpfSeed, nonce: &[u8; NONCE_SIZE]) -> (VidpfSeed, W) {
+ let mut rng =
+ XofFixedKeyAes128::seed_stream(&Seed(seed), VidpfDomainSepTag::CONVERT, nonce);
+
+ let mut out_seed = VidpfSeed::default();
+ rng.fill_bytes(&mut out_seed);
+ let value = <W as IdpfValue>::generate(&mut rng, &self.weight_parameter);
+
+ (out_seed, value)
+ }
+
+ fn node_proof(
+ input: &VidpfInput,
+ level: usize,
+ seed: &VidpfSeed,
+ ) -> Result<VidpfProof, VidpfError> {
+ let mut shake = XofTurboShake128::init(seed, VidpfDomainSepTag::NODE_PROOF);
+ for chunk128 in input
+ .index(..=level)
+ .chunks(128)
+ .map(BitField::load_le::<u128>)
+ .map(u128::to_le_bytes)
+ {
+ shake.update(&chunk128);
+ }
+ shake.update(
+ &u16::try_from(level)
+ .map_err(|_e| VidpfError::LevelTooBig)?
+ .to_le_bytes(),
+ );
+ let mut rng = shake.into_seed_stream();
+
+ let mut proof = VidpfProof::default();
+ rng.fill_bytes(&mut proof);
+
+ Ok(proof)
+ }
+
+ fn node_proof_adjustment(mut proof: VidpfProof) -> VidpfProof {
+ let mut rng = XofTurboShake128::seed_stream(
+ &Seed(Default::default()),
+ VidpfDomainSepTag::NODE_PROOF_ADJUST,
+ &proof,
+ );
+ rng.fill_bytes(&mut proof);
+
+ proof
+ }
+}
+
+/// Contains the domain separation tags for invoking different oracles.
+struct VidpfDomainSepTag;
+impl VidpfDomainSepTag {
+ const PRG: &'static [u8] = b"Prg";
+ const CONVERT: &'static [u8] = b"Convert";
+ const NODE_PROOF: &'static [u8] = b"NodeProof";
+ const NODE_PROOF_ADJUST: &'static [u8] = b"NodeProofAdjust";
+}
+
+/// Private key of an aggregation server.
+pub struct VidpfKey {
+ id: VidpfServerId,
+ value: [u8; 16],
+}
+
+impl VidpfKey {
+ /// Generates a key at random.
+ ///
+ /// # Errors
+ /// Triggers an error if the random generator fails.
+ pub(crate) fn gen(id: VidpfServerId) -> Result<Self, VidpfError> {
+ let mut value = [0; 16];
+ getrandom::getrandom(&mut value)?;
+ Ok(Self { id, value })
+ }
+}
+
+/// Identifies the two aggregation servers.
+#[derive(Clone, Copy, PartialEq, Eq)]
+pub(crate) enum VidpfServerId {
+ /// S0 is the first server.
+ S0,
+ /// S1 is the second server.
+ S1,
+}
+
+impl From<VidpfServerId> for Choice {
+ fn from(value: VidpfServerId) -> Self {
+ match value {
+ VidpfServerId::S0 => Self::from(0),
+ VidpfServerId::S1 => Self::from(1),
+ }
+ }
+}
+
+/// Adjusts values of shares during the VIDPF evaluation.
+#[derive(Debug)]
+struct VidpfCorrectionWord<W: VidpfValue> {
+ seed: VidpfSeed,
+ left_control_bit: Choice,
+ right_control_bit: Choice,
+ weight: W,
+}
+
+/// Common public information used by aggregation servers.
+#[derive(Debug)]
+pub struct VidpfPublicShare<W: VidpfValue> {
+ cw: Vec<VidpfCorrectionWord<W>>,
+ cs: Vec<VidpfProof>,
+}
+
+/// Contains the values produced during input evaluation at a given level.
+pub struct VidpfEvalState {
+ seed: VidpfSeed,
+ control_bit: Choice,
+ proof: VidpfProof,
+}
+
+impl VidpfEvalState {
+ fn init_from_key(key: &VidpfKey) -> Self {
+ Self {
+ seed: key.value,
+ control_bit: Choice::from(key.id),
+ proof: VidpfProof::default(),
+ }
+ }
+}
+
+/// Contains a share of the input's weight together with a proof for verification.
+pub struct VidpfValueShare<W: VidpfValue> {
+ /// Secret share of the input's weight.
+ pub share: W,
+ /// Proof used to verify the share.
+ pub proof: VidpfProof,
+}
+
+/// Proof size in bytes.
+const VIDPF_PROOF_SIZE: usize = 32;
+
+/// Allows to validate user input and shares after evaluation.
+type VidpfProof = [u8; VIDPF_PROOF_SIZE];
+
+fn xor_proof(mut lhs: VidpfProof, rhs: &VidpfProof) -> VidpfProof {
+ zip(&mut lhs, rhs).for_each(|(a, b)| a.bitxor_assign(b));
+ lhs
+}
+
+fn conditional_xor_proof(mut lhs: VidpfProof, rhs: &VidpfProof, choice: Choice) -> VidpfProof {
+ zip(&mut lhs, rhs).for_each(|(a, b)| a.conditional_assign(&a.bitxor(b), choice));
+ lhs
+}
+
+/// Feeds a pseudorandom generator during evaluation.
+type VidpfSeed = [u8; 16];
+
+/// Contains the seeds and control bits produced by [`Vidpf::prg`].
+struct VidpfPrgOutput {
+ left_seed: VidpfSeed,
+ left_control_bit: Choice,
+ right_seed: VidpfSeed,
+ right_control_bit: Choice,
+}
+
+/// Represents an array of field elements that implements the [`VidpfValue`] trait.
+#[derive(Debug, PartialEq, Eq, Clone)]
+pub struct VidpfWeight<F: FieldElement>(Vec<F>);
+
+impl<F: FieldElement> From<Vec<F>> for VidpfWeight<F> {
+ fn from(value: Vec<F>) -> Self {
+ Self(value)
+ }
+}
+
+impl<F: FieldElement> VidpfValue for VidpfWeight<F> {}
+
+impl<F: FieldElement> IdpfValue for VidpfWeight<F> {
+ /// The parameter determines the number of field elements in the vector.
+ type ValueParameter = usize;
+
+ fn generate<S: RngCore>(seed_stream: &mut S, length: &Self::ValueParameter) -> Self {
+ Self(
+ (0..*length)
+ .map(|_| <F as IdpfValue>::generate(seed_stream, &()))
+ .collect(),
+ )
+ }
+
+ fn zero(length: &Self::ValueParameter) -> Self {
+ Self((0..*length).map(|_| <F as IdpfValue>::zero(&())).collect())
+ }
+
+ /// Panics if weight lengths are different.
+ fn conditional_select(lhs: &Self, rhs: &Self, choice: Choice) -> Self {
+ assert_eq!(
+ lhs.0.len(),
+ rhs.0.len(),
+ "{}",
+ VidpfError::InvalidWeightLength
+ );
+
+ Self(
+ zip(&lhs.0, &rhs.0)
+ .map(|(a, b)| <F as IdpfValue>::conditional_select(a, b, choice))
+ .collect(),
+ )
+ }
+}
+
+impl<F: FieldElement> ConditionallyNegatable for VidpfWeight<F> {
+ fn conditional_negate(&mut self, choice: Choice) {
+ self.0.iter_mut().for_each(|a| a.conditional_negate(choice));
+ }
+}
+
+impl<F: FieldElement> Add for VidpfWeight<F> {
+ type Output = Self;
+
+ /// Panics if weight lengths are different.
+ fn add(self, rhs: Self) -> Self::Output {
+ assert_eq!(
+ self.0.len(),
+ rhs.0.len(),
+ "{}",
+ VidpfError::InvalidWeightLength
+ );
+
+ Self(zip(self.0, rhs.0).map(|(a, b)| a.add(b)).collect())
+ }
+}
+
+impl<F: FieldElement> AddAssign for VidpfWeight<F> {
+ /// Panics if weight lengths are different.
+ fn add_assign(&mut self, rhs: Self) {
+ assert_eq!(
+ self.0.len(),
+ rhs.0.len(),
+ "{}",
+ VidpfError::InvalidWeightLength
+ );
+
+ zip(&mut self.0, rhs.0).for_each(|(a, b)| a.add_assign(b));
+ }
+}
+
+impl<F: FieldElement> Sub for VidpfWeight<F> {
+ type Output = Self;
+
+ /// Panics if weight lengths are different.
+ fn sub(self, rhs: Self) -> Self::Output {
+ assert_eq!(
+ self.0.len(),
+ rhs.0.len(),
+ "{}",
+ VidpfError::InvalidWeightLength
+ );
+
+ Self(zip(self.0, rhs.0).map(|(a, b)| a.sub(b)).collect())
+ }
+}
+
+impl<F: FieldElement> Encode for VidpfWeight<F> {
+ fn encode(&self, bytes: &mut Vec<u8>) -> Result<(), CodecError> {
+ for e in &self.0 {
+ F::encode(e, bytes)?;
+ }
+ Ok(())
+ }
+
+ fn encoded_len(&self) -> Option<usize> {
+ Some(self.0.len() * F::ENCODED_SIZE)
+ }
+}
+
+impl<F: FieldElement> ParameterizedDecode<<Self as IdpfValue>::ValueParameter> for VidpfWeight<F> {
+ fn decode_with_param(
+ decoding_parameter: &<Self as IdpfValue>::ValueParameter,
+ bytes: &mut Cursor<&[u8]>,
+ ) -> Result<Self, CodecError> {
+ let mut v = Vec::with_capacity(*decoding_parameter);
+ for _ in 0..*decoding_parameter {
+ v.push(F::decode_with_param(&(), bytes)?);
+ }
+
+ Ok(Self(v))
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use crate::field::Field128;
+
+ use super::VidpfWeight;
+
+ type TestWeight = VidpfWeight<Field128>;
+ const TEST_WEIGHT_LEN: usize = 3;
+ const TEST_NONCE_SIZE: usize = 16;
+ const TEST_NONCE: &[u8; TEST_NONCE_SIZE] = b"Test Nonce VIDPF";
+
+ mod vidpf {
+ use crate::{
+ idpf::IdpfValue,
+ vidpf::{
+ Vidpf, VidpfError, VidpfEvalState, VidpfInput, VidpfKey, VidpfPublicShare,
+ VidpfServerId,
+ },
+ };
+
+ use super::{TestWeight, TEST_NONCE, TEST_NONCE_SIZE, TEST_WEIGHT_LEN};
+
+ fn vidpf_gen_setup(
+ input: &VidpfInput,
+ weight: &TestWeight,
+ ) -> (
+ Vidpf<TestWeight, TEST_NONCE_SIZE>,
+ VidpfPublicShare<TestWeight>,
+ [VidpfKey; 2],
+ [u8; TEST_NONCE_SIZE],
+ ) {
+ let vidpf = Vidpf::new(TEST_WEIGHT_LEN);
+ let (public, keys) = vidpf.gen(input, weight, TEST_NONCE).unwrap();
+ (vidpf, public, keys, *TEST_NONCE)
+ }
+
+ #[test]
+ fn gen_with_keys() {
+ let input = VidpfInput::from_bytes(&[0xFF]);
+ let weight = TestWeight::from(vec![21.into(), 22.into(), 23.into()]);
+ let vidpf = Vidpf::new(TEST_WEIGHT_LEN);
+ let keys_with_same_id = [
+ VidpfKey::gen(VidpfServerId::S0).unwrap(),
+ VidpfKey::gen(VidpfServerId::S0).unwrap(),
+ ];
+
+ let err = vidpf
+ .gen_with_keys(&keys_with_same_id, &input, &weight, TEST_NONCE)
+ .unwrap_err();
+
+ assert_eq!(err.to_string(), VidpfError::SameKeyId.to_string());
+ }
+
+ #[test]
+ fn correctness_at_last_level() {
+ let input = VidpfInput::from_bytes(&[0xFF]);
+ let weight = TestWeight::from(vec![21.into(), 22.into(), 23.into()]);
+ let (vidpf, public, [key_0, key_1], nonce) = vidpf_gen_setup(&input, &weight);
+
+ let value_share_0 = vidpf.eval(&key_0, &public, &input, &nonce).unwrap();
+ let value_share_1 = vidpf.eval(&key_1, &public, &input, &nonce).unwrap();
+
+ assert_eq!(
+ value_share_0.share + value_share_1.share,
+ weight,
+ "shares must add up to the expected weight",
+ );
+
+ assert_eq!(
+ value_share_0.proof, value_share_1.proof,
+ "proofs must be equal"
+ );
+
+ let bad_input = VidpfInput::from_bytes(&[0x00]);
+ let zero = TestWeight::zero(&TEST_WEIGHT_LEN);
+ let value_share_0 = vidpf.eval(&key_0, &public, &bad_input, &nonce).unwrap();
+ let value_share_1 = vidpf.eval(&key_1, &public, &bad_input, &nonce).unwrap();
+
+ assert_eq!(
+ value_share_0.share + value_share_1.share,
+ zero,
+ "shares must add up to zero",
+ );
+
+ assert_eq!(
+ value_share_0.proof, value_share_1.proof,
+ "proofs must be equal"
+ );
+ }
+
+ #[test]
+ fn correctness_at_each_level() {
+ let input = VidpfInput::from_bytes(&[0xFF]);
+ let weight = TestWeight::from(vec![21.into(), 22.into(), 23.into()]);
+ let (vidpf, public, keys, nonce) = vidpf_gen_setup(&input, &weight);
+
+ assert_eval_at_each_level(&vidpf, &keys, &public, &input, &weight, &nonce);
+
+ let bad_input = VidpfInput::from_bytes(&[0x00]);
+ let zero = TestWeight::zero(&TEST_WEIGHT_LEN);
+
+ assert_eval_at_each_level(&vidpf, &keys, &public, &bad_input, &zero, &nonce);
+ }
+
+ fn assert_eval_at_each_level(
+ vidpf: &Vidpf<TestWeight, TEST_NONCE_SIZE>,
+ [key_0, key_1]: &[VidpfKey; 2],
+ public: &VidpfPublicShare<TestWeight>,
+ input: &VidpfInput,
+ weight: &TestWeight,
+ nonce: &[u8; TEST_NONCE_SIZE],
+ ) {
+ let mut state_0 = VidpfEvalState::init_from_key(key_0);
+ let mut state_1 = VidpfEvalState::init_from_key(key_1);
+
+ let n = input.len();
+ for level in 0..n {
+ let share_0;
+ let share_1;
+ (state_0, share_0) = vidpf
+ .eval_next(key_0.id, public, input, level, &state_0, nonce)
+ .unwrap();
+ (state_1, share_1) = vidpf
+ .eval_next(key_1.id, public, input, level, &state_1, nonce)
+ .unwrap();
+
+ assert_eq!(
+ share_0 + share_1,
+ *weight,
+ "shares must add up to the expected weight at the current level: {:?}",
+ level
+ );
+
+ assert_eq!(
+ state_0.proof, state_1.proof,
+ "proofs must be equal at the current level: {:?}",
+ level
+ );
+ }
+ }
+ }
+
+ mod weight {
+ use std::io::Cursor;
+ use subtle::{Choice, ConditionallyNegatable};
+
+ use crate::{
+ codec::{Encode, ParameterizedDecode},
+ idpf::IdpfValue,
+ vdaf::xof::{Seed, Xof, XofTurboShake128},
+ };
+
+ use super::{TestWeight, TEST_WEIGHT_LEN};
+
+ #[test]
+ fn roundtrip_codec() {
+ let weight = TestWeight::from(vec![21.into(), 22.into(), 23.into()]);
+
+ let mut bytes = vec![];
+ weight.encode(&mut bytes).unwrap();
+
+ let expected_bytes = [
+ [vec![21], vec![0u8; 15]].concat(),
+ [vec![22], vec![0u8; 15]].concat(),
+ [vec![23], vec![0u8; 15]].concat(),
+ ]
+ .concat();
+
+ assert_eq!(weight.encoded_len().unwrap(), expected_bytes.len());
+ // Check endianness of encoding
+ assert_eq!(bytes, expected_bytes);
+
+ let decoded =
+ TestWeight::decode_with_param(&TEST_WEIGHT_LEN, &mut Cursor::new(&bytes)).unwrap();
+ assert_eq!(weight, decoded);
+ }
+
+ #[test]
+ fn add_sub() {
+ let [a, b] = compatible_weights();
+ let mut c = a.clone();
+ c += a.clone();
+
+ assert_eq!(
+ (a.clone() + b.clone()) + (a.clone() - b.clone()),
+ c,
+ "a: {:?} b:{:?}",
+ a,
+ b
+ );
+ }
+
+ #[test]
+ fn conditional_negate() {
+ let [a, _] = compatible_weights();
+ let mut c = a.clone();
+ c.conditional_negate(Choice::from(0));
+ let mut d = a.clone();
+ d.conditional_negate(Choice::from(1));
+ let zero = TestWeight::zero(&TEST_WEIGHT_LEN);
+
+ assert_eq!(c + d, zero, "a: {:?}", a);
+ }
+
+ #[test]
+ #[should_panic = "invalid weight length"]
+ fn add_panics() {
+ let [w0, w1] = incompatible_weights();
+ let _ = w0 + w1;
+ }
+
+ #[test]
+ #[should_panic = "invalid weight length"]
+ fn add_assign_panics() {
+ let [mut w0, w1] = incompatible_weights();
+ w0 += w1;
+ }
+
+ #[test]
+ #[should_panic = "invalid weight length"]
+ fn sub_panics() {
+ let [w0, w1] = incompatible_weights();
+ let _ = w0 - w1;
+ }
+
+ #[test]
+ #[should_panic = "invalid weight length"]
+ fn conditional_select_panics() {
+ let [w0, w1] = incompatible_weights();
+ TestWeight::conditional_select(&w0, &w1, Choice::from(0));
+ }
+
+ fn compatible_weights() -> [TestWeight; 2] {
+ let mut xof = XofTurboShake128::seed_stream(&Seed(Default::default()), &[], &[]);
+ [
+ TestWeight::generate(&mut xof, &TEST_WEIGHT_LEN),
+ TestWeight::generate(&mut xof, &TEST_WEIGHT_LEN),
+ ]
+ }
+
+ fn incompatible_weights() -> [TestWeight; 2] {
+ let mut xof = XofTurboShake128::seed_stream(&Seed(Default::default()), &[], &[]);
+ [
+ TestWeight::generate(&mut xof, &TEST_WEIGHT_LEN),
+ TestWeight::generate(&mut xof, &(2 * TEST_WEIGHT_LEN)),
+ ]
+ }
+ }
+}