From 71d2de31972ec55b02693d798cede656955072c2 Mon Sep 17 00:00:00 2001 From: ovi Date: Fri, 22 Sep 2023 20:06:51 +0200 Subject: [PATCH] Squashed commit of the following: commit 44f6f1eb21ee2ea84506cc26af13e385e2bf56e3 Author: ovi Date: Wed Sep 20 16:41:42 2023 +0200 removing comment commit 58db26da598103c2b7e88fa610f698a70b22e41d Author: Maxim Urschumzew Date: Wed Sep 20 14:37:16 2023 +0200 Add comments. commit cd51caa4d855fad6746f8629601d23cc90e18880 Author: ovi Date: Mon Sep 18 12:40:54 2023 +0200 fixing git dep commit 128bbbac17bdfa0a9b90ca3937651ccd4b90c58c Author: ovi Date: Mon Sep 18 04:26:46 2023 +0200 format commit e9a9ca8401f9756072db9834054472d15697647e Author: ovi Date: Mon Sep 18 04:21:30 2023 +0200 Squashed commit of the following: commit 29f4fd42c6025e1a1c8b85519ecb1d5c55b24c78 Author: ovi Date: Mon Sep 18 01:46:04 2023 +0200 nits commit 6d9503eaa1e2fc4bb46f4952fc3dc76ad3c8ce6d Author: ovi Date: Wed Sep 13 00:51:40 2023 +0200 fix import commit f318903617a61fb6e972b03c92d995590623be82 Author: ovi Date: Tue Sep 12 23:45:00 2023 +0200 import fix commit 82f8b63d55d3c7e924bf9f9bf459f4fe96a07c20 Author: ovi Date: Tue Sep 12 22:36:57 2023 +0200 import fix commit 8a9e33cf37796f14e19f5739ee6f678749c2aff5 Author: ovi Date: Tue Sep 12 19:13:57 2023 +0200 fmt commit 1a6fa3dbca5d9e92c22ef40ef20b52e974a00284 Author: Maxim Urschumzew Date: Tue Sep 12 17:04:28 2023 +0200 Fixing imports and feature gates for clippy. Co-authored-by: Olivia commit 35c52d19560052cb2086c143ae1800d0e72a2b3a Author: ovi Date: Tue Sep 12 18:43:52 2023 +0200 clippy happy commit 340e7f9f9ce68eb5c9d84d5b246a0ebe7bdfe5a7 Author: ovi Date: Tue Sep 12 18:29:30 2023 +0200 enabling Poplar1 again, feature flag cleanup commit c22282e4777c01841350627662f3d51b2e62b050 Author: ovi Date: Tue Sep 12 16:45:08 2023 +0200 cleanup commit d562fdf3ba311faae8c246dc7d700188b0826912 Author: Maxim Urschumzew Date: Tue Sep 12 11:59:42 2023 +0200 Squashed commit of the following: commit 8934f0198d8789e67da5c40f93c736bdd9af866e Author: ovi Date: Mon Sep 11 21:35:29 2023 +0200 fixing e2e tests commit d5e3122077bfb54d72ed2f5c45a438f33bd82eba Author: Maxim Urschumzew Date: Sun Sep 10 14:19:53 2023 +0200 Fix serde error. commit 44b9575e1a98cedd1fca7a2a3cd6e7df4c940f9e Author: Maxim Urschumzew Date: Sun Sep 10 13:06:48 2023 +0200 Fix interop client. commit 3cafe7bf2992101aef1be53757fcc4e48e26b8c1 Author: ovi Date: Sun Sep 10 14:58:24 2023 +0200 updating fpvec vdaf instance struct commit 61b3d02221bdeb3ad501d5893247e3e1d7f8d123 Author: Maxim Urschumzew Date: Sun Sep 10 12:56:22 2023 +0200 Fix lib for interop_binaries. commit f7876e96f0b01c656389a8bcc1ca3bceae1bc436 Author: Maxim Urschumzew Date: Sun Sep 10 12:21:37 2023 +0200 Rewrite vdaf_dispatch macros to for single-case fixedpoint vecs. commit 98013513ede675fea29bd1c8c1f054010d6b6ce0 Author: Maxim Urschumzew Date: Sat Sep 9 16:40:50 2023 +0200 [WIP] Work towards usable macro system for dispatch. - Consolidate VdafInstance cases for fixedpoint types into a single case. - Remove the ZCdp cases for VdafOps for fixedpoint types. Couldn't merge the others because VdafOps contains actual vdaf instances and not VdafInstance objects. commit 2ae563512c859bac09ed241cf62aac56b7ea39f1 Author: Maxim Urschumzew Date: Sat Sep 9 12:41:47 2023 +0200 Add strategy dispatch for collection_job_driver. commit eec935a3644a1ef23d071ec8e3fd9aec6ce77db1 Author: ovi Date: Sat Sep 9 02:18:37 2023 +0200 adding dp strategy arg in aggregator commit c235908d072050760f03d35710bc874474776c57 Author: Maxim Urschumzew Date: Fri Sep 8 19:24:19 2023 +0200 Fix some typos. commit 11ee4884ac53ea3428c735c3c15baf13805e7ece Author: ovi Date: Fri Sep 8 19:13:21 2023 +0200 cleanup commit 469e1a5e8bf7ef1ae3e628ae72f9888cb3e65143 Author: Maxim Urschumzew Date: Fri Sep 8 16:58:10 2023 +0200 Remove dp_strategy from more places. commit ffe707da18a6b0ca4ecbceced4b5be21b103f584 Author: Maxim Urschumzew Date: Fri Sep 8 16:55:59 2023 +0200 Remove dp strategy. commit 7908abb4b86b5bca03eb9b0e3e9af4dd732f34c6 Author: ovi Date: Fri Sep 8 18:54:48 2023 +0200 some last vdaf instance branches commit 69e6795aca8a059d571210add0578dc227ba9e1c Author: ovi Date: Fri Sep 8 18:48:00 2023 +0200 more interop vdafinstance branches commit 357dc972cea02a0a20cbecbbb4cfdc1a098b08ea Author: Maxim Urschumzew Date: Fri Sep 8 16:39:28 2023 +0200 Add NoDifferentialPrivacy instance for fixedvec types. commit 99750c94c3dc8682f8efc2d1db72f7197256fdbc Author: ovi Date: Fri Sep 8 18:38:41 2023 +0200 interop vdafinstance branches commit 6fa4ebbab45322a47d9d356ecb3238d530b7f399 Author: Maxim Urschumzew Date: Fri Sep 8 16:30:40 2023 +0200 Add ZCdp cases in aggregator.rs. commit 16ef61fb0d41e238745d432f3decf770cfbc13d9 Author: ovi Date: Fri Sep 8 18:09:01 2023 +0200 adding enum cases commit 404ae32105a29829318c8131b7cc4ed3b64d40ac Author: Maxim Urschumzew Date: Fri Sep 8 16:02:09 2023 +0200 Remove dp_strategy from task definitions. commit e88107e8a20fefb4de67656836a7ef78d9a013cc Author: Maxim Urschumzew Date: Fri Sep 8 15:55:42 2023 +0200 Remove strategy field from Task struct. commit 46ca5a22eb8b42be8b5c681429f1d45072b90792 Author: Maxim Urschumzew Date: Fri Sep 8 13:24:21 2023 +0200 Add missing strategy field. commit bdd28f464cc6ef83954212aaa65505882e1a17d0 Author: Maxim Urschumzew Date: Fri Sep 8 12:40:09 2023 +0200 Fix json specification of dp strategy. commit fdcf851ff93a16d533374563b7b2e233a0b12ea7 Author: ovi Date: Fri Sep 8 04:08:22 2023 +0200 more serialize mistakes commit 6a069fe1ec37d5add723e20bedaf85a9b38b698e Author: Maxim Urschumzew Date: Tue Sep 5 15:56:30 2023 +0200 Fix more serialization mismatches. commit 891b6c5c9f9880dae92f6b928186b8f36a1785b2 Merge: 5dcd3e4 1fec56f Author: ovi Date: Tue Sep 5 17:23:01 2023 +0200 Merge branch 'janus-m5-v2' of github.com:dpsa-project/janus into janus-m5-v2 commit 5dcd3e422043ae99cde7347db7b6e5d378e9ef38 Author: ovi Date: Tue Sep 5 17:22:44 2023 +0200 reverting Cargo.lock commit 8572387ddc8642031d21790571f9cae9429e8dd4 Merge: e03aeec f8ee1f4 Author: ovi Date: Tue Sep 5 16:48:09 2023 +0200 Merge branch 'janus-m5-v2' of github.com:dpsa-project/janus into janus-m5-v2 commit e03aeec68f8df96f60c95bde5ce9cff73e9fbf82 Author: ovi Date: Tue Sep 5 16:47:42 2023 +0200 fixing macro import stuff commit 1fec56f24da0a3b555d8778b3a03a83d522ee4e8 Author: Maxim Urschumzew Date: Tue Sep 5 14:52:06 2023 +0200 Fix yaml value for test. commit f8ee1f42612c629342f2699b4bea0afaf64fae85 Author: Maxim Urschumzew Date: Tue Sep 5 13:50:41 2023 +0200 Update prio dep. commit a5beebf1f322bfcd59c474b196205064f3d10129 Author: ovi Date: Mon Sep 4 16:42:29 2023 +0200 interop stuff commit 7db08bc26984a1b847aa5fd680a1f77001c52c13 Author: ovi Date: Sun Sep 3 14:19:43 2023 +0200 some clippies commit a6ee8ecf7377ab9e32896e0fbbbde076c8b06e64 Author: Maxim Urschumzew Date: Sat Sep 2 21:42:01 2023 +0200 Call `add_noise_to_aggregate_share` also in collection_job_driver. commit b3a2826bd5e1b0977f269e0ce65d2d8dc298059d Author: Maxim Urschumzew Date: Sat Sep 2 21:35:12 2023 +0200 Fix error type mismatch. commit c126c1d0a54585c30d610e0295f7ad3682a0ee94 Author: Maxim Urschumzew Date: Sat Sep 2 17:02:33 2023 +0200 Fix typo. commit 834654f221c9d465dcec580230a7f2ecd0d3749b Author: ovi Date: Sat Sep 2 18:59:28 2023 +0200 actually adding noise! commit 6dc307c82058e85e914bebdca0642d33cc56b1cd Author: ovi Date: Sat Sep 2 15:31:35 2023 +0200 stretegy_alias for vdaf_dispatch commit 709893de81f8a49054d4ba031682b0454ac47d61 Author: ovi Date: Sat Sep 2 14:05:06 2023 +0200 not creating type alias on every invocation commit b0e14eecf3dddc99505915bb063d023595be36c1 Author: Maxim Urschumzew Date: Sat Sep 2 10:49:24 2023 +0200 Integrate $DpStrategy choice into dispatch macros. commit 8a1aa21be635aa1778a0673bd5f0b6d412491ca6 Author: Maxim Urschumzew Date: Sat Sep 2 09:24:30 2023 +0200 This commit shows the problem which we have if we match dynamically on the DpStrategyInstance. commit ce607f776764dcb78163c862e19b9a39b9f34975 Author: ovi Date: Sat Sep 2 04:13:16 2023 +0200 attempting strategies commit aec6f538e012d9b7507b79eaaff72adf24d408dd Author: Maxim Urschumzew Date: Fri Sep 1 17:58:14 2023 +0200 Added `DpStrategyInstance`. commit 6c83a1915f727f9f25d4c2e7e5de371df769ad06 Author: Maxim Urschumzew Date: Fri Sep 1 16:37:26 2023 +0200 Add `AggregatorWithNoise` references. commit 2984618fe3a2c9a77705ef5109ef2f889bd2e82f Author: Maxim Urschumzew Date: Thu Aug 31 21:27:00 2023 +0200 Compile with new prio dep. --- Cargo.lock | 4 +- Cargo.toml | 3 +- aggregator/src/aggregator.rs | 255 ++++++++++++--- aggregator/src/aggregator/aggregate_share.rs | 8 +- .../src/aggregator/aggregation_job_creator.rs | 151 ++++----- .../src/aggregator/collection_job_driver.rs | 33 +- aggregator/src/bin/janus_cli.rs | 2 + aggregator_core/src/datastore.rs | 3 + aggregator_core/src/task.rs | 1 + core/Cargo.toml | 3 +- core/src/dp.rs | 195 ++++++++++++ core/src/lib.rs | 1 + core/src/task.rs | 297 ++++++++++++------ core/src/test_util/dummy_vdaf.rs | 13 + docs/samples/tasks.yaml | 5 + .../src/bin/janus_interop_client.rs | 69 ++-- .../src/bin/janus_interop_collector.rs | 261 ++++++++------- interop_binaries/src/lib.rs | 63 ++-- interop_binaries/tests/end_to_end.rs | 30 +- messages/Cargo.toml | 3 +- 20 files changed, 951 insertions(+), 449 deletions(-) create mode 100644 core/src/dp.rs diff --git a/Cargo.lock b/Cargo.lock index 8c17661289..a122e21491 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 0b91139893..f216de208f 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 8fdd29858b..8f11ccd289 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 0b759b39c6..dbd6b72d87 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 c763cb6fe3..7d38a5b4f2 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 c12a470a62..0931bb62b7 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 3ebf692cb5..e33481760c 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 480f8d7e79..4fba1635f9 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 7e7318cc9e..09ccb1da62 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 c439f9c094..269acf4d16 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 0000000000..16279342af --- /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 c1a88a10c1..2cac66f4c5 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 2adaca84f9..b371f857c4 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 dd569fb020..dd903de16c 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 c4b49efbaa..caef8ffc01 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 96ad8c5c31..3d1a05f6d7 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 436c7bab1a..471a24b4fe 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 c185130780..38f1abc563 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 1c72310be3..87150f4a0b 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 58cd7edae2..de26860e07 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