From a08587026e554ff632d0132ddebac2138a4a591c Mon Sep 17 00:00:00 2001 From: Martin Thomson Date: Thu, 28 Mar 2024 18:09:57 +1100 Subject: [PATCH] Progress --- ipa-core/build.rs | 29 ++++++++++++++++--- .../boolean/bitwise_less_than_prime.rs | 17 ++++------- ipa-core/src/protocol/boolean/step.rs | 10 +++++++ .../protocol/context/upgrade_triple_step.rs | 1 - ipa-core/src/protocol/mod.rs | 5 ++-- .../modulus_conversion/convert_shares.rs | 5 +--- .../src/protocol/modulus_conversion/mod.rs | 1 + .../{convert_step.rs => step.rs} | 0 ipa-core/src/protocol/step.rs | 8 +++++ ipa-step-derive/src/lib.rs | 27 +++++++++++++++++ ipa-step-derive/src/track.rs | 19 ++++++++++-- ipa-step-test/build.rs | 3 +- ipa-step-test/src/lib.rs | 14 +++++++++ 13 files changed, 112 insertions(+), 27 deletions(-) delete mode 100644 ipa-core/src/protocol/context/upgrade_triple_step.rs rename ipa-core/src/protocol/modulus_conversion/{convert_step.rs => step.rs} (100%) create mode 100644 ipa-core/src/protocol/step.rs diff --git a/ipa-core/build.rs b/ipa-core/build.rs index 1e849cad2..6a34bb9e6 100644 --- a/ipa-core/build.rs +++ b/ipa-core/build.rs @@ -2,24 +2,45 @@ #![allow(clippy::module_name_repetitions)] use cfg_aliases::cfg_aliases; -// use ipa_step::build_gate; +use ipa_step::build_gate; use ipa_step_derive::track_steps; track_steps!( setup_steps: - helpers::prss_protocol::prss_step @"src/helpers/prss_step.rs", - protocol::{basics::mul::step, boolean::step}, + helpers::prss_protocol::prss_step @ "src/helpers/prss_step.rs", + protocol::{ + basics::{ + mul::step, + step, + sum_of_product::step, + }, + boolean::{ + comparison_step, + fallback_step, + step, + }, + context::step, + ipa_prf::{ + boolean_ops::step, + prf_sharding::step, + shuffle::step, + step, + }, + modulus_conversion::step, + step, + }, ); fn main() { setup_steps(); - // build_gate(); + build_gate::(); // test is not supported because cfg_aliases is based on // https://docs.rs/tectonic_cfg_support macro and that only supports features, target_os, family // env, etc. // https://docs.rs/tectonic_cfg_support/latest/tectonic_cfg_support/struct.TargetConfiguration.html cfg_aliases! { + descriptive_gate: { not(all(feature = "compact-gate", not(test), not(unit_test))) }, unit_test: { all(not(feature = "shuttle"), feature = "in-memory-infra") }, web_test: { all(not(feature = "shuttle"), feature = "real-world-infra") }, } diff --git a/ipa-core/src/protocol/boolean/bitwise_less_than_prime.rs b/ipa-core/src/protocol/boolean/bitwise_less_than_prime.rs index 2875befe0..91e2dd517 100644 --- a/ipa-core/src/protocol/boolean/bitwise_less_than_prime.rs +++ b/ipa-core/src/protocol/boolean/bitwise_less_than_prime.rs @@ -1,13 +1,16 @@ use std::cmp::Ordering; use futures::future::try_join; -use ipa_step_derive::CompactStep; use crate::{ error::Error, ff::PrimeField, protocol::{ - boolean::{any_ones, multiply_all_shares, or::or, step::BitOpStep}, + boolean::{ + any_ones, multiply_all_shares, + or::or, + step::{BitOpStep, BitwiseLessThanStep as Step}, + }, context::Context, BasicProtocols, RecordId, }, @@ -190,16 +193,6 @@ impl BitwiseLessThanPrime { } } -#[derive(CompactStep)] -pub(crate) enum Step { - CheckTrimmed, - CheckIfAnyOnes, - LeadingOnesOrRest, - CheckIfAllOnes, - CheckLeastSignificantBits, - AllOnesAndFinalBits, -} - #[cfg(all(test, unit_test))] mod tests { use rand::{distributions::Standard, prelude::Distribution}; diff --git a/ipa-core/src/protocol/boolean/step.rs b/ipa-core/src/protocol/boolean/step.rs index adb4b3ada..01c789cf4 100644 --- a/ipa-core/src/protocol/boolean/step.rs +++ b/ipa-core/src/protocol/boolean/step.rs @@ -36,3 +36,13 @@ pub(crate) enum ComparisonStep { PrefixOr, DotProduct, } + +#[derive(CompactStep)] +pub(crate) enum BitwiseLessThanStep { + CheckTrimmed, + CheckIfAnyOnes, + LeadingOnesOrRest, + CheckIfAllOnes, + CheckLeastSignificantBits, + AllOnesAndFinalBits, +} diff --git a/ipa-core/src/protocol/context/upgrade_triple_step.rs b/ipa-core/src/protocol/context/upgrade_triple_step.rs deleted file mode 100644 index ccfa17642..000000000 --- a/ipa-core/src/protocol/context/upgrade_triple_step.rs +++ /dev/null @@ -1 +0,0 @@ -use ipa_step_derive::CompactStep; diff --git a/ipa-core/src/protocol/mod.rs b/ipa-core/src/protocol/mod.rs index a15b86ace..cfbe92708 100644 --- a/ipa-core/src/protocol/mod.rs +++ b/ipa-core/src/protocol/mod.rs @@ -5,6 +5,7 @@ pub mod dp; pub mod ipa_prf; pub mod modulus_conversion; pub mod prss; +pub mod step; use std::{ fmt::{Debug, Display, Formatter}, @@ -24,9 +25,9 @@ pub type BreakdownKey = Gf8Bit; pub type TriggerValue = Gf3Bit; pub type Timestamp = Gf20Bit; -#[cfg(all(feature = "compact-gate", not(test), not(unit_test)))] +#[cfg(not(descriptive_gate))] pub type Gate = ProtocolGate; -#[cfg(not(all(feature = "compact-gate", not(test), not(unit_test))))] +#[cfg(descriptive_gate)] pub type Gate = ipa_step::descriptive::Descriptive; /// Unique identifier of the MPC query requested by report collectors diff --git a/ipa-core/src/protocol/modulus_conversion/convert_shares.rs b/ipa-core/src/protocol/modulus_conversion/convert_shares.rs index 5780074cc..e9411ec83 100644 --- a/ipa-core/src/protocol/modulus_conversion/convert_shares.rs +++ b/ipa-core/src/protocol/modulus_conversion/convert_shares.rs @@ -39,6 +39,7 @@ use crate::{ basics::{SecureMul, ZeroPositions}, boolean::xor_sparse, context::{Context, UpgradeContext, UpgradeToMalicious, UpgradedContext}, + modulus_conversion::step::ConvertSharesStep, RecordId, }, secret_sharing::{ @@ -48,10 +49,6 @@ use crate::{ seq_join::seq_join, }; -#[path = "convert_step.rs"] -mod convert_step; -use convert_step::ConvertSharesStep; - #[derive(Clone)] pub struct BitConversionTriple(pub(crate) [S; 3]); diff --git a/ipa-core/src/protocol/modulus_conversion/mod.rs b/ipa-core/src/protocol/modulus_conversion/mod.rs index 67a5e8ef9..d4f2a7b23 100644 --- a/ipa-core/src/protocol/modulus_conversion/mod.rs +++ b/ipa-core/src/protocol/modulus_conversion/mod.rs @@ -1,4 +1,5 @@ pub mod convert_shares; +pub mod step; // TODO: wean usage off convert_some_bits. pub(crate) use convert_shares::convert_some_bits; diff --git a/ipa-core/src/protocol/modulus_conversion/convert_step.rs b/ipa-core/src/protocol/modulus_conversion/step.rs similarity index 100% rename from ipa-core/src/protocol/modulus_conversion/convert_step.rs rename to ipa-core/src/protocol/modulus_conversion/step.rs diff --git a/ipa-core/src/protocol/step.rs b/ipa-core/src/protocol/step.rs new file mode 100644 index 000000000..61b828062 --- /dev/null +++ b/ipa-core/src/protocol/step.rs @@ -0,0 +1,8 @@ +use ipa_step_derive::{CompactGate, CompactStep}; + +#[derive(CompactStep, CompactGate)] +pub enum ProtocolStep { + IpaPrf, + IpaClassic, + Multiply, +} diff --git a/ipa-step-derive/src/lib.rs b/ipa-step-derive/src/lib.rs index df3ec9ef3..aa490fc1e 100644 --- a/ipa-step-derive/src/lib.rs +++ b/ipa-step-derive/src/lib.rs @@ -74,12 +74,39 @@ pub fn derive_step(input: TokenStreamBasic) -> TokenStreamBasic { /// Generate a `Gate` implementation from an implementation of `CompactStep`. /// The resulting object will be the top-level entry-point for a complete protocol. +/// +/// For this macro to work, you need to use `track_steps!` and call +/// `ipa_step::build_gate::()` in your `build.rs` file. #[proc_macro_derive(CompactGate)] pub fn derive_gate(input: TokenStreamBasic) -> TokenStreamBasic { TokenStreamBasic::from(derive_gate_impl(&parse_macro_input!(input as DeriveInput))) } /// Used to generate a map of steps for use in a build script. +/// +/// ```ignore +/// track_steps! { +/// fn_name: +/// path::to::step, +/// path::to::other_step, +/// other::path::{a, b @ "src/other/path/b_step.rs"} +/// } +/// ``` +/// +/// The first thing that needs to be included is an identifier, followed by a colon. +/// The macro will generate a function by this name. Call this function from `main()`. +/// +/// Next, there is a list of module paths. You can specify these in much the same +/// way you would a `use` statement. The macro will load files from your `src/` +/// directory by default, inferring the name of the file from the module name. +/// If you have a `mod.rs` or non-default filename (`#[path = "..."]`) then +/// you can supply the location of the code by following the module name with `@` +/// and the location of the file. +/// +/// To keep things clean, you should put any `CompactStep` definitions in their own +/// file. Include as little additional code as possible, because that code will +/// be compiled twice. Any dependencies for that code will also need to be listed +/// in `Cargo.toml` under `[build-dependencies]`. #[cfg(feature = "build")] #[proc_macro] pub fn track_steps(input: TokenStreamBasic) -> TokenStreamBasic { diff --git a/ipa-step-derive/src/track.rs b/ipa-step-derive/src/track.rs index f9579f42a..254c08777 100644 --- a/ipa-step-derive/src/track.rs +++ b/ipa-step-derive/src/track.rs @@ -5,10 +5,11 @@ use std::{ }; use proc_macro2::{ - token_stream::IntoIter as TokenTreeIter, Delimiter, Punct, Spacing, TokenStream, TokenTree, + token_stream::IntoIter as TokenTreeIter, Delimiter, Punct, Spacing, Span, TokenStream, + TokenTree, }; use quote::{quote, ToTokens, TokenStreamExt}; -use syn::{parse::Parser, parse2, Ident, LitStr}; +use syn::{parse::Parser, parse2, token::Pub, Ident, LitStr, Visibility}; use crate::IntoSpan; @@ -28,6 +29,10 @@ impl ModulePath { self.path.len() } + fn is_empty(&self) -> bool { + self.path.is_empty() + } + /// Determine if this path is a prefix of the other. fn is_prefix(&self, other: &Self) -> bool { (self.len() < other.len()) && self.path.iter().eq(other.path.iter().take(self.len())) @@ -238,8 +243,16 @@ impl<'p, 'm> ToTokens for ModuleTokens<'p, 'm> { prefix: &prefix, paths: self.paths, }; + let exposure = if self.prefix.is_empty() { + TokenStream::new() + } else { + Visibility::Public(Pub { + span: Span::call_site(), + }) + .into_token_stream() + }; tokens.extend(quote! { - mod #label { + #exposure mod #label { #inner_tokens } }); diff --git a/ipa-step-test/build.rs b/ipa-step-test/build.rs index 5b83f2ea8..d32fe5014 100644 --- a/ipa-step-test/build.rs +++ b/ipa-step-test/build.rs @@ -6,7 +6,7 @@ use ipa_step_derive::track_steps; // otherwise you will make the build take longer than necessary. // If they are not in the usual place, or if they are defined in "foo/mod.rs", // then you will need to list the files too. -track_steps!(setup: basic_step, complex_step @ "src/complex_step.rs"); +track_steps!(setup: basic_step, complex_step @ "src/complex_step.rs", module::{a, b}); fn main() { setup(); @@ -14,4 +14,5 @@ fn main() { // Now, for each step that is annotated with `#[derive(CompactGate)]`, // invoke this script to build it. build_gate::(); + build_gate::(); } diff --git a/ipa-step-test/src/lib.rs b/ipa-step-test/src/lib.rs index 58c3b19b2..67abb36af 100644 --- a/ipa-step-test/src/lib.rs +++ b/ipa-step-test/src/lib.rs @@ -1,5 +1,6 @@ mod basic_step; mod complex_step; +mod module; #[cfg(test)] mod tests { @@ -8,6 +9,10 @@ mod tests { use crate::{ basic_step::BasicStep, complex_step::{ComplexGate, ComplexStep}, + module::{ + a::{Alpha, AlphaGate}, + b::Beta, + }, }; #[test] @@ -49,4 +54,13 @@ mod tests { fn bad_narrow() { _ = ComplexGate::from("/two2/one").narrow(&BasicStep::Two); } + + /// Test that the alpha and beta gates work. + #[test] + fn alpha_and_beta() { + assert_eq!( + AlphaGate::default().narrow(&Alpha).narrow(&Beta::One), + AlphaGate::from("/alpha/one") + ); + } }