diff --git a/Cargo.lock b/Cargo.lock index 8c1766128..a122e2149 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2560,6 +2560,7 @@ dependencies = [ "num-bigint", "num-integer", "num-traits", + "serde", ] [[package]] @@ -3021,8 +3022,7 @@ dependencies = [ [[package]] name = "prio" version = "0.15.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2e546dc580118e2120309c8aa7bb0da8deabd4b848289c486e9429a27c05594" +source = "git+https://github.com/dpsa4fl/libprio-rs.git?branch=dp-update-for-janus-rebased#3aa7892719f5f36857169db3df5931189657c188" dependencies = [ "aes", "bitvec", diff --git a/Cargo.toml b/Cargo.toml index 0b9113989..f216de208 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -43,7 +43,8 @@ janus_messages = { version = "0.6.0-prerelease-1", path = "messages" } k8s-openapi = { version = "0.18.0", features = ["v1_24"] } # keep this version in sync with what is referenced by the indirect dependency via `kube` kube = { version = "0.82.2", default-features = false, features = ["client", "rustls-tls"] } opentelemetry = { version = "0.20", features = ["metrics"] } -prio = { version = "0.15.1", features = ["multithreaded", "experimental"] } +#prio = { version = "0.15.1", features = ["multithreaded", "experimental"] } +prio = {git = "https://github.com/dpsa4fl/libprio-rs.git", branch="dp-update-for-janus-rebased", features = ["multithreaded", "experimental"]} serde = { version = "1.0.188", features = ["derive"] } serde_json = "1.0.106" serde_test = "1.0.175" diff --git a/aggregator/src/aggregator.rs b/aggregator/src/aggregator.rs index 8fdd29858..8f11ccd28 100644 --- a/aggregator/src/aggregator.rs +++ b/aggregator/src/aggregator.rs @@ -36,6 +36,8 @@ use janus_aggregator_core::{ task::{self, Task, VerifyKey}, taskprov::{self, PeerAggregator}, }; +#[cfg(feature = "fpvec_bounded_l2")] +use janus_core::task::Prio3FixedPointBoundedL2VecSumBitSize; #[cfg(feature = "test-util")] use janus_core::test_util::dummy_vdaf; use janus_core::{ @@ -65,6 +67,7 @@ use prio::vdaf::prio3::Prio3FixedPointBoundedL2VecSumMultithreaded; use prio::vdaf::{PrepareTransition, VdafError}; use prio::{ codec::{Decode, Encode, ParameterizedDecode}, + dp::DifferentialPrivacyStrategy, topology::ping_pong::{PingPongState, PingPongTopology}, vdaf::{ self, @@ -836,28 +839,30 @@ impl TaskAggregator { } #[cfg(feature = "fpvec_bounded_l2")] - VdafInstance::Prio3FixedPoint16BitBoundedL2VecSum { length } => { - let vdaf: Prio3FixedPointBoundedL2VecSumMultithreaded> = - Prio3::new_fixedpoint_boundedl2_vec_sum_multithreaded(2, *length)?; - let verify_key = task.vdaf_verify_key()?; - VdafOps::Prio3FixedPoint16BitBoundedL2VecSum(Arc::new(vdaf), verify_key) - } - - #[cfg(feature = "fpvec_bounded_l2")] - VdafInstance::Prio3FixedPoint32BitBoundedL2VecSum { length } => { - let vdaf: Prio3FixedPointBoundedL2VecSumMultithreaded> = - Prio3::new_fixedpoint_boundedl2_vec_sum_multithreaded(2, *length)?; - let verify_key = task.vdaf_verify_key()?; - VdafOps::Prio3FixedPoint32BitBoundedL2VecSum(Arc::new(vdaf), verify_key) - } - - #[cfg(feature = "fpvec_bounded_l2")] - VdafInstance::Prio3FixedPoint64BitBoundedL2VecSum { length } => { - let vdaf: Prio3FixedPointBoundedL2VecSumMultithreaded> = - Prio3::new_fixedpoint_boundedl2_vec_sum_multithreaded(2, *length)?; - let verify_key = task.vdaf_verify_key()?; - VdafOps::Prio3FixedPoint64BitBoundedL2VecSum(Arc::new(vdaf), verify_key) - } + VdafInstance::Prio3FixedPointBoundedL2VecSum { + bitsize, + dp_strategy, + length, + } => match bitsize { + Prio3FixedPointBoundedL2VecSumBitSize::BitSize16 => { + let vdaf: Prio3FixedPointBoundedL2VecSumMultithreaded> = + Prio3::new_fixedpoint_boundedl2_vec_sum_multithreaded(2, *length)?; + let verify_key = task.vdaf_verify_key()?; + VdafOps::Prio3FixedPoint16BitBoundedL2VecSum(Arc::new(vdaf), verify_key, vdaf_ops_strategies::Prio3FixedPointBoundedL2VecSum::from_vdaf_instance_strategy(dp_strategy.clone())) + } + Prio3FixedPointBoundedL2VecSumBitSize::BitSize32 => { + let vdaf: Prio3FixedPointBoundedL2VecSumMultithreaded> = + Prio3::new_fixedpoint_boundedl2_vec_sum_multithreaded(2, *length)?; + let verify_key = task.vdaf_verify_key()?; + VdafOps::Prio3FixedPoint32BitBoundedL2VecSum(Arc::new(vdaf), verify_key, vdaf_ops_strategies::Prio3FixedPointBoundedL2VecSum::from_vdaf_instance_strategy(dp_strategy.clone())) + } + Prio3FixedPointBoundedL2VecSumBitSize::BitSize64 => { + let vdaf: Prio3FixedPointBoundedL2VecSumMultithreaded> = + Prio3::new_fixedpoint_boundedl2_vec_sum_multithreaded(2, *length)?; + let verify_key = task.vdaf_verify_key()?; + VdafOps::Prio3FixedPoint64BitBoundedL2VecSum(Arc::new(vdaf), verify_key, vdaf_ops_strategies::Prio3FixedPointBoundedL2VecSum::from_vdaf_instance_strategy(dp_strategy.clone())) + } + }, VdafInstance::Poplar1 { bits } => { let vdaf = Poplar1::new_shake128(*bits); @@ -1034,6 +1039,34 @@ impl TaskAggregator { } } +#[cfg(feature = "fpvec_bounded_l2")] +mod vdaf_ops_strategies { + use std::sync::Arc; + + use janus_core::task::vdaf_instance_strategies; + use prio::dp::distributions::ZCdpDiscreteGaussian; + + pub enum Prio3FixedPointBoundedL2VecSum { + NoDifferentialPrivacy, + ZCdpDiscreteGaussian(Arc), + } + + impl Prio3FixedPointBoundedL2VecSum { + pub fn from_vdaf_instance_strategy( + dp_strategy: vdaf_instance_strategies::Prio3FixedPointBoundedL2VecSum, + ) -> Self { + match dp_strategy { + vdaf_instance_strategies::Prio3FixedPointBoundedL2VecSum::NoDifferentialPrivacy => { + Prio3FixedPointBoundedL2VecSum::NoDifferentialPrivacy + } + vdaf_instance_strategies::Prio3FixedPointBoundedL2VecSum::ZCdpDiscreteGaussian( + s, + ) => Prio3FixedPointBoundedL2VecSum::ZCdpDiscreteGaussian(Arc::new(s)), + } + } + } +} + /// VdafOps stores VDAF-specific operations for a TaskAggregator in a non-generic way. #[allow(clippy::enum_variant_names)] enum VdafOps { @@ -1046,19 +1079,21 @@ enum VdafOps { Prio3FixedPoint16BitBoundedL2VecSum( Arc>>, VerifyKey, + vdaf_ops_strategies::Prio3FixedPointBoundedL2VecSum, ), #[cfg(feature = "fpvec_bounded_l2")] Prio3FixedPoint32BitBoundedL2VecSum( Arc>>, VerifyKey, + vdaf_ops_strategies::Prio3FixedPointBoundedL2VecSum, ), #[cfg(feature = "fpvec_bounded_l2")] Prio3FixedPoint64BitBoundedL2VecSum( Arc>>, VerifyKey, + vdaf_ops_strategies::Prio3FixedPointBoundedL2VecSum, ), Poplar1(Arc>, VerifyKey), - #[cfg(feature = "test-util")] Fake(Arc), } @@ -1069,13 +1104,17 @@ enum VdafOps { /// specify the VDAF's type, and the name of a const that will be set to the VDAF's verify key /// length, also for explicitly specifying type parameters. macro_rules! vdaf_ops_dispatch { - ($vdaf_ops:expr, ($vdaf:pat_param, $verify_key:pat_param, $Vdaf:ident, $VERIFY_KEY_LENGTH:ident) => $body:tt) => { + ($vdaf_ops:expr, ($vdaf:pat_param, $verify_key:pat_param, $Vdaf:ident, $VERIFY_KEY_LENGTH:ident $(, $DpStrategy:ident, $dp_strategy:ident )?) => $body:tt) => { match $vdaf_ops { crate::aggregator::VdafOps::Prio3Count(vdaf, verify_key) => { let $vdaf = vdaf; let $verify_key = verify_key; type $Vdaf = ::prio::vdaf::prio3::Prio3Count; const $VERIFY_KEY_LENGTH: usize = ::janus_core::task::VERIFY_KEY_LENGTH; + $( + type $DpStrategy = janus_core::dp::NoDifferentialPrivacy; + let $dp_strategy = &Arc::new(janus_core::dp::NoDifferentialPrivacy); + )? $body } @@ -1084,6 +1123,10 @@ macro_rules! vdaf_ops_dispatch { let $verify_key = verify_key; type $Vdaf = ::prio::vdaf::prio3::Prio3SumVecMultithreaded; const $VERIFY_KEY_LENGTH: usize = ::janus_core::task::VERIFY_KEY_LENGTH; + $( + type $DpStrategy = janus_core::dp::NoDifferentialPrivacy; + let $dp_strategy = &Arc::new(janus_core::dp::NoDifferentialPrivacy); + )? $body } @@ -1092,6 +1135,10 @@ macro_rules! vdaf_ops_dispatch { let $verify_key = verify_key; type $Vdaf = ::prio::vdaf::prio3::Prio3Sum; const $VERIFY_KEY_LENGTH: usize = ::janus_core::task::VERIFY_KEY_LENGTH; + $( + type $DpStrategy = janus_core::dp::NoDifferentialPrivacy; + let $dp_strategy = &Arc::new(janus_core::dp::NoDifferentialPrivacy); + )? $body } @@ -1100,6 +1147,10 @@ macro_rules! vdaf_ops_dispatch { let $verify_key = verify_key; type $Vdaf = ::prio::vdaf::prio3::Prio3SumVecMultithreaded; const $VERIFY_KEY_LENGTH: usize = ::janus_core::task::VERIFY_KEY_LENGTH; + $( + type $DpStrategy = janus_core::dp::NoDifferentialPrivacy; + let $dp_strategy = &Arc::new(janus_core::dp::NoDifferentialPrivacy); + )? $body } @@ -1108,37 +1159,122 @@ macro_rules! vdaf_ops_dispatch { let $verify_key = verify_key; type $Vdaf = ::prio::vdaf::prio3::Prio3Histogram; const $VERIFY_KEY_LENGTH: usize = ::janus_core::task::VERIFY_KEY_LENGTH; + $( + type $DpStrategy = janus_core::dp::NoDifferentialPrivacy; + let $dp_strategy = &Arc::new(janus_core::dp::NoDifferentialPrivacy); + )? $body } #[cfg(feature = "fpvec_bounded_l2")] - crate::aggregator::VdafOps::Prio3FixedPoint16BitBoundedL2VecSum(vdaf, verify_key) => { + // Note that the variable `_dp_strategy` is used if `$dp_strategy` + // and `$DpStrategy` are given. The underscore suppresses warnings + // which occur when `vdaf_ops!` is called without these parameters. + crate::aggregator::VdafOps::Prio3FixedPoint16BitBoundedL2VecSum(vdaf, verify_key, _dp_strategy) => { let $vdaf = vdaf; let $verify_key = verify_key; - type $Vdaf = - ::prio::vdaf::prio3::Prio3FixedPointBoundedL2VecSumMultithreaded>; const $VERIFY_KEY_LENGTH: usize = ::janus_core::task::VERIFY_KEY_LENGTH; - $body + + type $Vdaf = ::prio::vdaf::prio3::Prio3FixedPointBoundedL2VecSumMultithreaded>; + + janus_core::if_ident_exists!( + $($DpStrategy)?, + true => { + match _dp_strategy { + vdaf_ops_strategies::Prio3FixedPointBoundedL2VecSum::ZCdpDiscreteGaussian(strategy) => { + $( + type $DpStrategy = ::prio::dp::distributions::ZCdpDiscreteGaussian; + let $dp_strategy = &strategy; + )? + $body + }, + vdaf_ops_strategies::Prio3FixedPointBoundedL2VecSum::NoDifferentialPrivacy => { + $( + type $DpStrategy = janus_core::dp::NoDifferentialPrivacy; + let $dp_strategy = &Arc::new(janus_core::dp::NoDifferentialPrivacy); + )? + $body + } + } + }, + false => { + $body + } + ) } #[cfg(feature = "fpvec_bounded_l2")] - crate::aggregator::VdafOps::Prio3FixedPoint32BitBoundedL2VecSum(vdaf, verify_key) => { + // Note that the variable `_dp_strategy` is used if `$dp_strategy` + // and `$DpStrategy` are given. The underscore suppresses warnings + // which occur when `vdaf_ops!` is called without these parameters. + crate::aggregator::VdafOps::Prio3FixedPoint32BitBoundedL2VecSum(vdaf, verify_key, _dp_strategy) => { let $vdaf = vdaf; let $verify_key = verify_key; - type $Vdaf = - ::prio::vdaf::prio3::Prio3FixedPointBoundedL2VecSumMultithreaded>; const $VERIFY_KEY_LENGTH: usize = ::janus_core::task::VERIFY_KEY_LENGTH; - $body + + type $Vdaf = ::prio::vdaf::prio3::Prio3FixedPointBoundedL2VecSumMultithreaded>; + + janus_core::if_ident_exists!( + $($DpStrategy)?, + true => { + match _dp_strategy { + vdaf_ops_strategies::Prio3FixedPointBoundedL2VecSum::ZCdpDiscreteGaussian(strategy) => { + $( + type $DpStrategy = ::prio::dp::distributions::ZCdpDiscreteGaussian; + let $dp_strategy = &strategy; + )? + $body + }, + vdaf_ops_strategies::Prio3FixedPointBoundedL2VecSum::NoDifferentialPrivacy => { + $( + type $DpStrategy = janus_core::dp::NoDifferentialPrivacy; + let $dp_strategy = &Arc::new(janus_core::dp::NoDifferentialPrivacy); + )? + $body + } + } + }, + false => { + $body + } + ) } #[cfg(feature = "fpvec_bounded_l2")] - crate::aggregator::VdafOps::Prio3FixedPoint64BitBoundedL2VecSum(vdaf, verify_key) => { + // Note that the variable `_dp_strategy` is used if `$dp_strategy` + // and `$DpStrategy` are given. The underscore suppresses warnings + // which occur when `vdaf_ops!` is called without these parameters. + crate::aggregator::VdafOps::Prio3FixedPoint64BitBoundedL2VecSum(vdaf, verify_key, _dp_strategy) => { let $vdaf = vdaf; let $verify_key = verify_key; - type $Vdaf = - ::prio::vdaf::prio3::Prio3FixedPointBoundedL2VecSumMultithreaded>; const $VERIFY_KEY_LENGTH: usize = ::janus_core::task::VERIFY_KEY_LENGTH; - $body + + type $Vdaf = ::prio::vdaf::prio3::Prio3FixedPointBoundedL2VecSumMultithreaded>; + + janus_core::if_ident_exists!( + $($DpStrategy)?, + true => { + match _dp_strategy { + vdaf_ops_strategies::Prio3FixedPointBoundedL2VecSum::ZCdpDiscreteGaussian(strategy) => { + $( + type $DpStrategy = ::prio::dp::distributions::ZCdpDiscreteGaussian; + let $dp_strategy = &strategy; + )? + $body + }, + vdaf_ops_strategies::Prio3FixedPointBoundedL2VecSum::NoDifferentialPrivacy => { + $( + type $DpStrategy = janus_core::dp::NoDifferentialPrivacy; + let $dp_strategy = &Arc::new(janus_core::dp::NoDifferentialPrivacy); + )? + $body + } + } + }, + false => { + $body + } + ) } crate::aggregator::VdafOps::Poplar1(vdaf, verify_key) => { @@ -1146,6 +1282,10 @@ macro_rules! vdaf_ops_dispatch { let $verify_key = verify_key; type $Vdaf = ::prio::vdaf::poplar1::Poplar1<::prio::vdaf::xof::XofShake128, 16>; const $VERIFY_KEY_LENGTH: usize = ::janus_core::task::VERIFY_KEY_LENGTH; + $( + type $DpStrategy = janus_core::dp::NoDifferentialPrivacy; + let $dp_strategy = &Arc::new(janus_core::dp::NoDifferentialPrivacy); + )? $body } @@ -1155,10 +1295,17 @@ macro_rules! vdaf_ops_dispatch { let $verify_key = &VerifyKey::new([]); type $Vdaf = ::janus_core::test_util::dummy_vdaf::Vdaf; const $VERIFY_KEY_LENGTH: usize = 0; + $( + type $DpStrategy = janus_core::dp::NoDifferentialPrivacy; + let $dp_strategy = &Arc::new(janus_core::dp::NoDifferentialPrivacy); + )? $body } } }; + + ($vdaf_ops:expr, ($vdaf:pat_param, $verify_key:pat_param, $Vdaf:ident, $VERIFY_KEY_LENGTH:ident $(, $DpStrategy:ident, $dp_strategy:ident )?) => $body:tt) => { + vdaf_ops_dispatch!($vdaf_ops, ($vdaf, $verify_key, $Vdaf, $VERIFY_KEY_LENGTH $(, $DpStrategy, $dp_strategy )?) => $body)}; } impl VdafOps { @@ -2754,25 +2901,25 @@ impl VdafOps { ) -> Result { match task.query_type() { task::QueryType::TimeInterval => { - vdaf_ops_dispatch!(self, (vdaf, _, VdafType, VERIFY_KEY_LENGTH) => { + vdaf_ops_dispatch!(self, (vdaf, _, VdafType, VERIFY_KEY_LENGTH, DpStrategyType, dp_strategy) => { Self::handle_aggregate_share_generic::< VERIFY_KEY_LENGTH, TimeInterval, + DpStrategyType, VdafType, _, - >(datastore, clock, task, Arc::clone(vdaf), req_bytes, batch_aggregation_shard_count, collector_hpke_config) - .await + >(datastore, clock, task, Arc::clone(vdaf), req_bytes, batch_aggregation_shard_count, collector_hpke_config, Arc::clone(dp_strategy)).await }) } task::QueryType::FixedSize { .. } => { - vdaf_ops_dispatch!(self, (vdaf, _, VdafType, VERIFY_KEY_LENGTH) => { + vdaf_ops_dispatch!(self, (vdaf, _, VdafType, VERIFY_KEY_LENGTH, DpStrategyType, dp_strategy) => { Self::handle_aggregate_share_generic::< VERIFY_KEY_LENGTH, FixedSize, + DpStrategyType, VdafType, _, - >(datastore, clock, task, Arc::clone(vdaf), req_bytes, batch_aggregation_shard_count, collector_hpke_config) - .await + >(datastore, clock, task, Arc::clone(vdaf), req_bytes, batch_aggregation_shard_count, collector_hpke_config, Arc::clone(dp_strategy)).await }) } } @@ -2781,7 +2928,8 @@ impl VdafOps { async fn handle_aggregate_share_generic< const SEED_SIZE: usize, Q: CollectableQueryType, - A: vdaf::Aggregator + Send + Sync + 'static, + S: DifferentialPrivacyStrategy + Send + Clone + Sync + 'static, + A: vdaf::AggregatorWithNoise + Send + Sync + 'static, C: Clock, >( datastore: &Datastore, @@ -2791,10 +2939,12 @@ impl VdafOps { req_bytes: &[u8], batch_aggregation_shard_count: u64, collector_hpke_config: &HpkeConfig, + dp_strategy: Arc, ) -> Result where A::AggregationParam: Send + Sync + Eq + Hash, A::AggregateShare: Send + Sync, + S: Send + Sync, { // Decode request, and verify that it is for the current task. We use an assert to check // that the task IDs match as this should be guaranteed by the caller. @@ -2832,10 +2982,11 @@ impl VdafOps { let aggregate_share_job = datastore .run_tx_with_name("aggregate_share", |tx| { - let (task, vdaf, aggregate_share_req) = ( + let (task, vdaf, aggregate_share_req, dp_strategy) = ( Arc::clone(&task), Arc::clone(&vdaf), Arc::clone(&aggregate_share_req), + Arc::clone(&dp_strategy), ); Box::pin(async move { // Check if we have already serviced an aggregate share request with these @@ -2895,14 +3046,26 @@ impl VdafOps { &batch_aggregations, ); - let (helper_aggregate_share, report_count, checksum) = - compute_aggregate_share::( + let (mut helper_aggregate_share, report_count, checksum) = + compute_aggregate_share::( &task, &batch_aggregations, ) .await .map_err(|e| datastore::Error::User(e.into()))?; + vdaf.add_noise_to_agg_share( + &dp_strategy, + &aggregation_param, + &mut helper_aggregate_share, + report_count.try_into()?, + ) + .map_err(|e| { + datastore::Error::DifferentialPrivacy(format!( + "Error when adding noise to aggregate share: {e}" + )) + })?; + // Now that we are satisfied that the request is serviceable, we consume // a query by recording the aggregate share request parameters and the // result. diff --git a/aggregator/src/aggregator/aggregate_share.rs b/aggregator/src/aggregator/aggregate_share.rs index 0b759b39c..dbd6b72d8 100644 --- a/aggregator/src/aggregator/aggregate_share.rs +++ b/aggregator/src/aggregator/aggregate_share.rs @@ -4,7 +4,10 @@ use super::Error; use janus_aggregator_core::{datastore::models::BatchAggregation, task::Task}; use janus_core::report_id::ReportIdChecksumExt; use janus_messages::{query_type::QueryType, ReportIdChecksum}; -use prio::vdaf::{self, Aggregatable}; +use prio::{ + dp::DifferentialPrivacyStrategy, + vdaf::{self, Aggregatable}, +}; /// Computes the aggregate share over the provided batch aggregations. /// The assumption is that all aggregation jobs contributing to those batch aggregations have @@ -14,7 +17,8 @@ use prio::vdaf::{self, Aggregatable}; pub(crate) async fn compute_aggregate_share< const SEED_SIZE: usize, Q: QueryType, - A: vdaf::Aggregator, + S: DifferentialPrivacyStrategy, + A: vdaf::AggregatorWithNoise, >( task: &Task, batch_aggregations: &[BatchAggregation], diff --git a/aggregator/src/aggregator/aggregation_job_creator.rs b/aggregator/src/aggregator/aggregation_job_creator.rs index c763cb6fe..7d38a5b4f 100644 --- a/aggregator/src/aggregator/aggregation_job_creator.rs +++ b/aggregator/src/aggregator/aggregation_job_creator.rs @@ -11,6 +11,8 @@ use janus_aggregator_core::{ datastore::{self, Datastore}, task::{self, Task}, }; +#[cfg(feature = "fpvec_bounded_l2")] +use janus_core::task::Prio3FixedPointBoundedL2VecSumBitSize; use janus_core::{ task::{VdafInstance, VERIFY_KEY_LENGTH}, time::{Clock, DurationExt as _, TimeExt as _}, @@ -311,41 +313,37 @@ impl AggregationJobCreator { #[cfg(feature = "fpvec_bounded_l2")] ( task::QueryType::TimeInterval, - VdafInstance::Prio3FixedPoint16BitBoundedL2VecSum { length }, - ) => { - let vdaf: Arc>> = - Arc::new(Prio3::new_fixedpoint_boundedl2_vec_sum_multithreaded( - 2, *length, - )?); - self.create_aggregation_jobs_for_time_interval_task_no_param::>>(task, vdaf) - .await - } - - #[cfg(feature = "fpvec_bounded_l2")] - ( - task::QueryType::TimeInterval, - VdafInstance::Prio3FixedPoint32BitBoundedL2VecSum { length }, - ) => { - let vdaf: Arc>> = - Arc::new(Prio3::new_fixedpoint_boundedl2_vec_sum_multithreaded( - 2, *length, - )?); - self.create_aggregation_jobs_for_time_interval_task_no_param::>>(task, vdaf) - .await - } - - #[cfg(feature = "fpvec_bounded_l2")] - ( - task::QueryType::TimeInterval, - VdafInstance::Prio3FixedPoint64BitBoundedL2VecSum { length }, - ) => { - let vdaf: Arc>> = - Arc::new(Prio3::new_fixedpoint_boundedl2_vec_sum_multithreaded( - 2, *length, - )?); - self.create_aggregation_jobs_for_time_interval_task_no_param::>>(task, vdaf) - .await - } + VdafInstance::Prio3FixedPointBoundedL2VecSum { + bitsize, + dp_strategy: _, + length, + }, + ) => match bitsize { + Prio3FixedPointBoundedL2VecSumBitSize::BitSize16 => { + let vdaf: Arc>> = + Arc::new(Prio3::new_fixedpoint_boundedl2_vec_sum_multithreaded( + 2, *length, + )?); + self.create_aggregation_jobs_for_time_interval_task_no_param::>>(task, vdaf) + .await + } + Prio3FixedPointBoundedL2VecSumBitSize::BitSize32 => { + let vdaf: Arc>> = + Arc::new(Prio3::new_fixedpoint_boundedl2_vec_sum_multithreaded( + 2, *length, + )?); + self.create_aggregation_jobs_for_time_interval_task_no_param::>>(task, vdaf) + .await + } + Prio3FixedPointBoundedL2VecSumBitSize::BitSize64 => { + let vdaf: Arc>> = + Arc::new(Prio3::new_fixedpoint_boundedl2_vec_sum_multithreaded( + 2, *length, + )?); + self.create_aggregation_jobs_for_time_interval_task_no_param::>>(task, vdaf) + .await + } + }, ( task::QueryType::FixedSize { @@ -447,58 +445,47 @@ impl AggregationJobCreator { max_batch_size, batch_time_window_size, }, - VdafInstance::Prio3FixedPoint16BitBoundedL2VecSum { length }, - ) => { - let vdaf: Arc>> = - Arc::new(Prio3::new_fixedpoint_boundedl2_vec_sum_multithreaded( - 2, *length, - )?); - let max_batch_size = *max_batch_size; - let batch_time_window_size = *batch_time_window_size; - self.create_aggregation_jobs_for_fixed_size_task_no_param::< - VERIFY_KEY_LENGTH, - Prio3FixedPointBoundedL2VecSumMultithreaded>, - >(task, vdaf, max_batch_size, batch_time_window_size).await - } - - #[cfg(feature = "fpvec_bounded_l2")] - ( - task::QueryType::FixedSize { - max_batch_size, - batch_time_window_size, + VdafInstance::Prio3FixedPointBoundedL2VecSum { + bitsize, + dp_strategy: _, + length, }, - VdafInstance::Prio3FixedPoint32BitBoundedL2VecSum { length }, ) => { - let vdaf: Arc>> = - Arc::new(Prio3::new_fixedpoint_boundedl2_vec_sum_multithreaded( - 2, *length, - )?); let max_batch_size = *max_batch_size; let batch_time_window_size = *batch_time_window_size; - self.create_aggregation_jobs_for_fixed_size_task_no_param::< - VERIFY_KEY_LENGTH, - Prio3FixedPointBoundedL2VecSumMultithreaded>, - >(task, vdaf, max_batch_size, batch_time_window_size).await - } - #[cfg(feature = "fpvec_bounded_l2")] - ( - task::QueryType::FixedSize { - max_batch_size, - batch_time_window_size, - }, - VdafInstance::Prio3FixedPoint64BitBoundedL2VecSum { length }, - ) => { - let vdaf: Arc>> = - Arc::new(Prio3::new_fixedpoint_boundedl2_vec_sum_multithreaded( - 2, *length, - )?); - let max_batch_size = *max_batch_size; - let batch_time_window_size = *batch_time_window_size; - self.create_aggregation_jobs_for_fixed_size_task_no_param::< - VERIFY_KEY_LENGTH, - Prio3FixedPointBoundedL2VecSumMultithreaded>, - >(task, vdaf, max_batch_size, batch_time_window_size).await + match bitsize { + janus_core::task::Prio3FixedPointBoundedL2VecSumBitSize::BitSize16 => { + let vdaf: Arc>> = + Arc::new(Prio3::new_fixedpoint_boundedl2_vec_sum_multithreaded( + 2, *length, + )?); + self.create_aggregation_jobs_for_fixed_size_task_no_param::< + VERIFY_KEY_LENGTH, + Prio3FixedPointBoundedL2VecSumMultithreaded>, + >(task, vdaf, max_batch_size, batch_time_window_size).await + } + janus_core::task::Prio3FixedPointBoundedL2VecSumBitSize::BitSize32 => { + let vdaf: Arc>> = + Arc::new(Prio3::new_fixedpoint_boundedl2_vec_sum_multithreaded( + 2, *length, + )?); + self.create_aggregation_jobs_for_fixed_size_task_no_param::< + VERIFY_KEY_LENGTH, + Prio3FixedPointBoundedL2VecSumMultithreaded>, + >(task, vdaf, max_batch_size, batch_time_window_size).await + } + janus_core::task::Prio3FixedPointBoundedL2VecSumBitSize::BitSize64 => { + let vdaf: Arc>> = + Arc::new(Prio3::new_fixedpoint_boundedl2_vec_sum_multithreaded( + 2, *length, + )?); + self.create_aggregation_jobs_for_fixed_size_task_no_param::< + VERIFY_KEY_LENGTH, + Prio3FixedPointBoundedL2VecSumMultithreaded>, + >(task, vdaf, max_batch_size, batch_time_window_size).await + } + } } _ => { diff --git a/aggregator/src/aggregator/collection_job_driver.rs b/aggregator/src/aggregator/collection_job_driver.rs index c12a470a6..0931bb62b 100644 --- a/aggregator/src/aggregator/collection_job_driver.rs +++ b/aggregator/src/aggregator/collection_job_driver.rs @@ -16,7 +16,7 @@ use janus_aggregator_core::{ }, task, }; -use janus_core::{time::Clock, vdaf_dispatch}; +use janus_core::{dp::DpStrategyInstance, time::Clock, vdaf_dispatch}; use janus_messages::{ query_type::{FixedSize, QueryType, TimeInterval}, AggregateShare, AggregateShareReq, BatchSelector, @@ -27,6 +27,7 @@ use opentelemetry::{ }; use prio::{ codec::{Decode, Encode}, + dp::DifferentialPrivacyStrategy, vdaf, }; use reqwest::Method; @@ -81,24 +82,26 @@ impl CollectionJobDriver { ) -> Result<(), Error> { match lease.leased().query_type() { task::QueryType::TimeInterval => { - vdaf_dispatch!(lease.leased().vdaf(), (vdaf, VdafType, VERIFY_KEY_LENGTH) => { + vdaf_dispatch!(lease.leased().vdaf(), (vdaf, VdafType, VERIFY_KEY_LENGTH, DpStrategy, dp_strategy) => { self.step_collection_job_generic::< VERIFY_KEY_LENGTH, C, TimeInterval, + DpStrategy, VdafType - >(datastore, Arc::new(vdaf), lease) + >(datastore, Arc::new(vdaf), lease, dp_strategy) .await }) } task::QueryType::FixedSize { .. } => { - vdaf_dispatch!(lease.leased().vdaf(), (vdaf, VdafType, VERIFY_KEY_LENGTH) => { + vdaf_dispatch!(lease.leased().vdaf(), (vdaf, VdafType, VERIFY_KEY_LENGTH, DpStrategy, dp_strategy) => { self.step_collection_job_generic::< VERIFY_KEY_LENGTH, C, FixedSize, + DpStrategy, VdafType - >(datastore, Arc::new(vdaf), lease) + >(datastore, Arc::new(vdaf), lease, dp_strategy) .await }) } @@ -109,12 +112,14 @@ impl CollectionJobDriver { const SEED_SIZE: usize, C: Clock, Q: CollectableQueryType, - A: vdaf::Aggregator + Send + Sync, + S: DifferentialPrivacyStrategy + TryFrom, + A: vdaf::AggregatorWithNoise + Send + Sync, >( &self, datastore: Arc>, vdaf: Arc, lease: Arc>, + dp_strategy: S, ) -> Result<(), Error> where A: 'static, @@ -208,11 +213,23 @@ impl CollectionJobDriver { return Ok(()); } - let (leader_aggregate_share, report_count, checksum) = - compute_aggregate_share::(&task, &batch_aggregations) + let (mut leader_aggregate_share, report_count, checksum) = + compute_aggregate_share::(&task, &batch_aggregations) .await .map_err(|e| datastore::Error::User(e.into()))?; + vdaf.add_noise_to_agg_share( + &dp_strategy, + collection_job.aggregation_parameter(), + &mut leader_aggregate_share, + report_count.try_into()?, + ) + .map_err(|e| { + datastore::Error::DifferentialPrivacy(format!( + "Error when adding noise to aggregate share: {e}" + )) + })?; + // Send an aggregate share request to the helper. let req = AggregateShareReq::::new( BatchSelector::new(collection_job.batch_identifier().clone()), diff --git a/aggregator/src/bin/janus_cli.rs b/aggregator/src/bin/janus_cli.rs index 3ebf692cb..e33481760 100644 --- a/aggregator/src/bin/janus_cli.rs +++ b/aggregator/src/bin/janus_cli.rs @@ -734,6 +734,7 @@ mod tests { aggregator_auth_tokens: [] collector_auth_tokens: [] hpke_keys: [] + dp_strategy: !NoDifferentialPrivacy - leader_aggregator_endpoint: https://leader helper_aggregator_endpoint: https://helper query_type: TimeInterval @@ -756,6 +757,7 @@ mod tests { aggregator_auth_tokens: [] collector_auth_tokens: [] hpke_keys: [] + dp_strategy: !NoDifferentialPrivacy "#; let ephemeral_datastore = ephemeral_datastore().await; diff --git a/aggregator_core/src/datastore.rs b/aggregator_core/src/datastore.rs index 480f8d7e7..4fba1635f 100644 --- a/aggregator_core/src/datastore.rs +++ b/aggregator_core/src/datastore.rs @@ -4967,6 +4967,9 @@ pub enum Error { /// An invalid parameter was provided. #[error("invalid parameter: {0}")] InvalidParameter(&'static str), + /// An error occured when trying to ensure differential privacy. + #[error("differential privacy error: {0}")] + DifferentialPrivacy(String), /// An error occurred while manipulating timestamps or durations. #[error("{0}")] TimeOverflow(&'static str), diff --git a/aggregator_core/src/task.rs b/aggregator_core/src/task.rs index 7e7318cc9..09ccb1da6 100644 --- a/aggregator_core/src/task.rs +++ b/aggregator_core/src/task.rs @@ -12,6 +12,7 @@ use janus_messages::{ taskprov, AggregationJobId, CollectionJobId, Duration, HpkeAeadId, HpkeConfig, HpkeConfigId, HpkeKdfId, HpkeKemId, Role, TaskId, Time, }; + use rand::{distributions::Standard, random, thread_rng, Rng}; use serde::{de::Error as _, Deserialize, Deserializer, Serialize, Serializer}; use std::{array::TryFromSliceError, collections::HashMap}; diff --git a/core/Cargo.toml b/core/Cargo.toml index c439f9c09..269acf4d1 100644 --- a/core/Cargo.toml +++ b/core/Cargo.toml @@ -14,7 +14,7 @@ all-features = true rustdoc-args = ["--cfg", "docsrs"] [features] -fpvec_bounded_l2 = ["prio/experimental"] +fpvec_bounded_l2 = ["dep:fixed", "prio/experimental"] test-util = [ "dep:assert_matches", "dep:k8s-openapi", @@ -38,6 +38,7 @@ base64.workspace = true chrono = { workspace = true, features = ["clock"] } derivative = "2.2.0" futures = "0.3.28" +fixed = { version = "1.23", optional = true } hex = "0.4" hpke-dispatch = { version = "0.5.1", features = ["serde"] } http = "0.2.9" diff --git a/core/src/dp.rs b/core/src/dp.rs new file mode 100644 index 000000000..16279342a --- /dev/null +++ b/core/src/dp.rs @@ -0,0 +1,195 @@ +#[cfg(feature = "test-util")] +use crate::test_util::dummy_vdaf::Vdaf; +use anyhow::anyhow; +use derivative::Derivative; +#[cfg(feature = "fpvec_bounded_l2")] +use fixed::traits::Fixed; +#[cfg(feature = "fpvec_bounded_l2")] +use prio::flp::{ + gadgets::{ParallelSumGadget, PolyEval}, + types::fixedpoint_l2::{compatible_float::CompatibleFloat, FixedPointBoundedL2VecSum}, +}; +use prio::{ + dp::{ + distributions::ZCdpDiscreteGaussian, DifferentialPrivacyBudget, + DifferentialPrivacyDistribution, DifferentialPrivacyStrategy, DpError, + }, + field::{Field128, Field64}, + flp::{ + gadgets::{Mul, ParallelSum, ParallelSumMultithreaded}, + TypeWithNoise, + }, + vdaf::{xof::XofShake128, AggregatorWithNoise}, +}; +use serde::{Deserialize, Serialize}; + +//////////////////////////////////////////////////////////////// +// strategy enum for dispatch + +#[derive(Debug, Derivative, Clone, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)] +pub enum DpStrategyInstance { + NoDifferentialPrivacy, + ZCdpDiscreteGaussian(ZCdpDiscreteGaussian), +} + +impl DpStrategyInstance {} + +//////////////////////////////////////////////////////////////// +// identity strategy + +pub struct NoBudget; +impl DifferentialPrivacyBudget for NoBudget {} + +pub struct NoDistribution; +impl DifferentialPrivacyDistribution for NoDistribution {} + +#[derive(Debug, Derivative, Clone, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)] +pub struct NoDifferentialPrivacy; +impl DifferentialPrivacyStrategy for NoDifferentialPrivacy { + type Budget = NoBudget; + type Distribution = NoDistribution; + type Sensitivity = (); + fn from_budget(_b: NoBudget) -> Self { + NoDifferentialPrivacy + } + fn create_distribution(&self, _s: Self::Sensitivity) -> Result { + Ok(NoDistribution) + } +} + +//////////////////////////////////////////////////////////////// +// converting strategy enum into strategy types + +impl TryFrom for NoDifferentialPrivacy { + type Error = anyhow::Error; + fn try_from(value: DpStrategyInstance) -> Result { + match value { + DpStrategyInstance::NoDifferentialPrivacy => Ok(NoDifferentialPrivacy), + DpStrategyInstance::ZCdpDiscreteGaussian(_) => Err(anyhow!( + "Attempted to use ZCdp instance for NoDp strategy".to_string(), + )), + } + } +} + +impl TryFrom for ZCdpDiscreteGaussian { + type Error = anyhow::Error; + fn try_from(value: DpStrategyInstance) -> Result { + match value { + DpStrategyInstance::ZCdpDiscreteGaussian(s) => Ok(s), + DpStrategyInstance::NoDifferentialPrivacy => Err(anyhow!( + "Attempted to use NoDp instance for ZCdp strategy".to_string(), + )), + } + } +} + +//////////////////////////////////////////////////////////////// +// identity strategy implementations for vdafs from janus +#[cfg(feature = "test-util")] +impl AggregatorWithNoise<0, 16, NoDifferentialPrivacy> for Vdaf { + fn add_noise_to_agg_share( + &self, + _dp_strategy: &NoDifferentialPrivacy, + _agg_param: &Self::AggregationParam, + _agg_share: &mut Self::AggregateShare, + _num_measurements: usize, + ) -> Result<(), prio::vdaf::VdafError> { + Ok(()) + } +} + +//////////////////////////////////////////////////////////////// +// identity strategy implementations for vdafs from libprio +impl TypeWithNoise for prio::flp::types::Sum { + fn add_noise_to_result( + &self, + _dp_strategy: &NoDifferentialPrivacy, + _agg_result: &mut [Self::Field], + _num_measurements: usize, + ) -> Result<(), prio::flp::FlpError> { + Ok(()) + } +} +impl TypeWithNoise for prio::flp::types::Count { + fn add_noise_to_result( + &self, + _dp_strategy: &NoDifferentialPrivacy, + _agg_result: &mut [Self::Field], + _num_measurements: usize, + ) -> Result<(), prio::flp::FlpError> { + Ok(()) + } +} +impl TypeWithNoise + for prio::flp::types::Histogram>> +{ + fn add_noise_to_result( + &self, + _dp_strategy: &NoDifferentialPrivacy, + _agg_result: &mut [Self::Field], + _num_measurements: usize, + ) -> Result<(), prio::flp::FlpError> { + Ok(()) + } +} +impl TypeWithNoise + for prio::flp::types::SumVec>> +{ + fn add_noise_to_result( + &self, + _dp_strategy: &NoDifferentialPrivacy, + _agg_result: &mut [Self::Field], + _num_measurements: usize, + ) -> Result<(), prio::flp::FlpError> { + Ok(()) + } +} + +#[cfg(feature = "fpvec_bounded_l2")] +impl TypeWithNoise + for FixedPointBoundedL2VecSum +where + T: Fixed + CompatibleFloat, + SPoly: ParallelSumGadget> + Eq + Clone + 'static, + SBlindPoly: ParallelSumGadget> + Eq + Clone + 'static, +{ + fn add_noise_to_result( + &self, + _dp_strategy: &NoDifferentialPrivacy, + _agg_result: &mut [Self::Field], + _num_measurements: usize, + ) -> Result<(), prio::flp::FlpError> { + Ok(()) + } +} + +impl AggregatorWithNoise<16, 16, NoDifferentialPrivacy> + for prio::vdaf::poplar1::Poplar1 +{ + fn add_noise_to_agg_share( + &self, + _dp_strategy: &NoDifferentialPrivacy, + _agg_param: &Self::AggregationParam, + _agg_share: &mut Self::AggregateShare, + _num_measurements: usize, + ) -> Result<(), prio::vdaf::VdafError> { + Ok(()) + } +} + +//////////////////////////////////////////////////////////////// +// macro to use in dispatch + +/// If the first argument is non-empty, the `true` body is emitted, +/// otherwise, the `false` body is emitted. Useful to generate different +/// code in case an optional argument of an outer macro was given. +#[macro_export] +macro_rules! if_ident_exists { + ($token:ident, true => $body1:tt, false => $body2:tt) => { + $body1 + }; + (, true => $body1:tt, false => $body2:tt) => { + $body2 + }; +} diff --git a/core/src/lib.rs b/core/src/lib.rs index c1a88a10c..2cac66f4c 100644 --- a/core/src/lib.rs +++ b/core/src/lib.rs @@ -3,6 +3,7 @@ use std::future::Future; use tokio::task::JoinHandle; +pub mod dp; pub mod hpke; pub mod http; pub mod report_id; diff --git a/core/src/task.rs b/core/src/task.rs index 2adaca84f..b371f857c 100644 --- a/core/src/task.rs +++ b/core/src/task.rs @@ -14,6 +14,33 @@ pub const DAP_AUTH_HEADER: &str = "DAP-Auth-Token"; /// The length of the verify key parameter for Prio3 & Poplar1 VDAF instantiations. pub const VERIFY_KEY_LENGTH: usize = 16; +/// Bitsize parameter for the `Prio3FixedPointBoundedL2VecSum` VDAF. +#[cfg(feature = "fpvec_bounded_l2")] +#[derive(Debug, Derivative, Clone, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)] +pub enum Prio3FixedPointBoundedL2VecSumBitSize { + BitSize16, + BitSize32, + BitSize64, +} + +/// Contains dedicated enums which describe the differential privacy strategies +/// of a given VDAF. If a VDAF only supports a single strategy, such as for example +/// `NoDifferentialPrivacy`, then no enum is required. +#[cfg(feature = "fpvec_bounded_l2")] +pub mod vdaf_instance_strategies { + use derivative::Derivative; + use prio::dp::distributions::ZCdpDiscreteGaussian; + use serde::{Deserialize, Serialize}; + + /// Differential privacy strategies supported by `Prio3FixedPointBoundedL2VecSum`. + #[derive(Debug, Derivative, Clone, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)] + #[serde(tag = "dp_strategy")] + pub enum Prio3FixedPointBoundedL2VecSum { + NoDifferentialPrivacy, + ZCdpDiscreteGaussian(ZCdpDiscreteGaussian), + } +} + /// Identifiers for supported VDAFs, corresponding to definitions in /// [draft-irtf-cfrg-vdaf-03][1] and implementations in [`prio::vdaf::prio3`]. /// @@ -32,15 +59,13 @@ pub enum VdafInstance { Prio3SumVec { bits: usize, length: usize }, /// A `Prio3` histogram with `length` buckets in it. Prio3Histogram { length: usize }, - /// A `Prio3` 16-bit fixed point vector sum with bounded L2 norm. + /// A `Prio3` fixed point vector sum with bounded L2 norm. #[cfg(feature = "fpvec_bounded_l2")] - Prio3FixedPoint16BitBoundedL2VecSum { length: usize }, - /// A `Prio3` 32-bit fixed point vector sum with bounded L2 norm. - #[cfg(feature = "fpvec_bounded_l2")] - Prio3FixedPoint32BitBoundedL2VecSum { length: usize }, - /// A `Prio3` 64-bit fixedpoint vector sum with bounded L2 norm. - #[cfg(feature = "fpvec_bounded_l2")] - Prio3FixedPoint64BitBoundedL2VecSum { length: usize }, + Prio3FixedPointBoundedL2VecSum { + bitsize: Prio3FixedPointBoundedL2VecSumBitSize, + dp_strategy: vdaf_instance_strategies::Prio3FixedPointBoundedL2VecSum, + length: usize, + }, /// The `poplar1` VDAF. Support for this VDAF is experimental. Poplar1 { bits: usize }, @@ -113,41 +138,65 @@ impl TryFrom<&taskprov::VdafType> for VdafInstance { #[macro_export] macro_rules! vdaf_dispatch_impl_base { // Provide the dispatched type only, don't construct a VDAF instance. - (impl match base $vdaf_instance:expr, (_, $Vdaf:ident, $VERIFY_KEY_LEN:ident) => $body:tt) => { + (impl match base $vdaf_instance:expr, (_, $Vdaf:ident, $VERIFY_KEY_LEN:ident $(, $DpStrategy:ident, $dp_strategy:ident )?) => $body:tt) => { match $vdaf_instance { ::janus_core::task::VdafInstance::Prio3Count => { type $Vdaf = ::prio::vdaf::prio3::Prio3Count; const $VERIFY_KEY_LEN: usize = ::janus_core::task::VERIFY_KEY_LENGTH; + $( + type $DpStrategy = janus_core::dp::NoDifferentialPrivacy; + let $dp_strategy = janus_core::dp::NoDifferentialPrivacy; + )? $body } ::janus_core::task::VdafInstance::Prio3CountVec { length } => { - type $Vdaf = ::prio::vdaf::prio3::Prio3SumVecMultithreaded; + type $Vdaf = ::prio::vdaf::prio3::Prio3SumVecMultithreaded;; const $VERIFY_KEY_LEN: usize = ::janus_core::task::VERIFY_KEY_LENGTH; + $( + type $DpStrategy = janus_core::dp::NoDifferentialPrivacy; + let $dp_strategy = janus_core::dp::NoDifferentialPrivacy; + )? $body } ::janus_core::task::VdafInstance::Prio3Sum { bits } => { - type $Vdaf = ::prio::vdaf::prio3::Prio3Sum; + type $Vdaf = ::prio::vdaf::prio3::Prio3Sum;; const $VERIFY_KEY_LEN: usize = ::janus_core::task::VERIFY_KEY_LENGTH; + $( + type $DpStrategy = janus_core::dp::NoDifferentialPrivacy; + let $dp_strategy = janus_core::dp::NoDifferentialPrivacy; + )? $body } ::janus_core::task::VdafInstance::Prio3SumVec { bits, length } => { - type $Vdaf = ::prio::vdaf::prio3::Prio3SumVecMultithreaded; + type $Vdaf = ::prio::vdaf::prio3::Prio3SumVecMultithreaded;; const $VERIFY_KEY_LEN: usize = ::janus_core::task::VERIFY_KEY_LENGTH; + $( + type $DpStrategy = janus_core::dp::NoDifferentialPrivacy; + let $dp_strategy = janus_core::dp::NoDifferentialPrivacy; + )? $body } ::janus_core::task::VdafInstance::Prio3Histogram { buckets } => { - type $Vdaf = ::prio::vdaf::prio3::Prio3Histogram; + type $Vdaf = ::prio::vdaf::prio3::Prio3Histogram;; const $VERIFY_KEY_LEN: usize = ::janus_core::task::VERIFY_KEY_LENGTH; + $( + type $DpStrategy = janus_core::dp::NoDifferentialPrivacy; + let $dp_strategy = janus_core::dp::NoDifferentialPrivacy; + )? $body } ::janus_core::task::VdafInstance::Poplar1 { bits } => { - type $Vdaf = ::prio::vdaf::poplar1::Poplar1<::prio::vdaf::prg::PrgSha3, 16>; + type $Vdaf = ::prio::vdaf::poplar1::Poplar1<::prio::vdaf::prg::PrgSha3, 16>;; const $VERIFY_KEY_LEN: usize = ::janus_core::task::VERIFY_KEY_LENGTH; + $( + type $DpStrategy = janus_core::dp::NoDifferentialPrivacy; + let $dp_strategy = janus_core::dp::NoDifferentialPrivacy; + )? $body } @@ -156,12 +205,16 @@ macro_rules! vdaf_dispatch_impl_base { }; // Construct a VDAF instance, and provide that to the block as well. - (impl match base $vdaf_instance:expr, ($vdaf:ident, $Vdaf:ident, $VERIFY_KEY_LEN:ident) => $body:tt) => { + (impl match base $vdaf_instance:expr, ($vdaf:ident, $Vdaf:ident, $VERIFY_KEY_LEN:ident $(, $DpStrategy:ident, $dp_strategy:ident )?) => $body:tt) => { match $vdaf_instance { ::janus_core::task::VdafInstance::Prio3Count => { let $vdaf = ::prio::vdaf::prio3::Prio3::new_count(2)?; - type $Vdaf = ::prio::vdaf::prio3::Prio3Count; + type $Vdaf = ::prio::vdaf::prio3::Prio3Count;; const $VERIFY_KEY_LEN: usize = ::janus_core::task::VERIFY_KEY_LENGTH; + $( + type $DpStrategy = janus_core::dp::NoDifferentialPrivacy; + let $dp_strategy = janus_core::dp::NoDifferentialPrivacy; + )? $body } @@ -175,13 +228,21 @@ macro_rules! vdaf_dispatch_impl_base { )?; type $Vdaf = ::prio::vdaf::prio3::Prio3SumVecMultithreaded; const $VERIFY_KEY_LEN: usize = ::janus_core::task::VERIFY_KEY_LENGTH; + $( + type $DpStrategy = janus_core::dp::NoDifferentialPrivacy; + let $dp_strategy = janus_core::dp::NoDifferentialPrivacy; + )? $body } ::janus_core::task::VdafInstance::Prio3Sum { bits } => { let $vdaf = ::prio::vdaf::prio3::Prio3::new_sum(2, *bits)?; - type $Vdaf = ::prio::vdaf::prio3::Prio3Sum; + type $Vdaf = ::prio::vdaf::prio3::Prio3Sum;; const $VERIFY_KEY_LEN: usize = ::janus_core::task::VERIFY_KEY_LENGTH; + $( + type $DpStrategy = janus_core::dp::NoDifferentialPrivacy; + let $dp_strategy = janus_core::dp::NoDifferentialPrivacy; + )? $body } @@ -194,6 +255,10 @@ macro_rules! vdaf_dispatch_impl_base { )?; type $Vdaf = ::prio::vdaf::prio3::Prio3SumVecMultithreaded; const $VERIFY_KEY_LEN: usize = ::janus_core::task::VERIFY_KEY_LENGTH; + $( + type $DpStrategy = janus_core::dp::NoDifferentialPrivacy; + let $dp_strategy = janus_core::dp::NoDifferentialPrivacy; + )? $body } @@ -205,6 +270,10 @@ macro_rules! vdaf_dispatch_impl_base { )?; type $Vdaf = ::prio::vdaf::prio3::Prio3Histogram; const $VERIFY_KEY_LEN: usize = ::janus_core::task::VERIFY_KEY_LENGTH; + $( + type $DpStrategy = janus_core::dp::NoDifferentialPrivacy; + let $dp_strategy = janus_core::dp::NoDifferentialPrivacy; + )? $body } @@ -212,6 +281,10 @@ macro_rules! vdaf_dispatch_impl_base { let $vdaf = ::prio::vdaf::poplar1::Poplar1::new_shake128(*bits); type $Vdaf = ::prio::vdaf::poplar1::Poplar1<::prio::vdaf::xof::XofShake128, 16>; const $VERIFY_KEY_LEN: usize = ::janus_core::task::VERIFY_KEY_LENGTH; + $( + type $DpStrategy = janus_core::dp::NoDifferentialPrivacy; + let $dp_strategy = janus_core::dp::NoDifferentialPrivacy; + )? $body } @@ -227,76 +300,91 @@ macro_rules! vdaf_dispatch_impl_fpvec_bounded_l2 { // Provide the dispatched type only, don't construct a VDAF instance. (impl match fpvec_bounded_l2 $vdaf_instance:expr, (_, $Vdaf:ident, $VERIFY_KEY_LEN:ident) => $body:tt) => { match $vdaf_instance { - ::janus_core::task::VdafInstance::Prio3FixedPoint16BitBoundedL2VecSum { length } => { - type $Vdaf = ::prio::vdaf::prio3::Prio3FixedPointBoundedL2VecSumMultithreaded< - ::fixed::FixedI16<::fixed::types::extra::U15>, - >; + ::janus_core::task::VdafInstance::Prio3FixedPointBoundedL2VecSum { bitsize, dp_strategy, length } => { const $VERIFY_KEY_LEN: usize = ::janus_core::task::VERIFY_KEY_LENGTH; - $body + janus_core::vdaf_dispatch_impl_fpvec_bounded_l2!(@dispatch_bitsize bitsize, $Vdaf => $body) } - ::janus_core::task::VdafInstance::Prio3FixedPoint32BitBoundedL2VecSum { length } => { - type $Vdaf = ::prio::vdaf::prio3::Prio3FixedPointBoundedL2VecSumMultithreaded< - ::fixed::FixedI32<::fixed::types::extra::U31>, - >; - const $VERIFY_KEY_LEN: usize = ::janus_core::task::VERIFY_KEY_LENGTH; - $body - } + _ => unreachable!(), + } + }; - ::janus_core::task::VdafInstance::Prio3FixedPoint64BitBoundedL2VecSum { length } => { - type $Vdaf = ::prio::vdaf::prio3::Prio3FixedPointBoundedL2VecSumMultithreaded< - ::fixed::FixedI64<::fixed::types::extra::U63>, - >; + // Construct a VDAF instance, and provide that to the block as well. + (impl match fpvec_bounded_l2 $vdaf_instance:expr, ($vdaf:ident, $Vdaf:ident, $VERIFY_KEY_LEN:ident $(, $DpStrategy:ident, $dp_strategy:ident )?) => $body:tt) => { + match $vdaf_instance { + ::janus_core::task::VdafInstance::Prio3FixedPointBoundedL2VecSum { bitsize, dp_strategy, length } => { const $VERIFY_KEY_LEN: usize = ::janus_core::task::VERIFY_KEY_LENGTH; - $body - } + + janus_core::if_ident_exists!( + $($DpStrategy)?, + true => { + match dp_strategy.clone() { + janus_core::task::vdaf_instance_strategies::Prio3FixedPointBoundedL2VecSum::ZCdpDiscreteGaussian(strategy) => { + $( + type $DpStrategy = ::prio::dp::distributions::ZCdpDiscreteGaussian; + let $dp_strategy = strategy; + )? + janus_core::vdaf_dispatch_impl_fpvec_bounded_l2!(@dispatch_bitsize bitsize, $Vdaf, $vdaf, length => $body) + }, + janus_core::task::vdaf_instance_strategies::Prio3FixedPointBoundedL2VecSum::NoDifferentialPrivacy => { + $( + type $DpStrategy = janus_core::dp::NoDifferentialPrivacy; + let $dp_strategy = janus_core::dp::NoDifferentialPrivacy; + )? + janus_core::vdaf_dispatch_impl_fpvec_bounded_l2!(@dispatch_bitsize bitsize, $Vdaf, $vdaf, length => $body) + } + } + }, + false => { + janus_core::vdaf_dispatch_impl_fpvec_bounded_l2!(@dispatch_bitsize bitsize, $Vdaf, $vdaf, length => $body) + } + ) + }, _ => unreachable!(), } }; - // Construct a VDAF instance, and provide that to the block as well. - (impl match fpvec_bounded_l2 $vdaf_instance:expr, ($vdaf:ident, $Vdaf:ident, $VERIFY_KEY_LEN:ident) => $body:tt) => { - match $vdaf_instance { - ::janus_core::task::VdafInstance::Prio3FixedPoint16BitBoundedL2VecSum { length } => { + (@dispatch_bitsize $bitsize:ident, $Vdaf:ident $(, $vdaf:ident, $length:ident)? => $body:tt) => { + match $bitsize { + janus_core::task::Prio3FixedPointBoundedL2VecSumBitSize::BitSize16 => { + $( let $vdaf = ::prio::vdaf::prio3::Prio3::new_fixedpoint_boundedl2_vec_sum_multithreaded( - 2, *length, + 2, *$length, )?; + )? type $Vdaf = ::prio::vdaf::prio3::Prio3FixedPointBoundedL2VecSumMultithreaded< ::fixed::FixedI16<::fixed::types::extra::U15>, >; - const $VERIFY_KEY_LEN: usize = ::janus_core::task::VERIFY_KEY_LENGTH; $body - } - - ::janus_core::task::VdafInstance::Prio3FixedPoint32BitBoundedL2VecSum { length } => { + }, + janus_core::task::Prio3FixedPointBoundedL2VecSumBitSize::BitSize32 => { + $( let $vdaf = ::prio::vdaf::prio3::Prio3::new_fixedpoint_boundedl2_vec_sum_multithreaded( - 2, *length, + 2, *$length, )?; + )? type $Vdaf = ::prio::vdaf::prio3::Prio3FixedPointBoundedL2VecSumMultithreaded< ::fixed::FixedI32<::fixed::types::extra::U31>, >; - const $VERIFY_KEY_LEN: usize = ::janus_core::task::VERIFY_KEY_LENGTH; $body - } - - ::janus_core::task::VdafInstance::Prio3FixedPoint64BitBoundedL2VecSum { length } => { + }, + janus_core::task::Prio3FixedPointBoundedL2VecSumBitSize::BitSize64 => { + $( let $vdaf = ::prio::vdaf::prio3::Prio3::new_fixedpoint_boundedl2_vec_sum_multithreaded( - 2, *length, + 2, *$length, )?; + )? type $Vdaf = ::prio::vdaf::prio3::Prio3FixedPointBoundedL2VecSumMultithreaded< ::fixed::FixedI64<::fixed::types::extra::U63>, >; - const $VERIFY_KEY_LEN: usize = ::janus_core::task::VERIFY_KEY_LENGTH; $body - } - - _ => unreachable!(), - } - }; + }, + }; + } } /// Internal implementation details of [`vdaf_dispatch`](crate::vdaf_dispatch). @@ -304,23 +392,35 @@ macro_rules! vdaf_dispatch_impl_fpvec_bounded_l2 { #[macro_export] macro_rules! vdaf_dispatch_impl_test_util { // Provide the dispatched type only, don't construct a VDAF instance. - (impl match test_util $vdaf_instance:expr, (_, $Vdaf:ident, $VERIFY_KEY_LEN:ident) => $body:tt) => { + (impl match test_util $vdaf_instance:expr, (_, $Vdaf:ident, $VERIFY_KEY_LEN:ident $(, $DpStrategy:ident, $dp_strategy:ident )?) => $body:tt) => { match $vdaf_instance { ::janus_core::task::VdafInstance::Fake => { type $Vdaf = ::janus_core::test_util::dummy_vdaf::Vdaf; const $VERIFY_KEY_LEN: usize = 0; + $( + type $DpStrategy = janus_core::dp::NoDifferentialPrivacy; + let $dp_strategy = janus_core::dp::NoDifferentialPrivacy; + )? $body } ::janus_core::task::VdafInstance::FakeFailsPrepInit => { type $Vdaf = ::janus_core::test_util::dummy_vdaf::Vdaf; const $VERIFY_KEY_LEN: usize = 0; + $( + type $DpStrategy = janus_core::dp::NoDifferentialPrivacy; + let $dp_strategy = janus_core::dp::NoDifferentialPrivacy; + )? $body } ::janus_core::task::VdafInstance::FakeFailsPrepStep => { type $Vdaf = ::janus_core::test_util::dummy_vdaf::Vdaf; const $VERIFY_KEY_LEN: usize = 0; + $( + type $DpStrategy = janus_core::dp::NoDifferentialPrivacy; + let $dp_strategy = janus_core::dp::NoDifferentialPrivacy; + )? $body } @@ -329,12 +429,16 @@ macro_rules! vdaf_dispatch_impl_test_util { }; // Construct a VDAF instance, and provide that to the block as well. - (impl match test_util $vdaf_instance:expr, ($vdaf:ident, $Vdaf:ident, $VERIFY_KEY_LEN:ident) => $body:tt) => { + (impl match test_util $vdaf_instance:expr, ($vdaf:ident, $Vdaf:ident, $VERIFY_KEY_LEN:ident $(, $DpStrategy:ident, $dp_strategy:ident )?) => $body:tt) => { match $vdaf_instance { ::janus_core::task::VdafInstance::Fake => { let $vdaf = ::janus_core::test_util::dummy_vdaf::Vdaf::new(); type $Vdaf = ::janus_core::test_util::dummy_vdaf::Vdaf; const $VERIFY_KEY_LEN: usize = 0; + $( + type $DpStrategy = janus_core::dp::NoDifferentialPrivacy; + let $dp_strategy = janus_core::dp::NoDifferentialPrivacy; + )? $body } @@ -348,6 +452,10 @@ macro_rules! vdaf_dispatch_impl_test_util { ); type $Vdaf = ::janus_core::test_util::dummy_vdaf::Vdaf; const $VERIFY_KEY_LEN: usize = 0; + $( + type $DpStrategy = janus_core::dp::NoDifferentialPrivacy; + let $dp_strategy = janus_core::dp::NoDifferentialPrivacy; + )? $body } @@ -368,6 +476,10 @@ macro_rules! vdaf_dispatch_impl_test_util { ); type $Vdaf = ::janus_core::test_util::dummy_vdaf::Vdaf; const $VERIFY_KEY_LEN: usize = 0; + $( + type $DpStrategy = janus_core::dp::NoDifferentialPrivacy; + let $dp_strategy = janus_core::dp::NoDifferentialPrivacy; + )? $body } @@ -381,7 +493,7 @@ macro_rules! vdaf_dispatch_impl_test_util { #[macro_export] macro_rules! vdaf_dispatch_impl { // Provide the dispatched type only, don't construct a VDAF instance. - (impl match all $vdaf_instance:expr, (_, $Vdaf:ident, $VERIFY_KEY_LEN:ident) => $body:tt) => { + (impl match all $vdaf_instance:expr, (_, $Vdaf:ident, $VERIFY_KEY_LEN:ident $(, $DpStrategy:ident, $dp_strategy:ident )?) => $body:tt) => { match $vdaf_instance { ::janus_core::task::VdafInstance::Prio3Count | ::janus_core::task::VdafInstance::Prio3CountVec { .. } @@ -389,19 +501,17 @@ macro_rules! vdaf_dispatch_impl { | ::janus_core::task::VdafInstance::Prio3SumVec { .. } | ::janus_core::task::VdafInstance::Prio3Histogram { .. } | ::janus_core::task::VdafInstance::Poplar1 { .. } => { - ::janus_core::vdaf_dispatch_impl_base!(impl match base $vdaf_instance, (_, $Vdaf, $VERIFY_KEY_LEN) => $body) + ::janus_core::vdaf_dispatch_impl_base!(impl match base $vdaf_instance, (_, $Vdaf, $VERIFY_KEY_LEN $(, $DpStrategy, $dp_strategy)?) => $body) } - ::janus_core::task::VdafInstance::Prio3FixedPoint16BitBoundedL2VecSum { .. } - | ::janus_core::task::VdafInstance::Prio3FixedPoint32BitBoundedL2VecSum { .. } - | ::janus_core::task::VdafInstance::Prio3FixedPoint64BitBoundedL2VecSum { .. } => { - ::janus_core::vdaf_dispatch_impl_fpvec_bounded_l2!(impl match fpvec_bounded_l2 $vdaf_instance, (_, $Vdaf, $VERIFY_KEY_LEN) => $body) + ::janus_core::task::VdafInstance::Prio3FixedPointBoundedL2VecSum { .. } => { + ::janus_core::vdaf_dispatch_impl_fpvec_bounded_l2!(impl match fpvec_bounded_l2 $vdaf_instance, (_, $Vdaf, $VERIFY_KEY_LEN $(, $DpStrategy, $dp_strategy)?) => $body) } ::janus_core::task::VdafInstance::Fake | ::janus_core::task::VdafInstance::FakeFailsPrepInit | ::janus_core::task::VdafInstance::FakeFailsPrepStep => { - ::janus_core::vdaf_dispatch_impl_test_util!(impl match test_util $vdaf_instance, (_, $Vdaf, $VERIFY_KEY_LEN) => $body) + ::janus_core::vdaf_dispatch_impl_test_util!(impl match test_util $vdaf_instance, (_, $Vdaf, $VERIFY_KEY_LEN $(, $DpStrategy, $dp_strategy)?) => $body) } _ => panic!("VDAF {:?} is not yet supported", $vdaf_instance), @@ -409,7 +519,7 @@ macro_rules! vdaf_dispatch_impl { }; // Construct a VDAF instance, and provide that to the block as well. - (impl match all $vdaf_instance:expr, ($vdaf:ident, $Vdaf:ident, $VERIFY_KEY_LEN:ident) => $body:tt) => { + (impl match all $vdaf_instance:expr, ($vdaf:ident, $Vdaf:ident, $VERIFY_KEY_LEN:ident $(, $DpStrategy:ident, $dp_strategy:ident )?) => $body:tt) => { match $vdaf_instance { ::janus_core::task::VdafInstance::Prio3Count | ::janus_core::task::VdafInstance::Prio3CountVec { .. } @@ -417,19 +527,17 @@ macro_rules! vdaf_dispatch_impl { | ::janus_core::task::VdafInstance::Prio3SumVec { .. } | ::janus_core::task::VdafInstance::Prio3Histogram { .. } | ::janus_core::task::VdafInstance::Poplar1 { .. } => { - ::janus_core::vdaf_dispatch_impl_base!(impl match base $vdaf_instance, ($vdaf, $Vdaf, $VERIFY_KEY_LEN) => $body) + ::janus_core::vdaf_dispatch_impl_base!(impl match base $vdaf_instance, ($vdaf, $Vdaf, $VERIFY_KEY_LEN $(, $DpStrategy, $dp_strategy)?) => $body) } - ::janus_core::task::VdafInstance::Prio3FixedPoint16BitBoundedL2VecSum { .. } - | ::janus_core::task::VdafInstance::Prio3FixedPoint32BitBoundedL2VecSum { .. } - | ::janus_core::task::VdafInstance::Prio3FixedPoint64BitBoundedL2VecSum { .. } => { - ::janus_core::vdaf_dispatch_impl_fpvec_bounded_l2!(impl match fpvec_bounded_l2 $vdaf_instance, ($vdaf, $Vdaf, $VERIFY_KEY_LEN) => $body) + ::janus_core::task::VdafInstance::Prio3FixedPointBoundedL2VecSum { .. } => { + ::janus_core::vdaf_dispatch_impl_fpvec_bounded_l2!(impl match fpvec_bounded_l2 $vdaf_instance, ($vdaf, $Vdaf, $VERIFY_KEY_LEN $(, $DpStrategy, $dp_strategy)?) => $body) } ::janus_core::task::VdafInstance::Fake | ::janus_core::task::VdafInstance::FakeFailsPrepInit | ::janus_core::task::VdafInstance::FakeFailsPrepStep => { - ::janus_core::vdaf_dispatch_impl_test_util!(impl match test_util $vdaf_instance, ($vdaf, $Vdaf, $VERIFY_KEY_LEN) => $body) + ::janus_core::vdaf_dispatch_impl_test_util!(impl match test_util $vdaf_instance, ($vdaf, $Vdaf, $VERIFY_KEY_LEN $(, $DpStrategy, $dp_strategy)?) => $body) } _ => panic!("VDAF {:?} is not yet supported", $vdaf_instance), @@ -442,7 +550,7 @@ macro_rules! vdaf_dispatch_impl { #[macro_export] macro_rules! vdaf_dispatch_impl { // Provide the dispatched type only, don't construct a VDAF instance. - (impl match all $vdaf_instance:expr, (_, $Vdaf:ident, $VERIFY_KEY_LEN:ident) => $body:tt) => { + (impl match all $vdaf_instance:expr, (_, $Vdaf:ident, $VERIFY_KEY_LEN:ident $(, $DpStrategy:ident, $dp_strategy:ident )?) => $body:tt) => { match $vdaf_instance { ::janus_core::task::VdafInstance::Prio3Count | ::janus_core::task::VdafInstance::Prio3CountVec { .. } @@ -450,13 +558,11 @@ macro_rules! vdaf_dispatch_impl { | ::janus_core::task::VdafInstance::Prio3SumVec { .. } | ::janus_core::task::VdafInstance::Prio3Histogram { .. } | ::janus_core::task::VdafInstance::Poplar1 { .. } => { - ::janus_core::vdaf_dispatch_impl_base!(impl match base $vdaf_instance, (_, $Vdaf, $VERIFY_KEY_LEN) => $body) + ::janus_core::vdaf_dispatch_impl_base!(impl match base $vdaf_instance, (_, $Vdaf, $VERIFY_KEY_LEN $(, $DpStrategy, $dp_strategy)?) => $body) } - ::janus_core::task::VdafInstance::Prio3FixedPoint16BitBoundedL2VecSum { .. } - | ::janus_core::task::VdafInstance::Prio3FixedPoint32BitBoundedL2VecSum { .. } - | ::janus_core::task::VdafInstance::Prio3FixedPoint64BitBoundedL2VecSum { .. } => { - ::janus_core::vdaf_dispatch_impl_fpvec_bounded_l2!(impl match fpvec_bounded_l2 $vdaf_instance, (_, $Vdaf, $VERIFY_KEY_LEN) => $body) + ::janus_core::task::VdafInstance::Prio3FixedPointBoundedL2VecSum { .. } => { + ::janus_core::vdaf_dispatch_impl_fpvec_bounded_l2!(impl match fpvec_bounded_l2 $vdaf_instance, (_, $Vdaf, $VERIFY_KEY_LEN $(, $DpStrategy, $dp_strategy)?) => $body) } _ => panic!("VDAF {:?} is not yet supported", $vdaf_instance), @@ -464,7 +570,7 @@ macro_rules! vdaf_dispatch_impl { }; // Construct a VDAF instance, and provide that to the block as well. - (impl match all $vdaf_instance:expr, ($vdaf:ident, $Vdaf:ident, $VERIFY_KEY_LEN:ident) => $body:tt) => { + (impl match all $vdaf_instance:expr, ($vdaf:ident, $Vdaf:ident, $VERIFY_KEY_LEN:ident $(, $DpStrategy:ident, $dp_strategy:ident )?) => $body:tt) => { match $vdaf_instance { ::janus_core::task::VdafInstance::Prio3Count | ::janus_core::task::VdafInstance::Prio3CountVec { .. } @@ -472,13 +578,11 @@ macro_rules! vdaf_dispatch_impl { | ::janus_core::task::VdafInstance::Prio3SumVec { .. } | ::janus_core::task::VdafInstance::Prio3Histogram { .. } | ::janus_core::task::VdafInstance::Poplar1 { .. } => { - ::janus_core::vdaf_dispatch_impl_base!(impl match base $vdaf_instance, ($vdaf, $Vdaf, $VERIFY_KEY_LEN) => $body) + ::janus_core::vdaf_dispatch_impl_base!(impl match base $vdaf_instance, ($vdaf, $Vdaf, $VERIFY_KEY_LEN $(, $DpStrategy, $dp_strategy)?) => $body) } - ::janus_core::task::VdafInstance::Prio3FixedPoint16BitBoundedL2VecSum { .. } - | ::janus_core::task::VdafInstance::Prio3FixedPoint32BitBoundedL2VecSum { .. } - | ::janus_core::task::VdafInstance::Prio3FixedPoint64BitBoundedL2VecSum { .. } => { - ::janus_core::vdaf_dispatch_impl_fpvec_bounded_l2!(impl match fpvec_bounded_l2 $vdaf_instance, ($vdaf, $Vdaf, $VERIFY_KEY_LEN) => $body) + ::janus_core::task::VdafInstance::Prio3FixedPointBoundedL2VecSum { .. } => { + ::janus_core::vdaf_dispatch_impl_fpvec_bounded_l2!(impl match fpvec_bounded_l2 $vdaf_instance, ($vdaf, $Vdaf, $VERIFY_KEY_LEN $(, $DpStrategy, $dp_strategy)?) => $body) } _ => panic!("VDAF {:?} is not yet supported", $vdaf_instance), @@ -491,7 +595,7 @@ macro_rules! vdaf_dispatch_impl { #[macro_export] macro_rules! vdaf_dispatch_impl { // Provide the dispatched type only, don't construct a VDAF instance. - (impl match all $vdaf_instance:expr, (_, $Vdaf:ident, $VERIFY_KEY_LEN:ident) => $body:tt) => { + (impl match all $vdaf_instance:expr, (_, $Vdaf:ident, $VERIFY_KEY_LEN:ident $(, $DpStrategy:ident, $dp_strategy:ident )?) => $body:tt) => { match $vdaf_instance { ::janus_core::task::VdafInstance::Prio3Count | ::janus_core::task::VdafInstance::Prio3CountVec { .. } @@ -499,13 +603,13 @@ macro_rules! vdaf_dispatch_impl { | ::janus_core::task::VdafInstance::Prio3SumVec { .. } | ::janus_core::task::VdafInstance::Prio3Histogram { .. } | ::janus_core::task::VdafInstance::Poplar1 { .. } => { - ::janus_core::vdaf_dispatch_impl_base!(impl match base $vdaf_instance, (_, $Vdaf, $VERIFY_KEY_LEN) => $body) + ::janus_core::vdaf_dispatch_impl_base!(impl match base $vdaf_instance, (_, $Vdaf, $VERIFY_KEY_LEN $(, $DpStrategy, $dp_strategy)?) => $body) } ::janus_core::task::VdafInstance::Fake | ::janus_core::task::VdafInstance::FakeFailsPrepInit | ::janus_core::task::VdafInstance::FakeFailsPrepStep => { - ::janus_core::vdaf_dispatch_impl_test_util!(impl match test_util $vdaf_instance, (_, $Vdaf, $VERIFY_KEY_LEN) => $body) + ::janus_core::vdaf_dispatch_impl_test_util!(impl match test_util $vdaf_instance, (_, $Vdaf, $VERIFY_KEY_LEN $(, $DpStrategy, $dp_strategy)?) => $body) } _ => panic!("VDAF {:?} is not yet supported", $vdaf_instance), @@ -513,7 +617,7 @@ macro_rules! vdaf_dispatch_impl { }; // Construct a VDAF instance, and provide that to the block as well. - (impl match all $vdaf_instance:expr, ($vdaf:ident, $Vdaf:ident, $VERIFY_KEY_LEN:ident) => $body:tt) => { + (impl match all $vdaf_instance:expr, ($vdaf:ident, $Vdaf:ident, $VERIFY_KEY_LEN:ident $(, $DpStrategy:ident, $dp_strategy:ident )?) => $body:tt) => { match $vdaf_instance { ::janus_core::task::VdafInstance::Prio3Count | ::janus_core::task::VdafInstance::Prio3CountVec { .. } @@ -521,13 +625,13 @@ macro_rules! vdaf_dispatch_impl { | ::janus_core::task::VdafInstance::Prio3SumVec { .. } | ::janus_core::task::VdafInstance::Prio3Histogram { .. } | ::janus_core::task::VdafInstance::Poplar1 { .. } => { - ::janus_core::vdaf_dispatch_impl_base!(impl match base $vdaf_instance, ($vdaf, $Vdaf, $VERIFY_KEY_LEN) => $body) + ::janus_core::vdaf_dispatch_impl_base!(impl match base $vdaf_instance, ($vdaf, $Vdaf, $VERIFY_KEY_LEN $(, $DpStrategy, $dp_strategy)?) => $body) } ::janus_core::task::VdafInstance::Fake | ::janus_core::task::VdafInstance::FakeFailsPrepInit | ::janus_core::task::VdafInstance::FakeFailsPrepStep => { - ::janus_core::vdaf_dispatch_impl_test_util!(impl match test_util $vdaf_instance, ($vdaf, $Vdaf, $VERIFY_KEY_LEN) => $body) + ::janus_core::vdaf_dispatch_impl_test_util!(impl match test_util $vdaf_instance, ($vdaf, $Vdaf, $VERIFY_KEY_LEN $(, $DpStrategy, $dp_strategy)?) => $body) } _ => panic!("VDAF {:?} is not yet supported", $vdaf_instance), @@ -540,7 +644,7 @@ macro_rules! vdaf_dispatch_impl { #[macro_export] macro_rules! vdaf_dispatch_impl { // Provide the dispatched type only, don't construct a VDAF instance. - (impl match all $vdaf_instance:expr, (_, $Vdaf:ident, $VERIFY_KEY_LEN:ident) => $body:tt) => { + (impl match all $vdaf_instance:expr, (_, $Vdaf:ident, $VERIFY_KEY_LEN:ident $(, $DpStrategy:ident, $dp_strategy:ident )?) => $body:tt) => { match $vdaf_instance { ::janus_core::task::VdafInstance::Prio3Count | ::janus_core::task::VdafInstance::Prio3CountVec { .. } @@ -548,7 +652,7 @@ macro_rules! vdaf_dispatch_impl { | ::janus_core::task::VdafInstance::Prio3SumVec { .. } | ::janus_core::task::VdafInstance::Prio3Histogram { .. } | ::janus_core::task::VdafInstance::Poplar1 { .. } => { - ::janus_core::vdaf_dispatch_impl_base!(impl match base $vdaf_instance, (_, $Vdaf, $VERIFY_KEY_LEN) => $body) + ::janus_core::vdaf_dispatch_impl_base!(impl match base $vdaf_instance, (_, $Vdaf, $VERIFY_KEY_LEN $(, $DpStrategy, $dp_strategy)?) => $body) } _ => panic!("VDAF {:?} is not yet supported", $vdaf_instance), @@ -556,7 +660,7 @@ macro_rules! vdaf_dispatch_impl { }; // Construct a VDAF instance, and provide that to the block as well. - (impl match all $vdaf_instance:expr, ($vdaf:ident, $Vdaf:ident, $VERIFY_KEY_LEN:ident) => $body:tt) => { + (impl match all $vdaf_instance:expr, ($vdaf:ident, $Vdaf:ident, $VERIFY_KEY_LEN:ident $(, $DpStrategy:ident, $dp_strategy:ident )?) => $body:tt) => { match $vdaf_instance { ::janus_core::task::VdafInstance::Prio3Count | ::janus_core::task::VdafInstance::Prio3CountVec { .. } @@ -564,7 +668,7 @@ macro_rules! vdaf_dispatch_impl { | ::janus_core::task::VdafInstance::Prio3SumVec { .. } | ::janus_core::task::VdafInstance::Prio3Histogram { .. } | ::janus_core::task::VdafInstance::Poplar1 { .. } => { - ::janus_core::vdaf_dispatch_impl_base!(impl match base $vdaf_instance, ($vdaf, $Vdaf, $VERIFY_KEY_LEN) => $body) + ::janus_core::vdaf_dispatch_impl_base!(impl match base $vdaf_instance, ($vdaf, $Vdaf, $VERIFY_KEY_LEN $(, $DpStrategy, $dp_strategy)?) => $body) } _ => panic!("VDAF {:?} is not yet supported", $vdaf_instance), @@ -604,8 +708,8 @@ macro_rules! vdaf_dispatch { }; // Construct a VDAF instance, and provide that to the block as well. - ($vdaf_instance:expr, ($vdaf:ident, $Vdaf:ident, $VERIFY_KEY_LEN:ident) => $body:tt) => { - ::janus_core::vdaf_dispatch_impl!(impl match all $vdaf_instance, ($vdaf, $Vdaf, $VERIFY_KEY_LEN) => $body) + ($vdaf_instance:expr, ($vdaf:ident, $Vdaf:ident, $VERIFY_KEY_LEN:ident $(, $DpStrategy:ident, $dp_strategy:ident )?) => $body:tt) => { + ::janus_core::vdaf_dispatch_impl!(impl match all $vdaf_instance, ($vdaf, $Vdaf, $VERIFY_KEY_LEN $(, $DpStrategy, $dp_strategy)?) => $body) }; } @@ -776,7 +880,6 @@ pub fn url_ensure_trailing_slash(mut url: Url) -> Url { mod tests { use super::{AuthenticationToken, VdafInstance}; use serde_test::{assert_tokens, Token}; - #[test] fn vdaf_serialization() { // The `Vdaf` type must have a stable serialization, as it gets stored in a JSON database diff --git a/core/src/test_util/dummy_vdaf.rs b/core/src/test_util/dummy_vdaf.rs index dd569fb02..dd903de16 100644 --- a/core/src/test_util/dummy_vdaf.rs +++ b/core/src/test_util/dummy_vdaf.rs @@ -2,6 +2,7 @@ use prio::{ codec::{CodecError, Decode, Encode}, + dp::distributions::ZCdpDiscreteGaussian, vdaf::{self, Aggregatable, PrepareTransition, VdafError}, }; use std::fmt::Debug; @@ -93,6 +94,18 @@ impl vdaf::Vdaf for Vdaf { } } +impl vdaf::AggregatorWithNoise<0, 16, ZCdpDiscreteGaussian> for Vdaf { + fn add_noise_to_agg_share( + &self, + _dp_strategy: &ZCdpDiscreteGaussian, + _agg_param: &Self::AggregationParam, + _agg_share: &mut Self::AggregateShare, + _num_measurements: usize, + ) -> Result<(), VdafError> { + Ok(()) + } +} + impl vdaf::Aggregator<0, 16> for Vdaf { type PrepareState = PrepareState; type PrepareShare = (); diff --git a/docs/samples/tasks.yaml b/docs/samples/tasks.yaml index c4b49efba..caef8ffc0 100644 --- a/docs/samples/tasks.yaml +++ b/docs/samples/tasks.yaml @@ -13,6 +13,10 @@ # The DAP query type. See below for an example of a fixed-size task query_type: TimeInterval + # The differential privacy strategy. Note that it has to be supported + # by the selected VDAF. + dp_strategy: !NoDifferentialPrivacy {} + # The task's VDAF. Each VDAF requires its own set of parameters. vdaf: !Prio3Sum bits: 16 @@ -107,6 +111,7 @@ query_type: !FixedSize max_batch_size: 100 batch_time_window_size: null + dp_strategy: !NoDifferentialPrivacy {} vdaf: Prio3Count role: Helper vdaf_verify_key: "ZXtE4kLqtsCOr8h_pNUeoQ" diff --git a/interop_binaries/src/bin/janus_interop_client.rs b/interop_binaries/src/bin/janus_interop_client.rs index 96ad8c5c3..3d1a05f6d 100644 --- a/interop_binaries/src/bin/janus_interop_client.rs +++ b/interop_binaries/src/bin/janus_interop_client.rs @@ -2,10 +2,13 @@ use anyhow::{anyhow, Context}; use base64::{engine::general_purpose::URL_SAFE_NO_PAD, Engine}; use clap::{value_parser, Arg, Command}; #[cfg(feature = "fpvec_bounded_l2")] -use fixed::types::extra::{U15, U31, U63}; -#[cfg(feature = "fpvec_bounded_l2")] -use fixed::{FixedI16, FixedI32, FixedI64}; +use fixed::{ + types::extra::{U15, U31, U63}, + FixedI16, FixedI32, FixedI64, +}; use janus_client::ClientParameters; +#[cfg(feature = "fpvec_bounded_l2")] +use janus_core::task::Prio3FixedPointBoundedL2VecSumBitSize; use janus_core::{ task::VdafInstance, time::{MockClock, RealClock}, @@ -179,34 +182,40 @@ async fn handle_upload( } #[cfg(feature = "fpvec_bounded_l2")] - VdafInstance::Prio3FixedPoint16BitBoundedL2VecSum { length } => { - let measurement = - parse_vector_measurement::>(request.measurement.clone())?; - let vdaf_client: Prio3FixedPointBoundedL2VecSumMultithreaded> = - Prio3::new_fixedpoint_boundedl2_vec_sum_multithreaded(2, length) - .context("failed to construct Prio3FixedPoint16BitBoundedL2VecSum VDAF")?; - handle_upload_generic(http_client, vdaf_client, request, measurement).await?; - } - - #[cfg(feature = "fpvec_bounded_l2")] - VdafInstance::Prio3FixedPoint32BitBoundedL2VecSum { length } => { - let measurement = - parse_vector_measurement::>(request.measurement.clone())?; - let vdaf_client: Prio3FixedPointBoundedL2VecSumMultithreaded> = - Prio3::new_fixedpoint_boundedl2_vec_sum_multithreaded(2, length) - .context("failed to construct Prio3FixedPoint32BitBoundedL2VecSum VDAF")?; - handle_upload_generic(http_client, vdaf_client, request, measurement).await?; - } + VdafInstance::Prio3FixedPointBoundedL2VecSum { + bitsize, + dp_strategy: _, + length, + } => match bitsize { + Prio3FixedPointBoundedL2VecSumBitSize::BitSize16 => { + let measurement = + parse_vector_measurement::>(request.measurement.clone())?; + let vdaf_client: Prio3FixedPointBoundedL2VecSumMultithreaded> = + Prio3::new_fixedpoint_boundedl2_vec_sum_multithreaded(2, length).context( + "failed to construct Prio3FixedPoint16BitBoundedL2VecSumZCdp VDAF", + )?; + handle_upload_generic(http_client, vdaf_client, request, measurement).await?; + } + Prio3FixedPointBoundedL2VecSumBitSize::BitSize32 => { + let measurement = + parse_vector_measurement::>(request.measurement.clone())?; + let vdaf_client: Prio3FixedPointBoundedL2VecSumMultithreaded> = + Prio3::new_fixedpoint_boundedl2_vec_sum_multithreaded(2, length).context( + "failed to construct Prio3FixedPoint32BitBoundedL2VecSumZCdp VDAF", + )?; + handle_upload_generic(http_client, vdaf_client, request, measurement).await?; + } + Prio3FixedPointBoundedL2VecSumBitSize::BitSize64 => { + let measurement = + parse_vector_measurement::>(request.measurement.clone())?; + let vdaf_client: Prio3FixedPointBoundedL2VecSumMultithreaded> = + Prio3::new_fixedpoint_boundedl2_vec_sum_multithreaded(2, length).context( + "failed to construct Prio3FixedPoint64BitBoundedL2VecSumZCdp VDAF", + )?; + handle_upload_generic(http_client, vdaf_client, request, measurement).await?; + } + }, - #[cfg(feature = "fpvec_bounded_l2")] - VdafInstance::Prio3FixedPoint64BitBoundedL2VecSum { length } => { - let measurement = - parse_vector_measurement::>(request.measurement.clone())?; - let vdaf_client: Prio3FixedPointBoundedL2VecSumMultithreaded> = - Prio3::new_fixedpoint_boundedl2_vec_sum_multithreaded(2, length) - .context("failed to construct Prio3FixedPoint64BitBoundedL2VecSum VDAF")?; - handle_upload_generic(http_client, vdaf_client, request, measurement).await?; - } _ => panic!("Unsupported VDAF: {vdaf_instance:?}"), } Ok(()) diff --git a/interop_binaries/src/bin/janus_interop_collector.rs b/interop_binaries/src/bin/janus_interop_collector.rs index 436c7bab1..471a24b4f 100644 --- a/interop_binaries/src/bin/janus_interop_collector.rs +++ b/interop_binaries/src/bin/janus_interop_collector.rs @@ -3,10 +3,13 @@ use backoff::ExponentialBackoffBuilder; use base64::{engine::general_purpose::URL_SAFE_NO_PAD, Engine}; use clap::{value_parser, Arg, Command}; #[cfg(feature = "fpvec_bounded_l2")] -use fixed::types::extra::{U15, U31, U63}; -#[cfg(feature = "fpvec_bounded_l2")] -use fixed::{FixedI16, FixedI32, FixedI64}; +use fixed::{ + types::extra::{U15, U31, U63}, + FixedI16, FixedI32, FixedI64, +}; use janus_collector::{Collector, CollectorParameters}; +#[cfg(feature = "fpvec_bounded_l2")] +use janus_core::task::Prio3FixedPointBoundedL2VecSumBitSize; use janus_core::{ hpke::HpkeKeypair, task::{AuthenticationToken, VdafInstance}, @@ -388,71 +391,67 @@ async fn handle_collection_start( #[cfg(feature = "fpvec_bounded_l2")] ( ParsedQuery::TimeInterval(batch_interval), - janus_core::task::VdafInstance::Prio3FixedPoint16BitBoundedL2VecSum { length }, - ) => { - let vdaf: Prio3FixedPointBoundedL2VecSumMultithreaded> = - Prio3::new_fixedpoint_boundedl2_vec_sum_multithreaded(2, length) - .context("failed to construct Prio3FixedPoint16BitBoundedL2VecSum VDAF")?; - handle_collect_generic( - http_client, - collector_params, - Query::new_time_interval(batch_interval), - vdaf, - &agg_param, - |_| None, - |result| { - let converted = result.iter().cloned().map(NumberAsString).collect(); - AggregationResult::FloatVec(converted) - }, - ) - .await? - } - - #[cfg(feature = "fpvec_bounded_l2")] - ( - ParsedQuery::TimeInterval(batch_interval), - janus_core::task::VdafInstance::Prio3FixedPoint32BitBoundedL2VecSum { length }, - ) => { - let vdaf: Prio3FixedPointBoundedL2VecSumMultithreaded> = - Prio3::new_fixedpoint_boundedl2_vec_sum_multithreaded(2, length) - .context("failed to construct Prio3FixedPoint32BitBoundedL2VecSum VDAF")?; - handle_collect_generic( - http_client, - collector_params, - Query::new_time_interval(batch_interval), - vdaf, - &agg_param, - |_| None, - |result| { - let converted = result.iter().cloned().map(NumberAsString).collect(); - AggregationResult::FloatVec(converted) - }, - ) - .await? - } - - #[cfg(feature = "fpvec_bounded_l2")] - ( - ParsedQuery::TimeInterval(batch_interval), - janus_core::task::VdafInstance::Prio3FixedPoint64BitBoundedL2VecSum { length }, - ) => { - let vdaf: Prio3FixedPointBoundedL2VecSumMultithreaded> = - Prio3::new_fixedpoint_boundedl2_vec_sum_multithreaded(2, length) - .context("failed to construct Prio3FixedPoint64BitBoundedL2VecSum VDAF")?; - handle_collect_generic( - http_client, - collector_params, - Query::new_time_interval(batch_interval), - vdaf, - &agg_param, - |_| None, - |result| { - let converted = result.iter().cloned().map(NumberAsString).collect(); - AggregationResult::FloatVec(converted) - }, - ) - .await? - } + janus_core::task::VdafInstance::Prio3FixedPointBoundedL2VecSum { + bitsize, + dp_strategy: _, + length, + }, + ) => match bitsize { + Prio3FixedPointBoundedL2VecSumBitSize::BitSize16 => { + let vdaf: Prio3FixedPointBoundedL2VecSumMultithreaded> = + Prio3::new_fixedpoint_boundedl2_vec_sum_multithreaded(2, length) + .context("failed to construct Prio3FixedPoint16BitBoundedL2VecSum VDAF")?; + handle_collect_generic( + http_client, + collector_params, + Query::new_time_interval(batch_interval), + vdaf, + &agg_param, + |_| None, + |result| { + let converted = result.iter().cloned().map(NumberAsString).collect(); + AggregationResult::FloatVec(converted) + }, + ) + .await? + } + Prio3FixedPointBoundedL2VecSumBitSize::BitSize32 => { + let vdaf: Prio3FixedPointBoundedL2VecSumMultithreaded> = + Prio3::new_fixedpoint_boundedl2_vec_sum_multithreaded(2, length) + .context("failed to construct Prio3FixedPoint32BitBoundedL2VecSum VDAF")?; + handle_collect_generic( + http_client, + collector_params, + Query::new_time_interval(batch_interval), + vdaf, + &agg_param, + |_| None, + |result| { + let converted = result.iter().cloned().map(NumberAsString).collect(); + AggregationResult::FloatVec(converted) + }, + ) + .await? + } + Prio3FixedPointBoundedL2VecSumBitSize::BitSize64 => { + let vdaf: Prio3FixedPointBoundedL2VecSumMultithreaded> = + Prio3::new_fixedpoint_boundedl2_vec_sum_multithreaded(2, length) + .context("failed to construct Prio3FixedPoint64BitBoundedL2VecSum VDAF")?; + handle_collect_generic( + http_client, + collector_params, + Query::new_time_interval(batch_interval), + vdaf, + &agg_param, + |_| None, + |result| { + let converted = result.iter().cloned().map(NumberAsString).collect(); + AggregationResult::FloatVec(converted) + }, + ) + .await? + } + }, (ParsedQuery::FixedSize(fixed_size_query), VdafInstance::Prio3Count {}) => { let vdaf = Prio3::new_count(2).context("failed to construct Prio3Count VDAF")?; @@ -490,71 +489,67 @@ async fn handle_collection_start( #[cfg(feature = "fpvec_bounded_l2")] ( ParsedQuery::FixedSize(fixed_size_query), - janus_core::task::VdafInstance::Prio3FixedPoint16BitBoundedL2VecSum { length }, - ) => { - let vdaf: Prio3FixedPointBoundedL2VecSumMultithreaded> = - Prio3::new_fixedpoint_boundedl2_vec_sum_multithreaded(2, length) - .context("failed to construct Prio3FixedPoint16BitBoundedL2VecSum VDAF")?; - handle_collect_generic( - http_client, - collector_params, - Query::new_fixed_size(fixed_size_query), - vdaf, - &agg_param, - |selector| Some(*selector.batch_id()), - |result| { - let converted = result.iter().cloned().map(NumberAsString).collect(); - AggregationResult::FloatVec(converted) - }, - ) - .await? - } - - #[cfg(feature = "fpvec_bounded_l2")] - ( - ParsedQuery::FixedSize(fixed_size_query), - janus_core::task::VdafInstance::Prio3FixedPoint32BitBoundedL2VecSum { length }, - ) => { - let vdaf: Prio3FixedPointBoundedL2VecSumMultithreaded> = - Prio3::new_fixedpoint_boundedl2_vec_sum_multithreaded(2, length) - .context("failed to construct Prio3FixedPoint32BitBoundedL2VecSum VDAF")?; - handle_collect_generic( - http_client, - collector_params, - Query::new_fixed_size(fixed_size_query), - vdaf, - &agg_param, - |selector| Some(*selector.batch_id()), - |result| { - let converted = result.iter().cloned().map(NumberAsString).collect(); - AggregationResult::FloatVec(converted) - }, - ) - .await? - } - - #[cfg(feature = "fpvec_bounded_l2")] - ( - ParsedQuery::FixedSize(fixed_size_query), - janus_core::task::VdafInstance::Prio3FixedPoint64BitBoundedL2VecSum { length }, - ) => { - let vdaf: Prio3FixedPointBoundedL2VecSumMultithreaded> = - Prio3::new_fixedpoint_boundedl2_vec_sum_multithreaded(2, length) - .context("failed to construct Prio3FixedPoint64BitBoundedL2VecSum VDAF")?; - handle_collect_generic( - http_client, - collector_params, - Query::new_fixed_size(fixed_size_query), - vdaf, - &agg_param, - |selector| Some(*selector.batch_id()), - |result| { - let converted = result.iter().cloned().map(NumberAsString).collect(); - AggregationResult::FloatVec(converted) - }, - ) - .await? - } + janus_core::task::VdafInstance::Prio3FixedPointBoundedL2VecSum { + bitsize, + dp_strategy: _, + length, + }, + ) => match bitsize { + Prio3FixedPointBoundedL2VecSumBitSize::BitSize16 => { + let vdaf: Prio3FixedPointBoundedL2VecSumMultithreaded> = + Prio3::new_fixedpoint_boundedl2_vec_sum_multithreaded(2, length) + .context("failed to construct Prio3FixedPoint16BitBoundedL2VecSum VDAF")?; + handle_collect_generic( + http_client, + collector_params, + Query::new_fixed_size(fixed_size_query), + vdaf, + &agg_param, + |selector| Some(*selector.batch_id()), + |result| { + let converted = result.iter().cloned().map(NumberAsString).collect(); + AggregationResult::FloatVec(converted) + }, + ) + .await? + } + Prio3FixedPointBoundedL2VecSumBitSize::BitSize32 => { + let vdaf: Prio3FixedPointBoundedL2VecSumMultithreaded> = + Prio3::new_fixedpoint_boundedl2_vec_sum_multithreaded(2, length) + .context("failed to construct Prio3FixedPoint32BitBoundedL2VecSum VDAF")?; + handle_collect_generic( + http_client, + collector_params, + Query::new_fixed_size(fixed_size_query), + vdaf, + &agg_param, + |selector| Some(*selector.batch_id()), + |result| { + let converted = result.iter().cloned().map(NumberAsString).collect(); + AggregationResult::FloatVec(converted) + }, + ) + .await? + } + Prio3FixedPointBoundedL2VecSumBitSize::BitSize64 => { + let vdaf: Prio3FixedPointBoundedL2VecSumMultithreaded> = + Prio3::new_fixedpoint_boundedl2_vec_sum_multithreaded(2, length) + .context("failed to construct Prio3FixedPoint64BitBoundedL2VecSum VDAF")?; + handle_collect_generic( + http_client, + collector_params, + Query::new_fixed_size(fixed_size_query), + vdaf, + &agg_param, + |selector| Some(*selector.batch_id()), + |result| { + let converted = result.iter().cloned().map(NumberAsString).collect(); + AggregationResult::FloatVec(converted) + }, + ) + .await? + } + }, (ParsedQuery::FixedSize(fixed_size_query), VdafInstance::Prio3Sum { bits }) => { let vdaf = Prio3::new_sum(2, bits).context("failed to construct Prio3Sum VDAF")?; diff --git a/interop_binaries/src/lib.rs b/interop_binaries/src/lib.rs index c18513078..38f1abc56 100644 --- a/interop_binaries/src/lib.rs +++ b/interop_binaries/src/lib.rs @@ -1,5 +1,7 @@ use base64::{engine::general_purpose::URL_SAFE_NO_PAD, Engine}; use janus_aggregator_core::task::{QueryType, Task}; +#[cfg(feature = "fpvec_bounded_l2")] +use janus_core::task::{vdaf_instance_strategies, Prio3FixedPointBoundedL2VecSumBitSize}; use janus_core::{ hpke::{generate_hpke_config_and_private_key, HpkeKeypair}, task::VdafInstance, @@ -120,15 +122,9 @@ pub enum VdafObject { length: NumberAsString, }, #[cfg(feature = "fpvec_bounded_l2")] - Prio3FixedPoint16BitBoundedL2VecSum { - length: NumberAsString, - }, - #[cfg(feature = "fpvec_bounded_l2")] - Prio3FixedPoint32BitBoundedL2VecSum { - length: NumberAsString, - }, - #[cfg(feature = "fpvec_bounded_l2")] - Prio3FixedPoint64BitBoundedL2VecSum { + Prio3FixedPointBoundedL2VecSum { + bitsize: Prio3FixedPointBoundedL2VecSumBitSize, + dp_strategy: vdaf_instance_strategies::Prio3FixedPointBoundedL2VecSum, length: NumberAsString, }, } @@ -156,25 +152,16 @@ impl From for VdafObject { }, #[cfg(feature = "fpvec_bounded_l2")] - VdafInstance::Prio3FixedPoint16BitBoundedL2VecSum { length } => { - VdafObject::Prio3FixedPoint16BitBoundedL2VecSum { - length: NumberAsString(length), - } - } - - #[cfg(feature = "fpvec_bounded_l2")] - VdafInstance::Prio3FixedPoint32BitBoundedL2VecSum { length } => { - VdafObject::Prio3FixedPoint32BitBoundedL2VecSum { - length: NumberAsString(length), - } - } + VdafInstance::Prio3FixedPointBoundedL2VecSum { + bitsize, + dp_strategy, + length, + } => VdafObject::Prio3FixedPointBoundedL2VecSum { + bitsize, + dp_strategy, + length: NumberAsString(length), + }, - #[cfg(feature = "fpvec_bounded_l2")] - VdafInstance::Prio3FixedPoint64BitBoundedL2VecSum { length } => { - VdafObject::Prio3FixedPoint64BitBoundedL2VecSum { - length: NumberAsString(length), - } - } _ => panic!("Unsupported VDAF: {vdaf:?}"), } } @@ -201,19 +188,15 @@ impl From for VdafInstance { } #[cfg(feature = "fpvec_bounded_l2")] - VdafObject::Prio3FixedPoint16BitBoundedL2VecSum { length } => { - VdafInstance::Prio3FixedPoint16BitBoundedL2VecSum { length: length.0 } - } - - #[cfg(feature = "fpvec_bounded_l2")] - VdafObject::Prio3FixedPoint32BitBoundedL2VecSum { length } => { - VdafInstance::Prio3FixedPoint32BitBoundedL2VecSum { length: length.0 } - } - - #[cfg(feature = "fpvec_bounded_l2")] - VdafObject::Prio3FixedPoint64BitBoundedL2VecSum { length } => { - VdafInstance::Prio3FixedPoint64BitBoundedL2VecSum { length: length.0 } - } + VdafObject::Prio3FixedPointBoundedL2VecSum { + bitsize, + dp_strategy, + length, + } => VdafInstance::Prio3FixedPointBoundedL2VecSum { + bitsize, + dp_strategy, + length: length.0, + }, } } } diff --git a/interop_binaries/tests/end_to_end.rs b/interop_binaries/tests/end_to_end.rs index 1c72310be..87150f4a0 100644 --- a/interop_binaries/tests/end_to_end.rs +++ b/interop_binaries/tests/end_to_end.rs @@ -692,7 +692,10 @@ async fn e2e_prio3_fixed16vec() { let fp16_16_inv = fixed!(0.0625: I1F15); let result = run( QueryKind::TimeInterval, - json!({"type": "Prio3FixedPoint16BitBoundedL2VecSum", "length": "3"}), + json!({"type": "Prio3FixedPointBoundedL2VecSum", + "bitsize": "BitSize16", + "dp_strategy": json!( {"dp_strategy": "NoDifferentialPrivacy"}), + "length": "3"}), &[ json!([ fp16_4_inv.to_string(), @@ -728,7 +731,10 @@ async fn e2e_prio3_fixed32vec() { let fp32_16_inv = fixed!(0.0625: I1F31); let result = run( QueryKind::TimeInterval, - json!({"type": "Prio3FixedPoint32BitBoundedL2VecSum", "length": "3"}), + json!({"type": "Prio3FixedPointBoundedL2VecSum", + "bitsize": "BitSize32", + "dp_strategy": json!( {"dp_strategy": "NoDifferentialPrivacy"}), + "length": "3"}), &[ json!([ fp32_4_inv.to_string(), @@ -764,7 +770,10 @@ async fn e2e_prio3_fixed64vec() { let fp64_16_inv = fixed!(0.0625: I1F63); let result = run( QueryKind::TimeInterval, - json!({"type": "Prio3FixedPoint64BitBoundedL2VecSum", "length": "3"}), + json!({"type": "Prio3FixedPointBoundedL2VecSum", + "bitsize": "BitSize64", + "dp_strategy": json!( {"dp_strategy": "NoDifferentialPrivacy"}), + "length": "3"}), &[ json!([ fp64_4_inv.to_string(), @@ -800,7 +809,10 @@ async fn e2e_prio3_fixed16vec_fixed_size() { let fp16_16_inv = fixed!(0.0625: I1F15); let result = run( QueryKind::FixedSize, - json!({"type": "Prio3FixedPoint16BitBoundedL2VecSum", "length": "3"}), + json!({"type": "Prio3FixedPointBoundedL2VecSum", + "bitsize": "BitSize16", + "dp_strategy": json!( {"dp_strategy": "NoDifferentialPrivacy"}), + "length": "3"}), &[ json!([ fp16_4_inv.to_string(), @@ -836,7 +848,10 @@ async fn e2e_prio3_fixed32vec_fixed_size() { let fp32_16_inv = fixed!(0.0625: I1F31); let result = run( QueryKind::FixedSize, - json!({"type": "Prio3FixedPoint32BitBoundedL2VecSum", "length": "3"}), + json!({"type": "Prio3FixedPointBoundedL2VecSum", + "bitsize": "BitSize32", + "dp_strategy": json!( {"dp_strategy": "NoDifferentialPrivacy"}), + "length": "3"}), &[ json!([ fp32_4_inv.to_string(), @@ -872,7 +887,10 @@ async fn e2e_prio3_fixed64vec_fixed_size() { let fp64_16_inv = fixed!(0.0625: I1F63); let result = run( QueryKind::FixedSize, - json!({"type": "Prio3FixedPoint64BitBoundedL2VecSum", "length": "3"}), + json!({"type": "Prio3FixedPointBoundedL2VecSum", + "bitsize": "BitSize64", + "dp_strategy": json!( {"dp_strategy": "NoDifferentialPrivacy"}), + "length": "3"}), &[ json!([ fp64_4_inv.to_string(), diff --git a/messages/Cargo.toml b/messages/Cargo.toml index 58cd7edae..de26860e0 100644 --- a/messages/Cargo.toml +++ b/messages/Cargo.toml @@ -20,7 +20,8 @@ hex = "0.4" num_enum = "0.7.0" # We can't pull prio in from the workspace because that would enable default features, and we do not # want prio/crypto-dependencies -prio = { version = "0.15.1", default-features = false, features = ["multithreaded", "experimental"] } +#prio = { version = "0.15.1", default-features = false, features = ["multithreaded", "experimental"] } +prio = {git = "https://github.com/dpsa4fl/libprio-rs.git", branch ="dp-update-for-janus-rebased", features = ["multithreaded", "experimental"]} rand = "0.8" serde.workspace = true thiserror.workspace = true