Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Delete the old IPA implementation #956

Merged
merged 22 commits into from
Feb 20, 2024
Merged
Show file tree
Hide file tree
Changes from 14 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .github/workflows/check.yml
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,10 @@ jobs:
if: ${{ success() || failure() }}
run: cargo clippy --tests --features shuttle

- name: Clippy web
if: ${{ success() || failure() }}
run: cargo clippy --no-default-features --features "cli web-app real-world-infra test-fixture descriptive-gate"

- name: Build
if: ${{ success() || failure() }}
run: cargo build --tests
Expand Down
6 changes: 0 additions & 6 deletions ipa-core/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -205,12 +205,6 @@ path = "benches/oneshot/arithmetic_circuit.rs"
harness = false
required-features = ["enable-benches", "descriptive-gate"]

[[bench]]
name = "oneshot_sort"
path = "benches/oneshot/sort.rs"
harness = false
required-features = ["enable-benches", "descriptive-gate"]

[[bench]]
name = "oneshot_ipa"
path = "benches/oneshot/ipa.rs"
Expand Down
29 changes: 6 additions & 23 deletions ipa-core/benches/oneshot/ipa.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use ipa_core::{
ff::Fp32BitPrime,
helpers::{query::IpaQueryConfig, GatewayConfig},
test_fixture::{
ipa::{ipa_in_the_clear, test_ipa, test_oprf_ipa, CappingOrder, IpaSecurityModel},
ipa::{ipa_in_the_clear, test_oprf_ipa, CappingOrder, IpaSecurityModel},
EventGenerator, EventGeneratorConfig, TestWorld, TestWorldConfig,
},
};
Expand Down Expand Up @@ -38,7 +38,7 @@ struct Args {
#[arg(short = 'u', long, default_value = "50")]
records_per_user: u32,
/// The contribution cap for each person.
#[arg(short = 'c', long, default_value = "3")]
#[arg(short = 'c', long, default_value = "8")]
per_user_cap: u32,
/// The number of breakdown keys.
#[arg(short = 'b', long, default_value = "16")]
Expand Down Expand Up @@ -70,8 +70,6 @@ struct Args {
/// Needed for benches.
#[arg(long, hide = true)]
bench: bool,
#[arg(short = 'o', long)]
oprf: bool,
}

impl Args {
Expand Down Expand Up @@ -112,8 +110,8 @@ async fn run(args: Args) -> Result<(), Error> {
);
let rng = StdRng::seed_from_u64(seed);
let (user_count, min_events_per_user, max_events_per_user, query_size) =
if args.oprf && cfg!(feature = "step-trace") {
// For the steps collection, OPRF mode requires a single user with the same number
if cfg!(feature = "step-trace") {
// For the steps collection, compact gate requires a single user with the same number
// of dynamic steps as defined for `UserNthRowStep::Row`.
(
NonZeroU64::new(1).unwrap(),
Expand Down Expand Up @@ -146,11 +144,7 @@ async fn run(args: Args) -> Result<(), Error> {
// timestamp.
raw_data.sort_by_key(|e| e.timestamp);

let order = if args.oprf {
CappingOrder::CapMostRecentFirst
} else {
CappingOrder::CapOldestFirst
};
let order = CappingOrder::CapMostRecentFirst;

let expected_results = ipa_in_the_clear(
&raw_data,
Expand All @@ -164,18 +158,7 @@ async fn run(args: Args) -> Result<(), Error> {
tracing::trace!("Preparation complete in {:?}", _prep_time.elapsed());

let _protocol_time = Instant::now();
if args.oprf {
test_oprf_ipa::<BenchField>(&world, raw_data, &expected_results, args.config()).await;
} else {
test_ipa::<BenchField>(
&world,
&raw_data,
&expected_results,
args.config(),
args.mode,
)
.await;
}
test_oprf_ipa::<BenchField>(&world, raw_data, &expected_results, args.config()).await;
tracing::trace!(
"{m:?} IPA for {q} records took {t:?}",
m = args.mode,
Expand Down
72 changes: 0 additions & 72 deletions ipa-core/benches/oneshot/sort.rs

This file was deleted.

63 changes: 10 additions & 53 deletions ipa-core/src/bin/report_collector.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,14 @@ use hyper::http::uri::Scheme;
use ipa_core::{
cli::{
noise::{apply, ApplyDpArgs},
playbook::{make_clients, playbook_ipa, playbook_oprf_ipa, validate, InputSource},
playbook::{make_clients, playbook_oprf_ipa, validate, InputSource},
CsvSerializer, IpaQueryResult, Verbosity,
},
config::NetworkConfig,
ff::{FieldType, Fp32BitPrime},
helpers::query::{IpaQueryConfig, QueryConfig, QuerySize, QueryType},
hpke::{KeyRegistry, PublicKeyOnly},
net::MpcHelperClient,
protocol::{BreakdownKey, MatchKey},
report::{KeyIdentifier, DEFAULT_KEY_ID},
test_fixture::{
ipa::{ipa_in_the_clear, CappingOrder, IpaQueryStyle, IpaSecurityModel, TestRawDataRecord},
Expand Down Expand Up @@ -84,10 +83,6 @@ impl From<&CommandInput> for InputSource {

#[derive(Debug, Subcommand)]
enum ReportCollectorCommand {
/// Execute IPA in semi-honest honest majority setting
SemiHonestIpa(IpaQueryConfig),
/// Execute IPA in malicious honest majority setting
MaliciousIpa(IpaQueryConfig),
/// Generate inputs for IPA
GenIpaInputs {
/// Number of records to generate
Expand Down Expand Up @@ -129,28 +124,6 @@ async fn main() -> Result<(), Box<dyn Error>> {

let (clients, network) = make_clients(args.network.as_deref(), scheme, args.wait).await;
match args.action {
ReportCollectorCommand::SemiHonestIpa(config) => {
ipa(
&args,
&network,
IpaSecurityModel::SemiHonest,
config,
&clients,
IpaQueryStyle::SortInMpc,
)
.await?
}
ReportCollectorCommand::MaliciousIpa(config) => {
ipa(
&args,
&network,
IpaSecurityModel::Malicious,
config,
&clients,
IpaQueryStyle::SortInMpc,
)
.await?
}
ReportCollectorCommand::GenIpaInputs {
count,
seed,
Expand Down Expand Up @@ -181,7 +154,7 @@ fn gen_inputs(
) -> io::Result<()> {
let rng = seed
.map(StdRng::seed_from_u64)
.unwrap_or_else(|| StdRng::from_entropy());
.unwrap_or_else(StdRng::from_entropy);
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

here and below - clippy error fixes

let mut event_gen = EventGenerator::with_config(rng, args)
.take(count as usize)
.collect::<Vec<_>>();
Expand All @@ -194,7 +167,7 @@ fn gen_inputs(

for event in event_gen {
event.to_csv(&mut writer)?;
writer.write(&[b'\n'])?;
writer.write_all(&[b'\n'])?;
}

Ok(())
Expand All @@ -204,13 +177,14 @@ fn gen_inputs(
struct KeyRegistries(Vec<KeyRegistry<PublicKeyOnly>>);

impl KeyRegistries {
#[allow(dead_code)]
fn init_from(
&mut self,
network: &NetworkConfig,
) -> Option<(KeyIdentifier, [&KeyRegistry<PublicKeyOnly>; 3])> {
// Get the configs, if all three peers have one
let Some(configs) = network.peers().iter().fold(Some(vec![]), |acc, peer| {
if let (Some(mut vec), Some(hpke_config)) = (acc, peer.hpke_config.as_ref()) {
let Some(configs) = network.peers().iter().try_fold(Vec::new(), |acc, peer| {
if let (mut vec, Some(hpke_config)) = (acc, peer.hpke_config.as_ref()) {
vec.push(hpke_config);
Some(vec)
} else {
Expand Down Expand Up @@ -244,14 +218,8 @@ async fn ipa(
let input = InputSource::from(&args.input);
let query_type: QueryType;
match (security_model, &query_style) {
(IpaSecurityModel::SemiHonest, IpaQueryStyle::SortInMpc) => {
query_type = QueryType::SemiHonestIpa(ipa_query_config.clone());
}
(IpaSecurityModel::Malicious, IpaQueryStyle::SortInMpc) => {
query_type = QueryType::MaliciousIpa(ipa_query_config.clone())
}
(IpaSecurityModel::SemiHonest, IpaQueryStyle::Oprf) => {
query_type = QueryType::OprfIpa(ipa_query_config.clone());
query_type = QueryType::OprfIpa(ipa_query_config);
}
(IpaSecurityModel::Malicious, IpaQueryStyle::Oprf) => {
panic!("OPRF for malicious is not implemented as yet")
Expand All @@ -274,7 +242,6 @@ async fn ipa(
ipa_query_config.max_breakdown_key,
&(match query_style {
IpaQueryStyle::Oprf => CappingOrder::CapMostRecentFirst,
IpaQueryStyle::SortInMpc => CappingOrder::CapOldestFirst,
}),
);

Expand All @@ -292,17 +259,7 @@ async fn ipa(
IpaQueryStyle::Oprf => {
playbook_oprf_ipa::<Fp32BitPrime, _>(
input_rows,
&helper_clients,
query_id,
ipa_query_config,
key_registries.init_from(network),
)
.await
}
IpaQueryStyle::SortInMpc => {
playbook_ipa::<Fp32BitPrime, MatchKey, BreakdownKey, _>(
&input_rows,
&helper_clients,
helper_clients,
query_id,
ipa_query_config,
key_registries.init_from(network),
Expand All @@ -313,7 +270,7 @@ async fn ipa(

if let Some(ref path) = args.output_file {
// it will be sad to lose the results if file already exists.
let path = if Path::is_file(&path) {
let path = if Path::is_file(path) {
let mut new_file_name = thread_rng()
.sample_iter(&Alphanumeric)
.take(5)
Expand Down Expand Up @@ -357,7 +314,7 @@ fn apply_dp_noise(args: &Args, dp_args: &ApplyDpArgs) -> Result<(), Box<dyn Erro
let IpaQueryResult { breakdowns, .. } =
serde_json::from_slice(&InputSource::from(&args.input).to_vec()?)?;

let output = apply(&breakdowns, &dp_args);
let output = apply(&breakdowns, dp_args);
let mut table = Table::new();
let header = std::iter::once("Epsilon".to_string())
.chain(std::iter::once("Variance".to_string()))
Expand Down
6 changes: 3 additions & 3 deletions ipa-core/src/bin/test_mpc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -111,14 +111,14 @@ where

let query_id = helper_clients[0].create_query(query_config).await.unwrap();
let expected = input_rows.iter().map(|(a, b)| *a * *b).collect::<Vec<_>>();
let actual = secure_mul(input_rows, &helper_clients, query_id).await;
let actual = secure_mul(input_rows, helper_clients, query_id).await;

validate(&expected, &actual);
}

async fn multiply(args: &Args, helper_clients: &[MpcHelperClient; 3]) {
match args.input.field {
FieldType::Fp31 => multiply_in_field::<Fp31>(&args, helper_clients).await,
FieldType::Fp32BitPrime => multiply_in_field::<Fp32BitPrime>(&args, helper_clients).await,
FieldType::Fp31 => multiply_in_field::<Fp31>(args, helper_clients).await,
FieldType::Fp32BitPrime => multiply_in_field::<Fp32BitPrime>(args, helper_clients).await,
};
}
21 changes: 16 additions & 5 deletions ipa-core/src/cli/noise.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use std::{
cmp::Ordering,
collections::BTreeMap,
fmt::{Debug, Display, Formatter},
};
Expand Down Expand Up @@ -41,7 +42,7 @@ pub struct NoisyOutput {

/// This exists to be able to use f64 as key inside a map. We don't have to deal with infinities or
/// NaN values for epsilons, so we can treat them as raw bytes for this purpose.
#[derive(Debug, Copy, Clone, PartialOrd)]
#[derive(Debug, Copy, Clone)]
pub struct EpsilonBits(f64);

#[cfg(feature = "enable-serde")]
Expand Down Expand Up @@ -71,9 +72,15 @@ impl PartialEq for EpsilonBits {

impl Eq for EpsilonBits {}

impl PartialOrd for EpsilonBits {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}

impl Ord for EpsilonBits {
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
self.partial_cmp(other).unwrap()
self.0.partial_cmp(&other.0).unwrap()
}
}

Expand All @@ -83,14 +90,18 @@ impl Display for EpsilonBits {
}
}

/// Apply DP noise to the given input.
///
/// ## Panics
/// If DP parameters are not valid.
pub fn apply<I: AsRef<[u32]>>(input: I, args: &ApplyDpArgs) -> BTreeMap<EpsilonBits, NoisyOutput> {
let mut rng = args
.seed
.map(StdRng::seed_from_u64)
.unwrap_or_else(StdRng::from_entropy);
.map_or_else(StdRng::from_entropy, StdRng::seed_from_u64);
let mut result = BTreeMap::new();
for &epsilon in &args.epsilon {
let discrete_dp = InsecureDiscreteDp::new(epsilon, args.delta, args.cap as f64).unwrap();
let discrete_dp =
InsecureDiscreteDp::new(epsilon, args.delta, f64::from(args.cap)).unwrap();
let mut v = input
.as_ref()
.iter()
Expand Down
Loading
Loading