Skip to content

Commit

Permalink
Add discrete Laplace noise w/ SumVec and Histogram (#3302)
Browse files Browse the repository at this point in the history
* Add discrete Laplace noise w/ SumVec and Histogram

* Add smoke tests to check that noise is added

* Add aggregator API feature
  • Loading branch information
divergentdave authored Jul 23, 2024
1 parent 2f8ed33 commit 3eab5d4
Show file tree
Hide file tree
Showing 17 changed files with 698 additions and 101 deletions.
177 changes: 141 additions & 36 deletions aggregator/src/aggregator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -926,55 +926,80 @@ impl<C: Clock> TaskAggregator<C> {
bits,
length,
chunk_length,
dp_strategy,
} => {
let vdaf = Prio3::new_sum_vec(2, *bits, *length, *chunk_length)?;
let verify_key = task.vdaf_verify_key()?;
VdafOps::Prio3SumVec(Arc::new(vdaf), verify_key)
VdafOps::Prio3SumVec(
Arc::new(vdaf),
verify_key,
vdaf_ops_strategies::Prio3SumVec::from_vdaf_dp_strategy(dp_strategy.clone()),
)
}

VdafInstance::Prio3SumVecField64MultiproofHmacSha256Aes128 {
proofs,
bits,
length,
chunk_length,
dp_strategy,
} => {
let vdaf = new_prio3_sum_vec_field64_multiproof_hmacsha256_aes128::<
ParallelSum<Field64, Mul<Field64>>,
>(*proofs, *bits, *length, *chunk_length)?;
let verify_key = task.vdaf_verify_key()?;
VdafOps::Prio3SumVecField64MultiproofHmacSha256Aes128(Arc::new(vdaf), verify_key)
VdafOps::Prio3SumVecField64MultiproofHmacSha256Aes128(
Arc::new(vdaf),
verify_key,
vdaf_ops_strategies::Prio3SumVec::from_vdaf_dp_strategy(dp_strategy.clone()),
)
}

VdafInstance::Prio3Histogram {
length,
chunk_length,
dp_strategy,
} => {
let vdaf = Prio3::new_histogram(2, *length, *chunk_length)?;
let verify_key = task.vdaf_verify_key()?;
VdafOps::Prio3Histogram(Arc::new(vdaf), verify_key)
VdafOps::Prio3Histogram(
Arc::new(vdaf),
verify_key,
vdaf_ops_strategies::Prio3Histogram::from_vdaf_dp_strategy(dp_strategy.clone()),
)
}

#[cfg(feature = "fpvec_bounded_l2")]
VdafInstance::Prio3FixedPointBoundedL2VecSum {
bitsize,
dp_strategy,
length,
} => {
match bitsize {
Prio3FixedPointBoundedL2VecSumBitSize::BitSize16 => {
let vdaf: Prio3FixedPointBoundedL2VecSum<FixedI16<U15>> =
Prio3::new_fixedpoint_boundedl2_vec_sum(2, *length)?;
let verify_key = task.vdaf_verify_key()?;
VdafOps::Prio3FixedPoint16BitBoundedL2VecSum(Arc::new(vdaf), verify_key, vdaf_ops_strategies::Prio3FixedPointBoundedL2VecSum::from_vdaf_dp_strategy(dp_strategy.clone()))
}
Prio3FixedPointBoundedL2VecSumBitSize::BitSize32 => {
let vdaf: Prio3FixedPointBoundedL2VecSum<FixedI32<U31>> =
Prio3::new_fixedpoint_boundedl2_vec_sum(2, *length)?;
let verify_key = task.vdaf_verify_key()?;
VdafOps::Prio3FixedPoint32BitBoundedL2VecSum(Arc::new(vdaf), verify_key, vdaf_ops_strategies::Prio3FixedPointBoundedL2VecSum::from_vdaf_dp_strategy(dp_strategy.clone()))
}
} => match bitsize {
Prio3FixedPointBoundedL2VecSumBitSize::BitSize16 => {
let vdaf: Prio3FixedPointBoundedL2VecSum<FixedI16<U15>> =
Prio3::new_fixedpoint_boundedl2_vec_sum(2, *length)?;
let verify_key = task.vdaf_verify_key()?;
VdafOps::Prio3FixedPoint16BitBoundedL2VecSum(
Arc::new(vdaf),
verify_key,
vdaf_ops_strategies::Prio3FixedPointBoundedL2VecSum::from_vdaf_dp_strategy(
dp_strategy.clone(),
),
)
}
}
Prio3FixedPointBoundedL2VecSumBitSize::BitSize32 => {
let vdaf: Prio3FixedPointBoundedL2VecSum<FixedI32<U31>> =
Prio3::new_fixedpoint_boundedl2_vec_sum(2, *length)?;
let verify_key = task.vdaf_verify_key()?;
VdafOps::Prio3FixedPoint32BitBoundedL2VecSum(
Arc::new(vdaf),
verify_key,
vdaf_ops_strategies::Prio3FixedPointBoundedL2VecSum::from_vdaf_dp_strategy(
dp_strategy.clone(),
),
)
}
},

VdafInstance::Poplar1 { bits } => {
let vdaf = Poplar1::new_turboshake128(*bits);
Expand Down Expand Up @@ -1165,19 +1190,60 @@ impl<C: Clock> TaskAggregator<C> {
}
}

#[cfg(feature = "fpvec_bounded_l2")]
mod vdaf_ops_strategies {
use std::sync::Arc;

use janus_core::vdaf::vdaf_dp_strategies;
use prio::dp::distributions::PureDpDiscreteLaplace;
#[cfg(feature = "fpvec_bounded_l2")]
use prio::dp::distributions::ZCdpDiscreteGaussian;

#[derive(Debug)]
pub enum Prio3Histogram {
NoDifferentialPrivacy,
PureDpDiscreteLaplace(Arc<PureDpDiscreteLaplace>),
}

impl Prio3Histogram {
pub fn from_vdaf_dp_strategy(dp_strategy: vdaf_dp_strategies::Prio3Histogram) -> Self {
match dp_strategy {
vdaf_dp_strategies::Prio3Histogram::NoDifferentialPrivacy => {
Prio3Histogram::NoDifferentialPrivacy
}
vdaf_dp_strategies::Prio3Histogram::PureDpDiscreteLaplace(s) => {
Prio3Histogram::PureDpDiscreteLaplace(Arc::new(s))
}
}
}
}

#[derive(Debug)]
pub enum Prio3SumVec {
NoDifferentialPrivacy,
PureDpDiscreteLaplace(Arc<PureDpDiscreteLaplace>),
}

impl Prio3SumVec {
pub fn from_vdaf_dp_strategy(dp_strategy: vdaf_dp_strategies::Prio3SumVec) -> Self {
match dp_strategy {
vdaf_dp_strategies::Prio3SumVec::NoDifferentialPrivacy => {
Prio3SumVec::NoDifferentialPrivacy
}
vdaf_dp_strategies::Prio3SumVec::PureDpDiscreteLaplace(s) => {
Prio3SumVec::PureDpDiscreteLaplace(Arc::new(s))
}
}
}
}

#[cfg(feature = "fpvec_bounded_l2")]
#[derive(Debug)]
pub enum Prio3FixedPointBoundedL2VecSum {
NoDifferentialPrivacy,
ZCdpDiscreteGaussian(Arc<ZCdpDiscreteGaussian>),
}

#[cfg(feature = "fpvec_bounded_l2")]
impl Prio3FixedPointBoundedL2VecSum {
pub fn from_vdaf_dp_strategy(
dp_strategy: vdaf_dp_strategies::Prio3FixedPointBoundedL2VecSum,
Expand All @@ -1200,12 +1266,21 @@ mod vdaf_ops_strategies {
enum VdafOps {
Prio3Count(Arc<Prio3Count>, VerifyKey<VERIFY_KEY_LENGTH>),
Prio3Sum(Arc<Prio3Sum>, VerifyKey<VERIFY_KEY_LENGTH>),
Prio3SumVec(Arc<Prio3SumVec>, VerifyKey<VERIFY_KEY_LENGTH>),
Prio3SumVec(
Arc<Prio3SumVec>,
VerifyKey<VERIFY_KEY_LENGTH>,
vdaf_ops_strategies::Prio3SumVec,
),
Prio3SumVecField64MultiproofHmacSha256Aes128(
Arc<Prio3SumVecField64MultiproofHmacSha256Aes128<ParallelSum<Field64, Mul<Field64>>>>,
VerifyKey<32>,
vdaf_ops_strategies::Prio3SumVec,
),
Prio3Histogram(
Arc<Prio3Histogram>,
VerifyKey<VERIFY_KEY_LENGTH>,
vdaf_ops_strategies::Prio3Histogram,
),
Prio3Histogram(Arc<Prio3Histogram>, VerifyKey<VERIFY_KEY_LENGTH>),
#[cfg(feature = "fpvec_bounded_l2")]
Prio3FixedPoint16BitBoundedL2VecSum(
Arc<Prio3FixedPointBoundedL2VecSum<FixedI16<U15>>>,
Expand Down Expand Up @@ -1256,18 +1331,28 @@ macro_rules! vdaf_ops_dispatch {
body
}

crate::aggregator::VdafOps::Prio3SumVec(vdaf, verify_key) => {
crate::aggregator::VdafOps::Prio3SumVec(vdaf, verify_key, _dp_strategy) => {
let $vdaf = vdaf;
let $verify_key = verify_key;
type $Vdaf = ::prio::vdaf::prio3::Prio3SumVec;
const $VERIFY_KEY_LENGTH: usize = ::janus_core::vdaf::VERIFY_KEY_LENGTH;
type $DpStrategy = janus_core::dp::NoDifferentialPrivacy;
let $dp_strategy = &Arc::new(janus_core::dp::NoDifferentialPrivacy);
let body = $body;
body
match _dp_strategy {
vdaf_ops_strategies::Prio3SumVec::NoDifferentialPrivacy => {
type $DpStrategy = janus_core::dp::NoDifferentialPrivacy;
let $dp_strategy = &Arc::new(janus_core::dp::NoDifferentialPrivacy);
let body = $body;
body
}
vdaf_ops_strategies::Prio3SumVec::PureDpDiscreteLaplace(_strategy) => {
type $DpStrategy = ::prio::dp::distributions::PureDpDiscreteLaplace;
let $dp_strategy = &_strategy;
let body = $body;
body
}
}
}

crate::aggregator::VdafOps::Prio3SumVecField64MultiproofHmacSha256Aes128(vdaf, verify_key) => {
crate::aggregator::VdafOps::Prio3SumVecField64MultiproofHmacSha256Aes128(vdaf, verify_key, _dp_strategy) => {
let $vdaf = vdaf;
let $verify_key = verify_key;
type $Vdaf = ::janus_core::vdaf::Prio3SumVecField64MultiproofHmacSha256Aes128<
Expand All @@ -1277,21 +1362,41 @@ macro_rules! vdaf_ops_dispatch {
>,
>;
const $VERIFY_KEY_LENGTH: usize = 32;
type $DpStrategy = janus_core::dp::NoDifferentialPrivacy;
let $dp_strategy = &Arc::new(janus_core::dp::NoDifferentialPrivacy);
let body = $body;
body
match _dp_strategy {
vdaf_ops_strategies::Prio3SumVec::NoDifferentialPrivacy => {
type $DpStrategy = janus_core::dp::NoDifferentialPrivacy;
let $dp_strategy = &Arc::new(janus_core::dp::NoDifferentialPrivacy);
let body = $body;
body
}
vdaf_ops_strategies::Prio3SumVec::PureDpDiscreteLaplace(_strategy) => {
type $DpStrategy = ::prio::dp::distributions::PureDpDiscreteLaplace;
let $dp_strategy = &_strategy;
let body = $body;
body
}
}
}

crate::aggregator::VdafOps::Prio3Histogram(vdaf, verify_key) => {
crate::aggregator::VdafOps::Prio3Histogram(vdaf, verify_key, _dp_strategy) => {
let $vdaf = vdaf;
let $verify_key = verify_key;
type $Vdaf = ::prio::vdaf::prio3::Prio3Histogram;
const $VERIFY_KEY_LENGTH: usize = ::janus_core::vdaf::VERIFY_KEY_LENGTH;
type $DpStrategy = janus_core::dp::NoDifferentialPrivacy;
let $dp_strategy = &Arc::new(janus_core::dp::NoDifferentialPrivacy);
let body = $body;
body
match _dp_strategy {
vdaf_ops_strategies::Prio3Histogram::NoDifferentialPrivacy => {
type $DpStrategy = janus_core::dp::NoDifferentialPrivacy;
let $dp_strategy = &Arc::new(janus_core::dp::NoDifferentialPrivacy);
let body = $body;
body
}
vdaf_ops_strategies::Prio3Histogram::PureDpDiscreteLaplace(_strategy) => {
type $DpStrategy = ::prio::dp::distributions::PureDpDiscreteLaplace;
let $dp_strategy = &_strategy;
let body = $body;
body
}
}
}

#[cfg(feature = "fpvec_bounded_l2")]
Expand Down
6 changes: 6 additions & 0 deletions aggregator/src/aggregator/aggregation_job_creator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -321,6 +321,7 @@ impl<C: Clock + 'static> AggregationJobCreator<C> {
bits,
length,
chunk_length,
dp_strategy: _,
},
) => {
let vdaf = Arc::new(Prio3::new_sum_vec(2, *bits, *length, *chunk_length)?);
Expand All @@ -335,6 +336,7 @@ impl<C: Clock + 'static> AggregationJobCreator<C> {
bits,
length,
chunk_length,
dp_strategy: _,
},
) => {
let vdaf = Arc::new(new_prio3_sum_vec_field64_multiproof_hmacsha256_aes128::<
Expand All @@ -351,6 +353,7 @@ impl<C: Clock + 'static> AggregationJobCreator<C> {
VdafInstance::Prio3Histogram {
length,
chunk_length,
dp_strategy: _,
},
) => {
let vdaf = Arc::new(Prio3::new_histogram(2, *length, *chunk_length)?);
Expand Down Expand Up @@ -431,6 +434,7 @@ impl<C: Clock + 'static> AggregationJobCreator<C> {
bits,
length,
chunk_length,
dp_strategy: _,
},
) => {
let vdaf = Arc::new(Prio3::new_sum_vec(2, *bits, *length, *chunk_length)?);
Expand All @@ -452,6 +456,7 @@ impl<C: Clock + 'static> AggregationJobCreator<C> {
bits,
length,
chunk_length,
dp_strategy: _,
},
) => {
let vdaf = Arc::new(new_prio3_sum_vec_field64_multiproof_hmacsha256_aes128::<
Expand All @@ -473,6 +478,7 @@ impl<C: Clock + 'static> AggregationJobCreator<C> {
VdafInstance::Prio3Histogram {
length,
chunk_length,
dp_strategy: _,
},
) => {
let vdaf = Arc::new(Prio3::new_histogram(2, *length, *chunk_length)?);
Expand Down
3 changes: 3 additions & 0 deletions aggregator/src/aggregator/aggregation_job_writer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -699,6 +699,7 @@ where
bits,
length,
chunk_length: _,
dp_strategy: _,
} => {
metrics.aggregated_report_share_dimension_histogram.record(
u64::try_from(*bits)
Expand All @@ -715,6 +716,7 @@ where
bits,
length,
chunk_length: _,
dp_strategy: _,
} => {
metrics.aggregated_report_share_dimension_histogram.record(
u64::try_from(*bits)
Expand All @@ -732,6 +734,7 @@ where
Prio3Histogram {
length,
chunk_length: _,
dp_strategy: _,
} => {
metrics.aggregated_report_share_dimension_histogram.record(
u64::try_from(*length).unwrap_or(u64::MAX),
Expand Down
3 changes: 2 additions & 1 deletion aggregator/src/binaries/janus_cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -760,7 +760,7 @@ mod tests {
hpke::HpkeKeypair,
test_util::{kubernetes, roundtrip_encoding},
time::RealClock,
vdaf::VdafInstance,
vdaf::{vdaf_dp_strategies, VdafInstance},
};
use janus_messages::{
codec::Encode, Duration, HpkeAeadId, HpkeConfig, HpkeConfigId, HpkeKdfId, HpkeKemId, Role,
Expand Down Expand Up @@ -1296,6 +1296,7 @@ mod tests {
bits: 1,
length: 4,
chunk_length: 2,
dp_strategy: vdaf_dp_strategies::Prio3SumVec::NoDifferentialPrivacy,
},
)
.with_id(*tasks[0].id())
Expand Down
7 changes: 6 additions & 1 deletion aggregator_api/src/routes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,12 @@ pub(super) async fn get_config(
SupportedQueryType::TimeInterval,
SupportedQueryType::FixedSize,
],
features: &["TokenHash", "UploadMetrics", "TimeBucketedFixedSize"],
features: &[
"TokenHash",
"UploadMetrics",
"TimeBucketedFixedSize",
"PureDpDiscreteLaplace",
],
})
}

Expand Down
Loading

0 comments on commit 3eab5d4

Please sign in to comment.