Skip to content

Commit

Permalink
Delete the old IPA implementation (#956)
Browse files Browse the repository at this point in the history
  • Loading branch information
akoshelev authored Feb 20, 2024
1 parent 684c2e3 commit 36c5883
Show file tree
Hide file tree
Showing 96 changed files with 641 additions and 17,012 deletions.
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.

62 changes: 9 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);
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 @@ -209,8 +182,8 @@ impl KeyRegistries {
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 +217,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 +241,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 +258,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 +269,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 +313,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

0 comments on commit 36c5883

Please sign in to comment.