Skip to content

Commit

Permalink
Added Aggregator::is_agg_param_valid method (#1139)
Browse files Browse the repository at this point in the history
* Added Aggregator::is_agg_param_valid method, representing the is_valid method in the spec

Co-authored-by: Michael Rosenberg <[email protected]>
Co-authored-by: David Cook <[email protected]>
  • Loading branch information
3 people authored Nov 15, 2024
1 parent d5e9b15 commit d57731b
Show file tree
Hide file tree
Showing 5 changed files with 104 additions and 0 deletions.
5 changes: 5 additions & 0 deletions src/vdaf.rs
Original file line number Diff line number Diff line change
Expand Up @@ -298,6 +298,11 @@ pub trait Aggregator<const VERIFY_KEY_SIZE: usize, const NONCE_SIZE: usize>: Vda
agg_param: &Self::AggregationParam,
output_shares: M,
) -> Result<Self::AggregateShare, VdafError>;

/// Validates an aggregation parameter with respect to all previous aggregaiton parameters used
/// for the same input share. `prev` MUST be sorted from least to most recently used.
#[must_use]
fn is_agg_param_valid(cur: &Self::AggregationParam, prev: &[Self::AggregationParam]) -> bool;
}

/// Aggregator that implements differential privacy with Aggregator-side noise addition.
Expand Down
4 changes: 4 additions & 0 deletions src/vdaf/dummy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,10 @@ impl vdaf::Aggregator<0, 16> for Vdaf {
}
Ok(aggregate_share)
}

fn is_agg_param_valid(_cur: &Self::AggregationParam, _prev: &[Self::AggregationParam]) -> bool {
true
}
}

impl vdaf::Client<16> for Vdaf {
Expand Down
85 changes: 85 additions & 0 deletions src/vdaf/poplar1.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ use crate::{
use bitvec::{prelude::Lsb0, vec::BitVec};
use rand_core::RngCore;
use std::{
collections::BTreeSet,
convert::TryFrom,
fmt::Debug,
io::{Cursor, Read},
Expand Down Expand Up @@ -1245,6 +1246,39 @@ impl<P: Xof<SEED_SIZE>, const SEED_SIZE: usize> Aggregator<SEED_SIZE, 16>
output_shares,
)
}

/// Validates that no aggregation parameter with the same level as `cur` has been used with the
/// same input share before. `prev` contains the aggregation parameters used for the same input.
/// `prev` MUST be sorted from least to most recently used.
fn is_agg_param_valid(cur: &Poplar1AggregationParam, prev: &[Poplar1AggregationParam]) -> bool {
// Exit early if there are no previous aggregation params to compare to, i.e., this is the
// first time the input share has been processed
if prev.is_empty() {
return true;
}

// Unpack this agg param and the last one in the list
let Poplar1AggregationParam {
level: cur_level,
prefixes: cur_prefixes,
} = cur;
let Poplar1AggregationParam {
level: last_level,
prefixes: last_prefixes,
} = prev.last().as_ref().unwrap();
let last_prefixes_set = BTreeSet::from_iter(last_prefixes);

// Check that the level increased.
if cur_level <= last_level {
return false;
}

// Check that current prefixes are extensions of the last level's prefixes.
cur_prefixes.iter().all(|cur_prefix| {
let last_prefix = cur_prefix.prefix(*last_level as usize);
last_prefixes_set.contains(&last_prefix)
})
}
}

impl<P: Xof<SEED_SIZE>, const SEED_SIZE: usize> Collector for Poplar1<P, SEED_SIZE> {
Expand Down Expand Up @@ -1979,6 +2013,57 @@ mod tests {
assert_matches!(err, CodecError::Other(_));
}

// Tests Poplar1::is_valid() functionality. This unit test is translated from
// https://github.com/cfrg/draft-irtf-cfrg-vdaf/blob/a4874547794818573acd8734874c9784043b1140/poc/tests/test_vdaf_poplar1.py#L187
#[test]
fn agg_param_validity() {
// The actual Poplar instance doesn't matter for the parameter validity tests
type V = Poplar1<XofTurboShake128, 16>;

// Helper function for making aggregation params
fn make_agg_param(bitstrings: &[&[u8]]) -> Result<Poplar1AggregationParam, VdafError> {
Poplar1AggregationParam::try_from_prefixes(
bitstrings
.iter()
.map(|v| {
let bools = v.iter().map(|&b| b != 0).collect::<Vec<_>>();
IdpfInput::from_bools(&bools)
})
.collect(),
)
}

// Test `is_valid` returns False on repeated levels, and True otherwise.
let agg_params = [
make_agg_param(&[&[0], &[1]]).unwrap(),
make_agg_param(&[&[0, 0]]).unwrap(),
make_agg_param(&[&[0, 0], &[1, 0]]).unwrap(),
];
assert!(V::is_agg_param_valid(&agg_params[0], &[]));
assert!(V::is_agg_param_valid(&agg_params[1], &agg_params[..1]));
assert!(!V::is_agg_param_valid(&agg_params[2], &agg_params[..2]));

// Test `is_valid` accepts level jumps.
let agg_params = [
make_agg_param(&[&[0], &[1]]).unwrap(),
make_agg_param(&[&[0, 1, 0], &[0, 1, 1], &[1, 0, 1], &[1, 1, 1]]).unwrap(),
];
assert!(V::is_agg_param_valid(&agg_params[1], &agg_params[..1]));

// Test `is_valid` rejects unconnected prefixes.
let agg_params = [
make_agg_param(&[&[0]]).unwrap(),
make_agg_param(&[&[0, 1, 0], &[0, 1, 1], &[1, 0, 1], &[1, 1, 1]]).unwrap(),
];
assert!(!V::is_agg_param_valid(&agg_params[1], &agg_params[..1]));

// Test that the `Poplar1AggregationParam` constructor rejects unsorted and duplicate
// prefixes.
assert!(make_agg_param(&[&[1], &[0]]).is_err());
assert!(make_agg_param(&[&[1, 0, 0], &[0, 1, 1]]).is_err());
assert!(make_agg_param(&[&[0, 0, 0], &[0, 1, 0], &[0, 1, 0]]).is_err());
}

#[derive(Debug, Deserialize)]
struct HexEncoded(#[serde(with = "hex")] Vec<u8>);

Expand Down
5 changes: 5 additions & 0 deletions src/vdaf/prio2.rs
Original file line number Diff line number Diff line change
Expand Up @@ -325,6 +325,11 @@ impl Aggregator<32, 16> for Prio2 {

Ok(agg_share)
}

/// Returns `true` iff `prev.is_empty()`
fn is_agg_param_valid(_cur: &Self::AggregationParam, prev: &[Self::AggregationParam]) -> bool {
prev.is_empty()
}
}

impl Collector for Prio2 {
Expand Down
5 changes: 5 additions & 0 deletions src/vdaf/prio3.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1441,6 +1441,11 @@ where

Ok(agg_share)
}

/// Returns `true` iff `prev.is_empty()`
fn is_agg_param_valid(_cur: &Self::AggregationParam, prev: &[Self::AggregationParam]) -> bool {
prev.is_empty()
}
}

#[cfg(feature = "experimental")]
Expand Down

0 comments on commit d57731b

Please sign in to comment.