diff --git a/0001-CI-split-extra-step-into-two.patch b/0001-CI-split-extra-step-into-two.patch deleted file mode 100644 index 85d7146d2..000000000 --- a/0001-CI-split-extra-step-into-two.patch +++ /dev/null @@ -1,88 +0,0 @@ -From ba6c503fbe930a9298d83c04bab15f329faf13ae Mon Sep 17 00:00:00 2001 -From: Alex Koshelev -Date: Fri, 11 Aug 2023 14:25:03 -0700 -Subject: [PATCH] CI: split extra step into two - -This is an attempt to increase parallelism on CI. Those builds take ~4 mins and running tests take another 5-6 mins. Splitting this step should make CI run faster. ---- - .github/workflows/check.yml | 42 ++++++++++++++++++++++++++++--------- - 1 file changed, 32 insertions(+), 10 deletions(-) - -diff --git a/.github/workflows/check.yml b/.github/workflows/check.yml -index 54f869ac..9a8e1886 100644 ---- a/.github/workflows/check.yml -+++ b/.github/workflows/check.yml -@@ -15,13 +15,15 @@ on: - - "benches/**/*" - - "tests/**/*" - -+env: -+ CARGO_TERM_COLOR: always -+ RUSTFLAGS: -D warnings -+ RUSTDOCFLAGS: -D warnings -+ - jobs: - basic: - name: Basic Checks - env: -- CARGO_TERM_COLOR: always -- RUSTFLAGS: -D warnings -- RUSTDOCFLAGS: -D warnings - CARGO_INCREMENTAL: 0 - - runs-on: ubuntu-latest -@@ -64,12 +66,13 @@ jobs: - - name: Run Web Tests - run: cargo test --no-default-features --features "cli web-app real-world-infra test-fixture descriptive-gate" - -- extra: -- name: Additional Builds and Concurrency Tests -+ - name: Run compact gate tests -+ run: cargo test --no-default-features --features "cli web-app real-world-infra test-fixture compact-gate" -+ -+ extra-builds: -+ name: Additional Builds - env: -- CARGO_TERM_COLOR: always - RUSTFLAGS: -D warnings -C target-cpu=native -- RUSTDOCFLAGS: -D warnings - - runs-on: ubuntu-latest - -@@ -102,11 +105,30 @@ jobs: - - name: Build concurrency tests (debug mode) - run: cargo build --features shuttle - -+ benches-and-fuzzy: -+ name: Run benchmarks and concurrency tests -+ -+ runs-on: ubuntu-latest -+ -+ steps: -+ - uses: actions/checkout@v3 -+ -+ - uses: dtolnay/rust-toolchain@stable -+ with: -+ components: clippy,rustfmt -+ -+ - uses: actions/cache@v3 -+ with: -+ path: | -+ ~/.cargo/bin/ -+ ~/.cargo/registry/index/ -+ ~/.cargo/registry/cache/ -+ ~/.cargo/git/db/ -+ target/ -+ key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.toml') }} -+ - - name: Run concurrency tests - run: cargo test --release --features shuttle - - - name: Run IPA bench - run: cargo bench --bench oneshot_ipa --no-default-features --features "enable-benches descriptive-gate" -- -- - name: Run compact gate tests -- run: cargo test --no-default-features --features "cli web-app real-world-infra test-fixture compact-gate" --- -2.31.1 - diff --git a/Cargo.toml b/Cargo.toml index 1767e8e24..ce7d91446 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,7 +12,8 @@ default = [ "tracing/max_level_trace", "tracing/release_max_level_info", "descriptive-gate", - "aggregate-circuit" + "aggregate-circuit", + "ipa-prf" ] cli = ["comfy-table", "clap"] enable-serde = ["serde", "serde_json"] @@ -41,6 +42,7 @@ compact-gate = ["ipa-macros/compact-gate"] # Standalone aggregation protocol. We use IPA infra for communication # but it has nothing to do with IPA. aggregate-circuit = [] +ipa-prf = ["descriptive-gate"] [dependencies] aes = "0.8.3" @@ -54,6 +56,7 @@ clap = { version = "4.3.2", optional = true, features = ["derive"] } comfy-table = { version = "7.0", optional = true } config = "0.13.2" criterion = { version = "0.5.1", optional = true, default-features = false, features = ["async_tokio", "plotters", "html_reports"] } +curve25519-dalek = "4.1.1" dashmap = "5.4" dhat = "0.3.2" embed-doc-image = "0.1.4" diff --git a/benches/oneshot/ipa.rs b/benches/oneshot/ipa.rs index a7102f91b..c597b7e29 100644 --- a/benches/oneshot/ipa.rs +++ b/benches/oneshot/ipa.rs @@ -9,7 +9,7 @@ use ipa::{ ff::Fp32BitPrime, helpers::{query::IpaQueryConfig, GatewayConfig}, test_fixture::{ - ipa::{ipa_in_the_clear, test_ipa, IpaSecurityModel}, + ipa::{ipa_in_the_clear, test_ipa, test_oprf_ipa, CappingOrder, IpaSecurityModel}, EventGenerator, EventGeneratorConfig, TestWorld, TestWorldConfig, }, }; @@ -70,6 +70,8 @@ struct Args { /// Needed for benches. #[arg(long, hide = true)] bench: bool, + #[arg(short = 'o', long)] + oprf: bool, } impl Args { @@ -121,25 +123,35 @@ async fn run(args: Args) -> Result<(), Error> { .take(args.query_size) .collect::>(); + let order = if args.oprf { + CappingOrder::CapMostRecentFirst + } else { + CappingOrder::CapOldestFirst + }; let expected_results = ipa_in_the_clear( &raw_data, args.per_user_cap, args.attribution_window(), args.breakdown_keys, + &order, ); let world = TestWorld::new_with(config.clone()); tracing::trace!("Preparation complete in {:?}", _prep_time.elapsed()); let _protocol_time = Instant::now(); - test_ipa::( - &world, - &raw_data, - &expected_results, - args.config(), - args.mode, - ) - .await; + if args.oprf { + test_oprf_ipa::(&world, raw_data, &expected_results, args.config()).await; + } else { + test_ipa::( + &world, + &raw_data, + &expected_results, + args.config(), + args.mode, + ) + .await; + } tracing::trace!( "{m:?} IPA for {q} records took {t:?}", m = args.mode, diff --git a/pre-commit b/pre-commit index 12d63958b..d60bece9e 100755 --- a/pre-commit +++ b/pre-commit @@ -99,6 +99,9 @@ check "Concurrency tests" \ check "IPA benchmark" \ cargo bench --bench oneshot_ipa --no-default-features --features="enable-benches descriptive-gate" -- -n 62 +check "IPA OPRF benchmark" \ + cargo bench --bench oneshot_ipa --no-default-features --features="enable-benches descriptive-gate" -- -n 62 --oprf -c 16 + check "Arithmetic circuit benchmark" \ cargo bench --bench oneshot_arithmetic --no-default-features --features "enable-benches descriptive-gate" diff --git a/scripts/collect_steps.py b/scripts/collect_steps.py index 3768fbe07..23c8ffc5e 100755 --- a/scripts/collect_steps.py +++ b/scripts/collect_steps.py @@ -149,9 +149,8 @@ def extract_intermediate_steps(steps): return steps - -if __name__ == "__main__": - steps = set() +def ipa_steps(): + output = set() for c in PER_USER_CAP: for w in ATTRIBUTION_WINDOW: for b in BREAKDOWN_KEYS: @@ -169,7 +168,42 @@ def extract_intermediate_steps(steps): m, ] print(" ".join(args), file=sys.stderr) - steps.update(collect_steps(args)) + output.update(collect_steps(args)) + return output + +OPRF_BREAKDOWN_KEY = 256 +OPRF_USER_CAP = [16, 64, 128] +OPRF_SECURITY_MODEL = "semi-honest" +OPRF_TRIGGER_VALUE = [6, 7] + +def oprf_steps(): + output = set() + for c in OPRF_USER_CAP: + for w in ATTRIBUTION_WINDOW: + for tv in OPRF_TRIGGER_VALUE: + args = ARGS + [ + "-n", + str(QUERY_SIZE), + "-c", + str(c), + "-w", + str(w), + "-b", + str(OPRF_BREAKDOWN_KEY), + "-m", + OPRF_SECURITY_MODEL, + "-t", + str(tv), + "-o" + ] + print(" ".join(args), file=sys.stderr) + output.update(collect_steps(args)) + return output + +if __name__ == "__main__": + steps = set() + steps.update(ipa_steps()) + steps.update(oprf_steps()) full_steps = extract_intermediate_steps(steps) sorted_steps = sorted(full_steps) diff --git a/src/bin/report_collector.rs b/src/bin/report_collector.rs index bac36b0db..f8ba75d7e 100644 --- a/src/bin/report_collector.rs +++ b/src/bin/report_collector.rs @@ -15,7 +15,7 @@ use hyper::http::uri::Scheme; use ipa::{ cli::{ noise::{apply, ApplyDpArgs}, - playbook::{make_clients, playbook_ipa, validate, InputSource}, + playbook::{make_clients, playbook_ipa, playbook_oprf_ipa, validate, InputSource}, CsvSerializer, IpaQueryResult, Verbosity, }, config::NetworkConfig, @@ -26,7 +26,7 @@ use ipa::{ protocol::{BreakdownKey, MatchKey}, report::{KeyIdentifier, DEFAULT_KEY_ID}, test_fixture::{ - ipa::{ipa_in_the_clear, IpaSecurityModel, TestRawDataRecord}, + ipa::{ipa_in_the_clear, CappingOrder, IpaQueryStyle, IpaSecurityModel, TestRawDataRecord}, EventGenerator, EventGeneratorConfig, }, }; @@ -103,6 +103,8 @@ enum ReportCollectorCommand { }, /// Apply differential privacy noise to IPA inputs ApplyDpNoise(ApplyDpArgs), + /// Execute OPRF IPA in a semi-honest majority setting + OprfIpa(IpaQueryConfig), } #[derive(Debug, clap::Args)] @@ -134,6 +136,7 @@ async fn main() -> Result<(), Box> { IpaSecurityModel::SemiHonest, config, &clients, + IpaQueryStyle::SortInMpc, ) .await? } @@ -144,6 +147,7 @@ async fn main() -> Result<(), Box> { IpaSecurityModel::Malicious, config, &clients, + IpaQueryStyle::SortInMpc, ) .await? } @@ -153,6 +157,17 @@ async fn main() -> Result<(), Box> { gen_args, } => gen_inputs(count, seed, args.output_file, gen_args)?, ReportCollectorCommand::ApplyDpNoise(ref dp_args) => apply_dp_noise(&args, dp_args)?, + ReportCollectorCommand::OprfIpa(config) => { + ipa( + &args, + &network, + IpaSecurityModel::SemiHonest, + config, + &clients, + IpaQueryStyle::Oprf, + ) + .await? + } }; Ok(()) @@ -221,16 +236,23 @@ async fn ipa( security_model: IpaSecurityModel, ipa_query_config: IpaQueryConfig, helper_clients: &[MpcHelperClient; 3], + query_style: IpaQueryStyle, ) -> Result<(), Box> { let input = InputSource::from(&args.input); let query_type: QueryType; - match security_model { - IpaSecurityModel::SemiHonest => { + match (security_model, &query_style) { + (IpaSecurityModel::SemiHonest, IpaQueryStyle::SortInMpc) => { query_type = QueryType::SemiHonestIpa(ipa_query_config.clone()); } - IpaSecurityModel::Malicious => { + (IpaSecurityModel::Malicious, IpaQueryStyle::SortInMpc) => { query_type = QueryType::MaliciousIpa(ipa_query_config.clone()) } + (IpaSecurityModel::SemiHonest, IpaQueryStyle::Oprf) => { + query_type = QueryType::OprfIpa(ipa_query_config.clone()); + } + (IpaSecurityModel::Malicious, IpaQueryStyle::Oprf) => { + panic!("OPRF for malicious is not implemented as yet") + } }; let input_rows = input.iter::().collect::>(); @@ -247,6 +269,10 @@ async fn ipa( ipa_query_config.per_user_credit_cap, ipa_query_config.attribution_window_seconds, ipa_query_config.max_breakdown_key, + &(match query_style { + IpaQueryStyle::Oprf => CappingOrder::CapMostRecentFirst, + IpaQueryStyle::SortInMpc => CappingOrder::CapOldestFirst, + }), ); // pad the output vector to the max breakdown key, to make sure it is aligned with the MPC results @@ -259,18 +285,27 @@ async fn ipa( }; let mut key_registries = KeyRegistries::default(); - let actual = playbook_ipa::( - &input_rows, - &helper_clients, - query_id, - ipa_query_config, - key_registries.init_from(network), - ) - .await; - - tracing::info!("{m:?}", m = ipa_query_config); - - validate(&expected, &actual.breakdowns); + let actual = match query_style { + IpaQueryStyle::Oprf => { + playbook_oprf_ipa::( + input_rows, + &helper_clients, + query_id, + ipa_query_config, + ) + .await + } + IpaQueryStyle::SortInMpc => { + playbook_ipa::( + &input_rows, + &helper_clients, + query_id, + ipa_query_config, + key_registries.init_from(network), + ) + .await + } + }; if let Some(ref path) = args.output_file { // it will be sad to lose the results if file already exists. @@ -307,6 +342,10 @@ async fn ipa( write!(file, "{}", serde_json::to_string_pretty(&actual)?)?; } + tracing::info!("{m:?}", m = ipa_query_config); + + validate(&expected, &actual.breakdowns); + Ok(()) } diff --git a/src/cli/playbook/ipa.rs b/src/cli/playbook/ipa.rs index 9047baeb3..6c258f858 100644 --- a/src/cli/playbook/ipa.rs +++ b/src/cli/playbook/ipa.rs @@ -22,9 +22,9 @@ use crate::{ hpke::PublicKeyRegistry, ipa_test_input, net::MpcHelperClient, - protocol::{ipa::IPAInputRow, BreakdownKey, MatchKey, QueryId}, + protocol::{ipa::IPAInputRow, BreakdownKey, MatchKey, QueryId, Timestamp, TriggerValue}, query::QueryStatus, - report::{KeyIdentifier, Report}, + report::{KeyIdentifier, OprfReport, Report}, secret_sharing::{replicated::semi_honest::AdditiveShare, IntoShares}, test_fixture::{input::GenericReportTestInput, ipa::TestRawDataRecord, Reconstruct}, }; @@ -99,6 +99,57 @@ where let inputs = buffers.map(BodyStream::from); tracing::info!("Starting query after finishing encryption"); + + run_query_and_validate::(inputs, query_size, clients, query_id, query_config).await +} + +pub async fn playbook_oprf_ipa( + mut records: Vec, + clients: &[MpcHelperClient; 3], + query_id: QueryId, + query_config: IpaQueryConfig, +) -> IpaQueryResult +where + F: PrimeField, + AdditiveShare: Serializable, +{ + let mut buffers: [_; 3] = std::array::from_fn(|_| Vec::new()); + let query_size = records.len(); + + let sz = as Serializable>::Size::USIZE; + for buffer in &mut buffers { + buffer.resize(query_size * sz, 0u8); + } + + //TODO(richaj) This manual sorting will be removed once we have the PRF sharding in place. + //This does a stable sort. It also expects the inputs to be sorted by timestamp + records.sort_by(|a, b| b.user_id.cmp(&a.user_id)); + + let shares: [Vec>; 3] = + records.iter().cloned().share(); + zip(&mut buffers, shares).for_each(|(buf, shares)| { + for (share, chunk) in zip(shares, buf.chunks_mut(sz)) { + share.serialize(GenericArray::from_mut_slice(chunk)); + } + }); + + let inputs = buffers.map(BodyStream::from); + tracing::info!("Starting query for OPRF"); + + run_query_and_validate::(inputs, query_size, clients, query_id, query_config).await +} + +pub async fn run_query_and_validate( + inputs: [BodyStream; 3], + query_size: usize, + clients: &[MpcHelperClient; 3], + query_id: QueryId, + query_config: IpaQueryConfig, +) -> IpaQueryResult +where + F: PrimeField, + AdditiveShare: Serializable, +{ let mpc_time = Instant::now(); try_join_all( inputs @@ -143,12 +194,20 @@ where .reconstruct(); let lat = mpc_time.elapsed(); + tracing::info!("Running IPA for {query_size:?} records took {t:?}", t = lat); let mut breakdowns = vec![0; usize::try_from(query_config.max_breakdown_key).unwrap()]; for (breakdown_key, trigger_value) in results.into_iter().enumerate() { // TODO: make the data type used consistent with `ipa_in_the_clear` // I think using u32 is wrong, we should move to u128 - breakdowns[breakdown_key] += u32::try_from(trigger_value.as_u128()).unwrap(); + assert!( + breakdown_key < query_config.max_breakdown_key.try_into().unwrap() + || trigger_value == F::ZERO, + "trigger values were attributed to buckets more than max breakdown key" + ); + if breakdown_key < query_config.max_breakdown_key.try_into().unwrap() { + breakdowns[breakdown_key] += u32::try_from(trigger_value.as_u128()).unwrap(); + } } IpaQueryResult { diff --git a/src/cli/playbook/mod.rs b/src/cli/playbook/mod.rs index cdc47be00..4fe0ac6ca 100644 --- a/src/cli/playbook/mod.rs +++ b/src/cli/playbook/mod.rs @@ -11,7 +11,7 @@ pub use input::InputSource; pub use multiply::secure_mul; use tokio::time::sleep; -pub use self::ipa::playbook_ipa; +pub use self::ipa::{playbook_ipa, playbook_oprf_ipa}; use crate::{ config::{ClientConfig, NetworkConfig, PeerConfig}, net::{ClientIdentity, MpcHelperClient}, diff --git a/src/cli/verbosity.rs b/src/cli/verbosity.rs index 74346f558..53a2bee39 100644 --- a/src/cli/verbosity.rs +++ b/src/cli/verbosity.rs @@ -4,7 +4,7 @@ use clap::Parser; use metrics_tracing_context::MetricsLayer; use tracing::{info, metadata::LevelFilter, Level}; use tracing_subscriber::{ - fmt, fmt::format::FmtSpan, layer::SubscriberExt, util::SubscriberInitExt, + fmt, fmt::format::FmtSpan, layer::SubscriberExt, util::SubscriberInitExt, EnvFilter, }; use crate::{ @@ -31,14 +31,14 @@ pub struct LoggingHandle { impl Verbosity { #[must_use] pub fn setup_logging(&self) -> LoggingHandle { - let filter_layer = self.level_filter(); + let filter_layer = self.log_filter(); let fmt_layer = fmt::layer() .with_span_events(FmtSpan::NEW | FmtSpan::CLOSE) .with_ansi(std::io::stderr().is_terminal()) .with_writer(stderr); tracing_subscriber::registry() - .with(self.level_filter()) + .with(self.log_filter()) .with(fmt_layer) .with(MetricsLayer::new()) .init(); @@ -53,15 +53,20 @@ impl Verbosity { handle } - fn level_filter(&self) -> LevelFilter { - if self.quiet { - LevelFilter::OFF - } else { - LevelFilter::from_level(match self.verbose { - 0 => Level::INFO, - 1 => Level::DEBUG, - _ => Level::TRACE, - }) - } + fn log_filter(&self) -> EnvFilter { + EnvFilter::builder() + .with_default_directive( + if self.quiet { + LevelFilter::OFF + } else { + LevelFilter::from_level(match self.verbose { + 0 => Level::INFO, + 1 => Level::DEBUG, + _ => Level::TRACE, + }) + } + .into(), + ) + .from_env_lossy() } } diff --git a/src/error.rs b/src/error.rs index c68b325a8..de41eda4b 100644 --- a/src/error.rs +++ b/src/error.rs @@ -58,6 +58,8 @@ pub enum Error { InvalidReport(#[from] InvalidReportError), #[error("unsupported: {0}")] Unsupported(String), + #[error("Decompressing invalid elliptic curve point: {0}")] + DecompressingInvalidCurvePoint(String), } impl Default for Error { diff --git a/src/ff/curve_points.rs b/src/ff/curve_points.rs new file mode 100644 index 000000000..8eaa57623 --- /dev/null +++ b/src/ff/curve_points.rs @@ -0,0 +1,239 @@ +use curve25519_dalek::{ + ristretto::{CompressedRistretto, RistrettoPoint}, + Scalar, +}; +use generic_array::GenericArray; +use typenum::U32; + +use crate::{ + ff::{ec_prime_field::Fp25519, Serializable}, + secret_sharing::{Block, WeakSharedValue}, +}; + +impl Block for CompressedRistretto { + type Size = U32; +} + +///ristretto point for curve 25519, +/// we store it in compressed format since it is 3 times smaller and we do a limited amount of +/// arithmetic operations on the curve points +/// +/// We use ristretto points such that we have a prime order elliptic curve, +/// This is needed for the Dodis Yampolski PRF +/// +/// decompressing invalid curve points will cause panics, +/// since we always generate curve points from scalars (elements in Fp25519) and +/// only deserialize previously serialized valid points, panics will not occur +/// However, we still added a debug assert to deserialize since values are sent by other servers +#[derive(Clone, Copy, PartialEq, Debug)] +pub struct RP25519(CompressedRistretto); + +/// Implementing trait for secret sharing +impl WeakSharedValue for RP25519 { + type Storage = CompressedRistretto; + const BITS: u32 = 256; + const ZERO: Self = Self(CompressedRistretto([0_u8; 32])); +} + +impl Serializable for RP25519 { + type Size = <::Storage as Block>::Size; + + fn serialize(&self, buf: &mut GenericArray) { + *buf.as_mut() = self.0.to_bytes(); + } + + fn deserialize(buf: &GenericArray) -> Self { + debug_assert!(CompressedRistretto((*buf).into()).decompress().is_some()); + RP25519(CompressedRistretto((*buf).into())) + } +} + +///## Panics +/// Panics when decompressing invalid curve point. This can happen when deserialize curve point +/// from bit array that does not have a valid representation on the curve +impl std::ops::Add for RP25519 { + type Output = Self; + + fn add(self, rhs: Self) -> Self::Output { + Self((self.0.decompress().unwrap() + rhs.0.decompress().unwrap()).compress()) + } +} + +impl std::ops::AddAssign for RP25519 { + #[allow(clippy::assign_op_pattern)] + fn add_assign(&mut self, rhs: Self) { + *self = *self + rhs; + } +} + +///## Panics +/// Panics when decompressing invalid curve point. This can happen when deserialize curve point +/// from bit array that does not have a valid representation on the curve +impl std::ops::Neg for RP25519 { + type Output = Self; + + fn neg(self) -> Self::Output { + Self(self.0.decompress().unwrap().neg().compress()) + } +} + +///## Panics +/// Panics when decompressing invalid curve point. This can happen when deserialize curve point +/// from bit array that does not have a valid representation on the curve +impl std::ops::Sub for RP25519 { + type Output = Self; + + fn sub(self, rhs: Self) -> Self::Output { + Self((self.0.decompress().unwrap() - rhs.0.decompress().unwrap()).compress()) + } +} + +impl std::ops::SubAssign for RP25519 { + #[allow(clippy::assign_op_pattern)] + fn sub_assign(&mut self, rhs: Self) { + *self = *self - rhs; + } +} + +///Scalar Multiplication +/// allows to multiply curve points with scalars from Fp25519 +///## Panics +/// Panics when decompressing invalid curve point. This can happen when deserialize curve point +/// from bit array that does not have a valid representation on the curve +impl std::ops::Mul for RP25519 { + type Output = Self; + + fn mul(self, rhs: Fp25519) -> RP25519 { + (self.0.decompress().unwrap() * Scalar::from(rhs)) + .compress() + .into() + } +} + +impl std::ops::MulAssign for RP25519 { + #[allow(clippy::assign_op_pattern)] + fn mul_assign(&mut self, rhs: Fp25519) { + *self = *self * rhs; + } +} + +impl From for RP25519 { + fn from(s: Scalar) -> Self { + RP25519(RistrettoPoint::mul_base(&s).compress()) + } +} + +impl From for RP25519 { + fn from(s: Fp25519) -> Self { + RP25519(RistrettoPoint::mul_base(&s.into()).compress()) + } +} + +impl From for RP25519 { + fn from(s: CompressedRistretto) -> Self { + RP25519(s) + } +} + +impl From for CompressedRistretto { + fn from(s: RP25519) -> Self { + s.0 + } +} + +///allows to convert curve points into unsigned integers, preserving high entropy +macro_rules! cp_hash_impl { + ( $u_type:ty) => { + impl From for $u_type { + fn from(s: RP25519) -> Self { + use hkdf::Hkdf; + use sha2::Sha256; + let hk = Hkdf::::new(None, s.0.as_bytes()); + let mut okm = <$u_type>::MIN.to_le_bytes(); + //error invalid length from expand only happens when okm is very large + hk.expand(&[], &mut okm).unwrap(); + <$u_type>::from_le_bytes(okm) + } + } + }; +} + +cp_hash_impl!(u128); + +cp_hash_impl!(u64); + +/// implementing random curve point generation for testing purposes, +/// in the actual IPA protocol, we generate them from scalars, i.e. Fp25519 +#[cfg(test)] +impl rand::distributions::Distribution for rand::distributions::Standard { + fn sample(&self, rng: &mut R) -> RP25519 { + let mut scalar_bytes = [0u8; 64]; + rng.fill_bytes(&mut scalar_bytes); + RP25519(RistrettoPoint::from_uniform_bytes(&scalar_bytes).compress()) + } +} + +#[cfg(all(test, unit_test))] +mod test { + use curve25519_dalek::{constants, scalar::Scalar}; + use generic_array::GenericArray; + use rand::{thread_rng, Rng}; + use typenum::U32; + + use crate::{ + ff::{curve_points::RP25519, ec_prime_field::Fp25519, Serializable}, + secret_sharing::WeakSharedValue, + }; + + cp_hash_impl!(u32); + + ///testing serialize and deserialize + #[test] + fn serde_25519() { + let mut rng = thread_rng(); + let input = rng.gen::(); + let mut a: GenericArray = [0u8; 32].into(); + input.serialize(&mut a); + let output = RP25519::deserialize(&a); + assert_eq!(input, output); + } + + ///testing conversion from scalar to Fp25519 and curve point, i.e. RP25519 + #[test] + fn scalar_to_point() { + let a = Scalar::ONE; + let b: RP25519 = a.into(); + let d: Fp25519 = a.into(); + let c: RP25519 = RP25519::from(d); + assert_eq!(b, RP25519(constants::RISTRETTO_BASEPOINT_COMPRESSED)); + assert_eq!(c, RP25519(constants::RISTRETTO_BASEPOINT_COMPRESSED)); + } + + ///testing simple curve arithmetics to check that `curve25519_dalek` library is used correctly + #[test] + fn curve_arithmetics() { + let mut rng = thread_rng(); + let fp_a = rng.gen::(); + let fp_b = rng.gen::(); + let fp_c = fp_a + fp_b; + let fp_d = RP25519::from(fp_a) + RP25519::from(fp_b); + assert_eq!(fp_d, RP25519::from(fp_c)); + assert_ne!(fp_d, RP25519(constants::RISTRETTO_BASEPOINT_COMPRESSED)); + let fp_e = rng.gen::(); + let fp_f = rng.gen::(); + let fp_g = fp_e * fp_f; + let fp_h = RP25519::from(fp_e) * fp_f; + assert_eq!(fp_h, RP25519::from(fp_g)); + assert_ne!(fp_h, RP25519(constants::RISTRETTO_BASEPOINT_COMPRESSED)); + assert_eq!(RP25519::ZERO, fp_h * Scalar::ZERO.into()); + } + + ///testing curve to unsigned integer conversion has entropy (!= 0) + #[test] + fn curve_point_to_hash() { + let mut rng = thread_rng(); + let fp_a = rng.gen::(); + assert_ne!(0u64, u64::from(fp_a)); + assert_ne!(0u32, u32::from(fp_a)); + } +} diff --git a/src/ff/ec_prime_field.rs b/src/ff/ec_prime_field.rs new file mode 100644 index 000000000..3385f10e8 --- /dev/null +++ b/src/ff/ec_prime_field.rs @@ -0,0 +1,269 @@ +use curve25519_dalek::scalar::Scalar; +use generic_array::GenericArray; +use hkdf::Hkdf; +use sha2::Sha256; +use typenum::U32; + +use crate::{ + ff::{Field, Serializable}, + secret_sharing::{Block, SharedValue}, +}; + +impl Block for Scalar { + type Size = U32; +} + +///implements the Scalar field for elliptic curve 25519 +/// we use elements in Fp25519 to generate curve points and operate on the curve +#[derive(Clone, Copy, PartialEq, Debug)] +pub struct Fp25519(::Storage); + +impl Fp25519 { + pub const ONE: Self = Self(Scalar::ONE); + + ///allow invert for scalars, i.e. computes 1/a mod p + ///# Panics + /// Panics when self is zero + #[must_use] + pub fn invert(&self) -> Fp25519 { + assert_ne!(*self, Fp25519::ZERO); + Fp25519(self.0.invert()) + } +} + +///trait for secret sharing +impl SharedValue for Fp25519 { + type Storage = Scalar; + const BITS: u32 = 256; + const ZERO: Self = Self(Scalar::ZERO); +} + +///conversion to Scalar struct of `curve25519_dalek` +impl From for Scalar { + fn from(s: Fp25519) -> Self { + s.0 + } +} + +impl Serializable for Fp25519 { + type Size = <::Storage as Block>::Size; + + fn serialize(&self, buf: &mut GenericArray) { + *buf.as_mut() = self.0.to_bytes(); + } + + fn deserialize(buf: &GenericArray) -> Self { + Fp25519(Scalar::from_bytes_mod_order((*buf).into())) + } +} + +///generate random elements in Fp25519 +impl rand::distributions::Distribution for rand::distributions::Standard { + fn sample(&self, rng: &mut R) -> Fp25519 { + let mut scalar_bytes = [0u8; 32]; + rng.fill_bytes(&mut scalar_bytes); + Fp25519(Scalar::from_bytes_mod_order(scalar_bytes)) + } +} + +impl std::ops::Add for Fp25519 { + type Output = Self; + + fn add(self, rhs: Self) -> Self::Output { + Self(self.0 + rhs.0) + } +} + +impl std::ops::AddAssign for Fp25519 { + #[allow(clippy::assign_op_pattern)] + fn add_assign(&mut self, rhs: Self) { + *self = *self + rhs; + } +} + +impl std::ops::Neg for Fp25519 { + type Output = Self; + + fn neg(self) -> Self::Output { + Self(self.0.neg()) + } +} + +impl std::ops::Sub for Fp25519 { + type Output = Self; + + fn sub(self, rhs: Self) -> Self::Output { + Self(self.0 - rhs.0) + } +} + +impl std::ops::SubAssign for Fp25519 { + #[allow(clippy::assign_op_pattern)] + fn sub_assign(&mut self, rhs: Self) { + *self = *self - rhs; + } +} + +impl std::ops::Mul for Fp25519 { + type Output = Self; + + fn mul(self, rhs: Self) -> Self::Output { + Self(self.0 * rhs.0) + } +} + +impl std::ops::MulAssign for Fp25519 { + #[allow(clippy::assign_op_pattern)] + fn mul_assign(&mut self, rhs: Self) { + *self = *self * rhs; + } +} + +impl From for Fp25519 { + fn from(s: Scalar) -> Self { + Fp25519(s) + } +} + +///conversion from and to unsigned integers, preserving entropy, for testing purposes only +#[cfg(test)] +macro_rules! sc_hash_impl { + ( $u_type:ty) => { + impl From for $u_type { + fn from(s: Fp25519) -> Self { + use hkdf::Hkdf; + use sha2::Sha256; + let hk = Hkdf::::new(None, s.0.as_bytes()); + let mut okm = <$u_type>::MIN.to_le_bytes(); + //error invalid length from expand only happens when okm is very large + hk.expand(&[], &mut okm).unwrap(); + <$u_type>::from_le_bytes(okm) + } + } + + impl From<$u_type> for Fp25519 { + fn from(s: $u_type) -> Self { + use hkdf::Hkdf; + use sha2::Sha256; + let hk = Hkdf::::new(None, &s.to_le_bytes()); + let mut okm = [0u8; 32]; + //error invalid length from expand only happens when okm is very large + hk.expand(&[], &mut okm).unwrap(); + Fp25519::deserialize(&okm.into()) + } + } + }; +} + +#[cfg(test)] +sc_hash_impl!(u64); + +///implement Field because required by PRSS +impl Field for Fp25519 { + const ONE: Fp25519 = Fp25519::ONE; + + ///both following methods are based on hashing and do not allow to actually convert elements in Fp25519 + /// from or into u128. However it is sufficient to generate random elements in Fp25519 + fn as_u128(&self) -> u128 { + let hk = Hkdf::::new(None, self.0.as_bytes()); + let mut okm = [0u8; 16]; + //error invalid length from expand only happens when okm is very large + hk.expand(&[], &mut okm).unwrap(); + u128::from_le_bytes(okm) + } + + ///PRSS uses `truncate_from function`, we need to expand the u128 using a PRG (Sha256) to a [u8;32] + fn truncate_from>(v: T) -> Self { + let hk = Hkdf::::new(None, &v.into().to_le_bytes()); + let mut okm = [0u8; 32]; + //error invalid length from expand only happens when okm is very large + hk.expand(&[], &mut okm).unwrap(); + Fp25519::deserialize(&okm.into()) + } +} + +///implement `TryFrom` since required by Field +impl TryFrom for Fp25519 { + type Error = crate::error::Error; + + fn try_from(v: u128) -> Result { + let mut bits = [0u8; 32]; + bits[..].copy_from_slice(&v.to_le_bytes()); + let f: Fp25519 = Fp25519::ONE; + f.serialize((&mut bits).into()); + Ok(f) + } +} + +#[cfg(all(test, unit_test))] +mod test { + use curve25519_dalek::scalar::Scalar; + use generic_array::GenericArray; + use rand::{thread_rng, Rng}; + use typenum::U32; + + use crate::{ + ff::{ec_prime_field::Fp25519, Serializable}, + secret_sharing::SharedValue, + }; + + sc_hash_impl!(u32); + + ///test serialize and deserialize + #[test] + fn serde_25519() { + let mut rng = thread_rng(); + let input = rng.gen::(); + let mut a: GenericArray = [0u8; 32].into(); + input.serialize(&mut a); + let output = Fp25519::deserialize(&a); + assert_eq!(input, output); + } + + ///test simple arithmetics to check that `curve25519_dalek` is used correctly + #[test] + fn simple_arithmetics_25519() { + let a = Fp25519(Scalar::from_bytes_mod_order([ + 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + ])); + let b = Fp25519(Scalar::from_bytes_mod_order([ + 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + ])); + let d = Fp25519(Scalar::from_bytes_mod_order([ + 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + ])); + let e = Fp25519(Scalar::from_bytes_mod_order([ + 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + ])); + let cc = b - a; + let dc = a + b; + let ec = a * b; + assert_eq!(cc, Fp25519::ONE); + assert_eq!(dc, d); + assert_eq!(ec, e); + } + + ///test random field element generation (!= 0) + #[test] + fn simple_random_25519() { + let mut rng = thread_rng(); + assert_ne!(Fp25519::ZERO, rng.gen::()); + } + + ///test inversion for field elements + #[test] + fn invert_25519() { + let mut rng = thread_rng(); + let a = rng.gen::(); + let ia = a.invert(); + assert_eq!(a * ia, Fp25519(Scalar::ONE)); + } +} diff --git a/src/ff/galois_field.rs b/src/ff/galois_field.rs index 18b6b58c8..633e1fd72 100644 --- a/src/ff/galois_field.rs +++ b/src/ff/galois_field.rs @@ -5,7 +5,7 @@ use std::{ use bitvec::prelude::{bitarr, BitArr, Lsb0}; use generic_array::GenericArray; -use typenum::{Unsigned, U1, U4, U5}; +use typenum::{Unsigned, U1, U2, U3, U4, U5}; use crate::{ ff::{Field, Serializable}, @@ -25,6 +25,8 @@ pub trait GaloisField: // Bit store type definitions type U8_1 = BitArr!(for 8, in u8, Lsb0); +type U8_2 = BitArr!(for 9, in u8, Lsb0); +type U8_3 = BitArr!(for 24, in u8, Lsb0); type U8_4 = BitArr!(for 32, in u8, Lsb0); type U8_5 = BitArr!(for 40, in u8, Lsb0); @@ -32,6 +34,14 @@ impl Block for U8_1 { type Size = U1; } +impl Block for U8_2 { + type Size = U2; +} + +impl Block for U8_3 { + type Size = U3; +} + impl Block for U8_4 { type Size = U4; } @@ -121,7 +131,7 @@ fn clmul(a: GF, b: GF) -> u128 { } macro_rules! bit_array_impl { - ( $modname:ident, $name:ident, $store:ty, $bits:expr, $one:expr, $polynomial:expr ) => { + ( $modname:ident, $name:ident, $store:ty, $bits:expr, $one:expr, $polynomial:expr, $({$($extra:item)*})? ) => { #[allow(clippy::suspicious_arithmetic_impl)] #[allow(clippy::suspicious_op_assign_impl)] mod $modname { @@ -524,6 +534,8 @@ macro_rules! bit_array_impl { assert_eq!(a, $name::deserialize(&buf)); } } + + $( $( $extra )* )? } pub use $modname::$name; @@ -537,7 +549,7 @@ bit_array_impl!( 40, bitarr!(const u8, Lsb0; 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), // x^40 + x^5 + x^3 + x^2 + 1 - 0b1_0000_0000_0000_0000_0000_0000_0000_0000_0010_1101_u128 + 0b1_0000_0000_0000_0000_0000_0000_0000_0000_0010_1101_u128, ); bit_array_impl!( @@ -547,7 +559,17 @@ bit_array_impl!( 32, bitarr!(const u8, Lsb0; 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), // x^32 + x^7 + x^3 + x^2 + 1 - 0b1_0000_0000_0000_0000_0000_0000_1000_1101_u128 + 0b1_0000_0000_0000_0000_0000_0000_1000_1101_u128, +); + +bit_array_impl!( + bit_array_20, + Gf20Bit, + U8_3, + 20, + bitarr!(const u8, Lsb0; 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), + // x^20 + x^7 + x^3 + x^2 + 1 + 0b1000_0000_0000_1000_1101_u128, ); bit_array_impl!( @@ -557,7 +579,17 @@ bit_array_impl!( 8, bitarr!(const u8, Lsb0; 1, 0, 0, 0, 0, 0, 0, 0), // x^8 + x^4 + x^3 + x + 1 - 0b1_0001_1011_u128 + 0b1_0001_1011_u128, +); + +bit_array_impl!( + bit_array_9, + Gf9Bit, + U8_2, + 9, + bitarr!(const u8, Lsb0; 1, 0, 0, 0, 0, 0, 0, 0, 0), + // x^9 + x^4 + x^3 + x + 1 + 0b10_0001_1011_u128, ); bit_array_impl!( @@ -567,7 +599,7 @@ bit_array_impl!( 5, bitarr!(const u8, Lsb0; 1, 0, 0, 0, 0), // x^5 + x^4 + x^3 + x^2 + x + 1 - 0b111_111_u128 + 0b111_111_u128, ); bit_array_impl!( @@ -577,7 +609,7 @@ bit_array_impl!( 3, bitarr!(const u8, Lsb0; 1, 0, 0), // x^3 + x + 1 - 0b1_011_u128 + 0b1_011_u128, ); bit_array_impl!( @@ -587,5 +619,14 @@ bit_array_impl!( 1, bitarr!(const u8, Lsb0; 1), // x - 0b10_u128 + 0b10_u128, + { + impl From for Gf2 { + fn from(value: bool) -> Self { + let mut v = Gf2::ZERO; + v.0.set(0, value); + v + } + } + } ); diff --git a/src/ff/mod.rs b/src/ff/mod.rs index 5544f2378..1ced6caf0 100644 --- a/src/ff/mod.rs +++ b/src/ff/mod.rs @@ -2,6 +2,8 @@ // // This is where we store arithmetic shared secret data models. +pub mod curve_points; +pub mod ec_prime_field; mod field; mod galois_field; mod prime_field; @@ -9,7 +11,9 @@ mod prime_field; use std::ops::{Add, AddAssign, Sub, SubAssign}; pub use field::{Field, FieldType}; -pub use galois_field::{GaloisField, Gf2, Gf32Bit, Gf3Bit, Gf40Bit, Gf5Bit, Gf8Bit}; +pub use galois_field::{ + GaloisField, Gf2, Gf20Bit, Gf32Bit, Gf3Bit, Gf40Bit, Gf5Bit, Gf8Bit, Gf9Bit, +}; use generic_array::{ArrayLength, GenericArray}; #[cfg(any(test, feature = "weak-field"))] pub use prime_field::Fp31; diff --git a/src/helpers/gateway/receive.rs b/src/helpers/gateway/receive.rs index 282ff68e2..b039c8653 100644 --- a/src/helpers/gateway/receive.rs +++ b/src/helpers/gateway/receive.rs @@ -43,6 +43,7 @@ impl ReceivingEnd { /// ## Panics /// This will panic if message size does not fit into 8 bytes and it somehow got serialized /// and sent to this helper. + #[tracing::instrument(level = "trace", "receive", skip_all, fields(i = %record_id, from = ?self.channel_id.role, gate = ?self.channel_id.gate.as_ref()))] pub async fn receive(&self, record_id: RecordId) -> Result { self.unordered_rx .recv::(record_id) diff --git a/src/helpers/gateway/send.rs b/src/helpers/gateway/send.rs index 4eb876af0..0d32de973 100644 --- a/src/helpers/gateway/send.rs +++ b/src/helpers/gateway/send.rs @@ -98,6 +98,7 @@ impl SendingEnd { /// call. /// /// [`set_total_records`]: crate::protocol::context::Context::set_total_records + #[tracing::instrument(level = "trace", "send", skip_all, fields(i = %record_id, total = %self.inner.total_records, to = ?self.channel_id.role, gate = ?self.channel_id.gate.as_ref()))] pub async fn send(&self, record_id: RecordId, msg: M) -> Result<(), Error> { let r = self.inner.send(record_id, msg).await; metrics::increment_counter!(RECORDS_SENT, diff --git a/src/helpers/mod.rs b/src/helpers/mod.rs index 373070736..1c510485e 100644 --- a/src/helpers/mod.rs +++ b/src/helpers/mod.rs @@ -1,5 +1,5 @@ use std::{ - fmt::{Debug, Formatter}, + fmt::{Debug, Display, Formatter}, num::NonZeroUsize, }; @@ -40,7 +40,7 @@ use crate::{ Role::{H1, H2, H3}, }, protocol::{step::Gate, RecordId}, - secret_sharing::SharedValue, + secret_sharing::WeakSharedValue, }; // TODO work with ArrayLength only @@ -409,7 +409,7 @@ impl Debug for ChannelId { pub trait Message: Debug + Send + Serializable + 'static + Sized {} /// Any shared value can be send as a message -impl Message for V {} +impl Message for V {} impl Serializable for PublicKey { type Size = typenum::U32; @@ -441,6 +441,16 @@ pub enum TotalRecords { Indeterminate, } +impl Display for TotalRecords { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + match self { + TotalRecords::Unspecified => write!(f, "unspecified"), + TotalRecords::Specified(v) => write!(f, "{v}"), + TotalRecords::Indeterminate => write!(f, "∞"), + } + } +} + impl TotalRecords { #[must_use] pub fn is_specified(&self) -> bool { diff --git a/src/helpers/transport/query.rs b/src/helpers/transport/query.rs index ab4e0761b..6bb7a9ed9 100644 --- a/src/helpers/transport/query.rs +++ b/src/helpers/transport/query.rs @@ -206,6 +206,7 @@ pub enum QueryType { MaliciousIpa(IpaQueryConfig), SemiHonestSparseAggregate(SparseAggregateQueryConfig), MaliciousSparseAggregate(SparseAggregateQueryConfig), + OprfIpa(IpaQueryConfig), } impl QueryType { @@ -214,6 +215,7 @@ impl QueryType { pub const MALICIOUS_IPA_STR: &'static str = "malicious-ipa"; pub const SEMIHONEST_AGGREGATE_STR: &'static str = "semihonest-sparse-aggregate"; pub const MALICIOUS_AGGREGATE_STR: &'static str = "malicious-sparse-aggregate"; + pub const OPRF_IPA_STR: &'static str = "oprf_ipa"; } /// TODO: should this `AsRef` impl (used for `Substep`) take into account config of IPA? @@ -226,6 +228,7 @@ impl AsRef for QueryType { QueryType::MaliciousIpa(_) => Self::MALICIOUS_IPA_STR, QueryType::SemiHonestSparseAggregate(_) => Self::SEMIHONEST_AGGREGATE_STR, QueryType::MaliciousSparseAggregate(_) => Self::MALICIOUS_AGGREGATE_STR, + QueryType::OprfIpa(_) => Self::OPRF_IPA_STR, } } } diff --git a/src/net/http_serde.rs b/src/net/http_serde.rs index faa2ec13d..406ec9a48 100644 --- a/src/net/http_serde.rs +++ b/src/net/http_serde.rs @@ -139,6 +139,10 @@ pub mod query { let Query(q) = req.extract().await?; Ok(QueryType::MaliciousSparseAggregate(q)) } + QueryType::OPRF_IPA_STR => { + let Query(q) = req.extract().await?; + Ok(QueryType::OprfIpa(q)) + } other => Err(Error::bad_query_value("query_type", other)), }?; Ok(QueryConfigQueryParams(QueryConfig { @@ -161,7 +165,9 @@ pub mod query { match self.query_type { #[cfg(any(test, feature = "test-fixture", feature = "cli"))] QueryType::TestMultiply => Ok(()), - QueryType::SemiHonestIpa(config) | QueryType::MaliciousIpa(config) => { + QueryType::SemiHonestIpa(config) + | QueryType::MaliciousIpa(config) + | QueryType::OprfIpa(config) => { write!( f, "&per_user_credit_cap={}&max_breakdown_key={}&num_multi_bits={}", diff --git a/src/protocol/basics/reveal.rs b/src/protocol/basics/reveal.rs index 672c8a473..9fddb65b8 100644 --- a/src/protocol/basics/reveal.rs +++ b/src/protocol/basics/reveal.rs @@ -18,7 +18,7 @@ use crate::{ malicious::{AdditiveShare as MaliciousReplicated, ExtendableField}, semi_honest::AdditiveShare as Replicated, }, - SecretSharing, SharedValue, + SecretSharing, WeakSharedValue, }, }; @@ -47,7 +47,7 @@ pub trait Reveal: Sized { /// i.e. their own shares and received share. #[async_trait] #[embed_doc_image("reveal", "images/reveal.png")] -impl Reveal for Replicated { +impl Reveal for Replicated { type Output = V; async fn reveal<'fut>(&self, ctx: C, record_id: RecordId) -> Result diff --git a/src/protocol/boolean/comparison.rs b/src/protocol/boolean/comparison.rs index 148117854..e7ddbfb7a 100644 --- a/src/protocol/boolean/comparison.rs +++ b/src/protocol/boolean/comparison.rs @@ -3,7 +3,7 @@ use ipa_macros::Step; use super::or::or; use crate::{ error::Error, - ff::PrimeField, + ff::{Field, PrimeField}, protocol::{ boolean::random_bits_generator::RandomBitsGenerator, context::{Context, UpgradedContext}, @@ -205,7 +205,7 @@ pub async fn bitwise_less_than_constant( c: u128, ) -> Result where - F: PrimeField, + F: Field, C: Context, S: LinearSecretSharing + BasicProtocols, for<'a> &'a S: LinearRefOps<'a, S, F>, @@ -236,7 +236,7 @@ async fn first_differing_bit( b: u128, ) -> Result, Error> where - F: PrimeField, + F: Field, C: Context, S: LinearSecretSharing + BasicProtocols, for<'a> &'a S: LinearRefOps<'a, S, F>, diff --git a/src/protocol/boolean/generate_random_bits.rs b/src/protocol/boolean/generate_random_bits.rs index f8e2d2e87..184bf7d80 100644 --- a/src/protocol/boolean/generate_random_bits.rs +++ b/src/protocol/boolean/generate_random_bits.rs @@ -5,6 +5,7 @@ use futures::stream::{iter as stream_iter, Stream, StreamExt}; use crate::{ error::Error, ff::PrimeField, + helpers::Role, protocol::{ basics::SecureMul, context::{prss::InstrumentedIndexedSharedRandomness, Context, UpgradedContext}, @@ -47,16 +48,14 @@ impl RawRandomBits { } impl ToBitConversionTriples for RawRandomBits { + type Residual = (); + // TODO const for this in place of the function fn bits(&self) -> u32 { self.count } - fn triple( - &self, - role: crate::helpers::Role, - i: u32, - ) -> BitConversionTriple> { + fn triple(&self, role: Role, i: u32) -> BitConversionTriple> { debug_assert!(u128::BITS - F::PRIME.into().leading_zeros() >= self.count); assert!(i < self.count); BitConversionTriple::new( @@ -65,6 +64,21 @@ impl ToBitConversionTriples for RawRandomBits { ((self.right >> i) & 1) == 1, ) } + + fn into_triples( + self, + role: Role, + indices: I, + ) -> ( + BitDecomposed>>, + Self::Residual, + ) + where + F: PrimeField, + I: IntoIterator, + { + (self.triple_range(role, indices), ()) + } } struct RawRandomBitIter { @@ -135,4 +149,5 @@ where .next() .await .unwrap() + .map(|(v, ())| v) } diff --git a/src/protocol/boolean/saturating_sum.rs b/src/protocol/boolean/saturating_sum.rs index f57551d98..3ce2d9e4d 100644 --- a/src/protocol/boolean/saturating_sum.rs +++ b/src/protocol/boolean/saturating_sum.rs @@ -24,7 +24,7 @@ impl> SaturatingSum { /// If one of the multiplications errors /// /// # Panics - /// If something try to add a bit decomposed value larger than this `SaturatingSum` can accomodate + /// If something try to add a bit decomposed value larger than this `SaturatingSum` can accommodate pub async fn add( &self, ctx: C, @@ -175,7 +175,9 @@ where /// /// If `compute_carry_out` is set to `true`, then the mutable refernce to `carry_in` is mutated to take on the value of the `carry_out` bit /// -async fn one_bit_subtractor( +/// # Errors +/// If one of the multiplications errors +pub async fn one_bit_subtractor( ctx: C, record_id: RecordId, x: &SB, diff --git a/src/protocol/ipa/mod.rs b/src/protocol/ipa/mod.rs index b8f516684..bac3d6e82 100644 --- a/src/protocol/ipa/mod.rs +++ b/src/protocol/ipa/mod.rs @@ -464,7 +464,7 @@ pub mod tests { test_executor::{run, run_with}, test_fixture::{ input::GenericReportTestInput, - ipa::{ipa_in_the_clear, test_ipa, IpaSecurityModel}, + ipa::{ipa_in_the_clear, test_ipa, CappingOrder, IpaSecurityModel}, logging, EventGenerator, EventGeneratorConfig, Reconstruct, Runner, TestWorld, TestWorldConfig, }, @@ -815,6 +815,7 @@ pub mod tests { per_user_cap, ATTRIBUTION_WINDOW_SECONDS, MAX_BREAKDOWN_KEY, + &CappingOrder::CapOldestFirst, ); let config = TestWorldConfig { diff --git a/src/protocol/ipa_prf/mod.rs b/src/protocol/ipa_prf/mod.rs new file mode 100644 index 000000000..755ef87a5 --- /dev/null +++ b/src/protocol/ipa_prf/mod.rs @@ -0,0 +1,2 @@ +pub mod prf_eval; +pub mod prf_sharding; diff --git a/src/protocol/ipa_prf/prf_eval/mod.rs b/src/protocol/ipa_prf/prf_eval/mod.rs new file mode 100644 index 000000000..ff37e30eb --- /dev/null +++ b/src/protocol/ipa_prf/prf_eval/mod.rs @@ -0,0 +1,198 @@ +use ipa_macros::Step; + +use crate::{ + error::Error, + ff::{curve_points::RP25519, ec_prime_field::Fp25519}, + protocol::{ + basics::{Reveal, SecureMul}, + context::Context, + prss::SharedRandomness, + RecordId, + }, + secret_sharing::replicated::{semi_honest::AdditiveShare, ReplicatedSecretSharing}, +}; + +#[derive(Step)] +pub(crate) enum Step { + PRFKeyGen, + GenRandomMask, + MultMaskWithPRFInput, + RevealR, + Revealz, +} + +/// generates match key pseudonyms from match keys (in Fp25519 format) and PRF key +/// PRF key needs to be generated separately using `gen_prf_key` +/// +/// `gen_prf_key` is not included such that `compute_match_key_pseudonym` can be tested for correctness +/// # Errors +/// Propagates errors from multiplications +pub async fn compute_match_key_pseudonym( + sh_ctx: C, + prf_key: AdditiveShare, + input_match_keys: Vec>, +) -> Result, Error> +where + C: Context, +{ + let ctx = sh_ctx.set_total_records(input_match_keys.len()); + let futures = input_match_keys + .iter() + .enumerate() + .map(|(i, x)| eval_dy_prf(ctx.clone(), i.into(), &prf_key, x)); + ctx.try_join(futures).await +} + +impl From> for AdditiveShare { + fn from(s: AdditiveShare) -> Self { + AdditiveShare::new(RP25519::from(s.left()), RP25519::from(s.right())) + } +} + +/// generates PRF key k as secret sharing over Fp25519 +pub fn gen_prf_key(ctx: &C) -> AdditiveShare +where + C: Context, +{ + ctx.narrow(&Step::PRFKeyGen) + .prss() + .generate_replicated(RecordId(0)) +} + +/// evaluates the Dodis-Yampolski PRF g^(1/(k+x)) +/// the input x and k are secret shared over finite field Fp25519, i.e. the scalar field of curve 25519 +/// PRF key k needs to be generated using `gen_prf_key` +/// x is the match key in Fp25519 format +/// outputs a u64 as specified in `protocol/prf_sharding/mod.rs`, all parties learn the output +/// # Errors +/// Propagates errors from multiplications, reveal and scalar multiplication + +pub async fn eval_dy_prf( + ctx: C, + record_id: RecordId, + k: &AdditiveShare, + x: &AdditiveShare, +) -> Result +where + C: Context, +{ + let sh_r: AdditiveShare = ctx + .narrow(&Step::GenRandomMask) + .prss() + .generate_replicated(record_id); + + //compute (g^left, g^right) + let sh_gr = AdditiveShare::::from(sh_r.clone()); + + //compute x+k + let mut y = x + k; + + //compute y <- r*y + y = y + .multiply(&sh_r, ctx.narrow(&Step::MultMaskWithPRFInput), record_id) + .await?; + + //reconstruct (z,R) + let gr: RP25519 = sh_gr.reveal(ctx.narrow(&Step::RevealR), record_id).await?; + let z = y.reveal(ctx.narrow(&Step::Revealz), record_id).await?; + + //compute R^(1/z) to u64 + Ok(u64::from(gr * (z.invert()))) +} + +#[cfg(all(test, unit_test))] +mod test { + use rand::Rng; + + use crate::{ + ff::{curve_points::RP25519, ec_prime_field::Fp25519}, + protocol::ipa_prf::prf_eval::compute_match_key_pseudonym, + secret_sharing::{replicated::semi_honest::AdditiveShare, IntoShares}, + test_executor::run, + test_fixture::{Reconstruct, Runner, TestWorld}, + }; + + ///defining test input struct + #[derive(Copy, Clone)] + struct ShuffledTestInput { + match_key: Fp25519, + } + + ///defining test output struct + #[derive(Debug, PartialEq)] + struct TestOutput { + match_key_pseudonym: u64, + } + + fn test_input(mk: u64) -> ShuffledTestInput { + ShuffledTestInput { + match_key: Fp25519::from(mk), + } + } + + impl IntoShares> for ShuffledTestInput { + fn share_with(self, rng: &mut R) -> [AdditiveShare; 3] { + self.match_key.share_with(rng) + } + } + + impl Reconstruct for [&u64; 3] { + fn reconstruct(&self) -> TestOutput { + TestOutput { + match_key_pseudonym: if *self[0] == *self[1] && *self[0] == *self[2] { + *self[0] + } else { + 0u64 + }, + } + } + } + + ///testing correctness of DY PRF evaluation + /// by checking MPC generated pseudonym with pseudonym generated in the clear + #[test] + fn semi_honest() { + run(|| async move { + let world = TestWorld::default(); + + //first two need to be identical for test to succeed + let records: Vec = vec![ + test_input(3), + test_input(3), + test_input(23_443_524_523), + test_input(56), + test_input(895_764_542), + test_input(456_764_576), + test_input(56), + test_input(3), + test_input(56), + test_input(23_443_524_523), + ]; + + //PRF Key Gen + let u = 3_216_412_445u64; + let k: Fp25519 = Fp25519::from(u); + + let expected: Vec = records + .iter() + .map(|&x| TestOutput { + match_key_pseudonym: (RP25519::from((x.match_key + k).invert())).into(), + }) + .collect(); + + let result: Vec<_> = world + .semi_honest( + (records.into_iter(), k), + |ctx, (input_match_keys, prf_key)| async move { + compute_match_key_pseudonym::<_>(ctx, prf_key, input_match_keys) + .await + .unwrap() + }, + ) + .await + .reconstruct(); + assert_eq!(result, expected); + assert_eq!(result[0], result[1]); + }); + } +} diff --git a/src/protocol/prf_sharding/bucket.rs b/src/protocol/ipa_prf/prf_sharding/bucket.rs similarity index 88% rename from src/protocol/prf_sharding/bucket.rs rename to src/protocol/ipa_prf/prf_sharding/bucket.rs index 6349f91a6..a1e62d1a2 100644 --- a/src/protocol/prf_sharding/bucket.rs +++ b/src/protocol/ipa_prf/prf_sharding/bucket.rs @@ -1,17 +1,43 @@ use embed_doc_image::embed_doc_image; +use ipa_macros::Step; use crate::{ error::Error, ff::{GaloisField, PrimeField, Serializable}, protocol::{ - basics::SecureMul, context::UpgradedContext, prf_sharding::BinaryTreeDepthStep, - step::BitOpStep, RecordId, + basics::SecureMul, context::UpgradedContext, ipa_prf::prf_sharding::BinaryTreeDepthStep, + RecordId, }, secret_sharing::{ replicated::malicious::ExtendableField, BitDecomposed, Linear as LinearSecretSharing, }, }; +#[derive(Step)] +pub enum BucketStep { + #[dynamic(256)] + Bit(usize), +} + +impl TryFrom for BucketStep { + type Error = String; + + fn try_from(v: u32) -> Result { + let val = usize::try_from(v); + let val = match val { + Ok(val) => Self::Bit(val), + Err(error) => panic!("{error:?}"), + }; + Ok(val) + } +} + +impl From for BucketStep { + fn from(v: usize) -> Self { + Self::Bit(v) + } +} + #[embed_doc_image("tree-aggregation", "images/tree_aggregation.png")] /// This function moves a single value to a correct bucket using tree aggregation approach /// @@ -53,8 +79,8 @@ where BK::BITS ); assert!( - breakdown_count <= 128, - "Our step implementation (BitOpStep) cannot go past 64" + breakdown_count <= 512, + "Our step implementation (BucketStep) cannot go past 256" ); let mut row_contribution = vec![value; breakdown_count]; @@ -69,7 +95,7 @@ where let mut futures = Vec::with_capacity(breakdown_count / step); for (i, tree_index) in (0..breakdown_count).step_by(step).enumerate() { - let bit_c = depth_c.narrow(&BitOpStep::from(i)); + let bit_c = depth_c.narrow(&BucketStep::from(i)); if robust || tree_index + span < breakdown_count { futures.push(row_contribution[tree_index].multiply(bit_of_bdkey, bit_c, record_id)); @@ -96,10 +122,10 @@ pub mod tests { use rand::thread_rng; use crate::{ - ff::{Field, Fp32BitPrime, Gf5Bit, Gf8Bit}, + ff::{Field, Fp32BitPrime, Gf8Bit, Gf9Bit}, protocol::{ context::{Context, UpgradableContext, Validator}, - prf_sharding::bucket::move_single_value_to_bucket, + ipa_prf::prf_sharding::bucket::move_single_value_to_bucket, RecordId, }, rand::Rng, @@ -108,12 +134,12 @@ pub mod tests { test_fixture::{get_bits, Reconstruct, Runner, TestWorld}, }; - const MAX_BREAKDOWN_COUNT: usize = 1 << Gf5Bit::BITS; + const MAX_BREAKDOWN_COUNT: usize = 256; const VALUE: u32 = 10; async fn move_to_bucket(count: usize, breakdown_key: usize, robust: bool) -> Vec { let breakdown_key_bits = - get_bits::(breakdown_key.try_into().unwrap(), Gf5Bit::BITS); + get_bits::(breakdown_key.try_into().unwrap(), Gf8Bit::BITS); let value = Fp32BitPrime::truncate_from(VALUE); TestWorld::default() @@ -122,7 +148,7 @@ pub mod tests { |ctx, (breakdown_key_share, value_share)| async move { let validator = ctx.validator(); let ctx = validator.context(); - move_single_value_to_bucket::( + move_single_value_to_bucket::( ctx.set_total_records(1), RecordId::from(0), breakdown_key_share, @@ -207,7 +233,7 @@ pub mod tests { #[should_panic] fn move_out_of_range_too_many_buckets_steps() { run(move || async move { - let breakdown_key_bits = get_bits::(0, Gf8Bit::BITS); + let breakdown_key_bits = get_bits::(0, Gf9Bit::BITS); let value = Fp32BitPrime::truncate_from(VALUE); _ = TestWorld::default() @@ -216,12 +242,12 @@ pub mod tests { |ctx, (breakdown_key_share, value_share)| async move { let validator = ctx.validator(); let ctx = validator.context(); - move_single_value_to_bucket::( + move_single_value_to_bucket::( ctx.set_total_records(1), RecordId::from(0), breakdown_key_share, value_share, - 129, + 513, false, ) .await diff --git a/src/protocol/prf_sharding/feature_label_dot_product.rs b/src/protocol/ipa_prf/prf_sharding/feature_label_dot_product.rs similarity index 99% rename from src/protocol/prf_sharding/feature_label_dot_product.rs rename to src/protocol/ipa_prf/prf_sharding/feature_label_dot_product.rs index f87f788d8..bc492b62c 100644 --- a/src/protocol/prf_sharding/feature_label_dot_product.rs +++ b/src/protocol/ipa_prf/prf_sharding/feature_label_dot_product.rs @@ -371,7 +371,7 @@ where pub mod tests { use crate::{ ff::{Field, Fp32BitPrime, GaloisField, Gf2, Gf32Bit}, - protocol::prf_sharding::feature_label_dot_product::{ + protocol::ipa_prf::prf_sharding::feature_label_dot_product::{ compute_feature_label_dot_product, PrfShardedIpaInputRow, }, rand::Rng, diff --git a/src/protocol/prf_sharding/mod.rs b/src/protocol/ipa_prf/prf_sharding/mod.rs similarity index 71% rename from src/protocol/prf_sharding/mod.rs rename to src/protocol/ipa_prf/prf_sharding/mod.rs index 110dc452a..0f6aa8ed2 100644 --- a/src/protocol/prf_sharding/mod.rs +++ b/src/protocol/ipa_prf/prf_sharding/mod.rs @@ -1,7 +1,13 @@ -use std::iter::{repeat, zip}; +use std::{ + iter::{repeat, zip}, + num::NonZeroU32, +}; use futures::{stream::iter as stream_iter, TryStreamExt}; -use futures_util::{future::try_join, StreamExt}; +use futures_util::{ + future::{try_join, try_join3}, + StreamExt, +}; use ipa_macros::Step; use crate::{ @@ -9,7 +15,7 @@ use crate::{ ff::{Field, GaloisField, Gf2, PrimeField, Serializable}, protocol::{ basics::{if_else, SecureMul, ShareKnownValue}, - boolean::{or::or, saturating_sum::SaturatingSum}, + boolean::{comparison::bitwise_less_than_constant, or::or, saturating_sum::SaturatingSum}, context::{UpgradableContext, UpgradedContext, Validator}, modulus_conversion::convert_bits, step::BitOpStep, @@ -22,18 +28,39 @@ use crate::{ }, BitDecomposed, Linear as LinearSecretSharing, SharedValue, }, - seq_join::{seq_join, seq_try_join_all}, + seq_join::seq_join, }; pub mod bucket; #[cfg(feature = "descriptive-gate")] pub mod feature_label_dot_product; -pub struct PrfShardedIpaInputRow { - prf_of_match_key: u64, - is_trigger_bit: Replicated, - breakdown_key: Replicated, - trigger_value: Replicated, +pub struct PrfShardedIpaInputRow { + pub prf_of_match_key: u64, + pub is_trigger_bit: Replicated, + pub breakdown_key: Replicated, + pub trigger_value: Replicated, + pub timestamp: Replicated, +} + +impl PrfShardedIpaInputRow { + pub fn breakdown_key_bits(&self) -> BitDecomposed> { + BitDecomposed::decompose(BK::BITS, |i| { + self.breakdown_key.map(|v| Gf2::truncate_from(v[i])) + }) + } + + pub fn trigger_value_bits(&self) -> BitDecomposed> { + BitDecomposed::decompose(TV::BITS, |i| { + self.trigger_value.map(|v| Gf2::truncate_from(v[i])) + }) + } + + pub fn timestamp_bits(&self) -> BitDecomposed> { + BitDecomposed::decompose(TS::BITS, |i| { + self.timestamp.map(|v| Gf2::truncate_from(v[i])) + }) + } } struct InputsRequiredFromPrevRow { @@ -41,6 +68,7 @@ struct InputsRequiredFromPrevRow { attributed_breakdown_key_bits: BitDecomposed>, saturating_sum: SaturatingSum>, difference_to_cap: BitDecomposed>, + source_event_timestamp: BitDecomposed>, } impl InputsRequiredFromPrevRow { @@ -68,30 +96,36 @@ impl InputsRequiredFromPrevRow { /// - `did_trigger_get_attributed` - a secret-shared bit indicating if this row corresponds to a trigger event /// which was attributed. Might be able to reveal this (after a shuffle and the addition of dummies) to minimize /// the amount of processing work that must be done in the Aggregation stage. - pub async fn compute_row_with_previous( + pub async fn compute_row_with_previous( &mut self, ctx: C, record_id: RecordId, - input_row: &PrfShardedIpaInputRow, + input_row: &PrfShardedIpaInputRow, num_saturating_sum_bits: usize, + attribution_window_seconds: Option, ) -> Result where C: UpgradedContext>, BK: GaloisField, TV: GaloisField, + TS: GaloisField, { - let bd_key = BitDecomposed::decompose(BK::BITS, |i| { - input_row.breakdown_key.map(|v| Gf2::truncate_from(v[i])) - }); - let tv = BitDecomposed::decompose(TV::BITS, |i| { - input_row.trigger_value.map(|v| Gf2::truncate_from(v[i])) - }); + let (bd_key, tv, timestamp) = ( + input_row.breakdown_key_bits(), + input_row.trigger_value_bits(), + input_row.timestamp_bits(), + ); + assert_eq!(self.saturating_sum.sum.len(), num_saturating_sum_bits); let share_of_one = Replicated::share_known_value(&ctx, Gf2::ONE); let is_source_event = &share_of_one - &input_row.is_trigger_bit; - let (ever_encountered_a_source_event, attributed_breakdown_key_bits) = try_join( + let ( + ever_encountered_a_source_event, + attributed_breakdown_key_bits, + source_event_timestamp, + ) = try_join3( or( ctx.narrow(&Step::EverEncounteredSourceEvent), record_id, @@ -105,23 +139,26 @@ impl InputsRequiredFromPrevRow { &self.attributed_breakdown_key_bits, &bd_key, ), + timestamp_of_most_recent_source_event( + ctx.narrow(&Step::SourceEventTimestamp), + record_id, + attribution_window_seconds, + &input_row.is_trigger_bit, + &self.source_event_timestamp, + ×tamp, + ), ) .await?; - let did_trigger_get_attributed = input_row - .is_trigger_bit - .multiply( - &ever_encountered_a_source_event, - ctx.narrow(&Step::DidTriggerGetAttributed), - record_id, - ) - .await?; - let attributed_trigger_value = zero_out_trigger_value_unless_attributed( ctx.narrow(&Step::AttributedTriggerValue), record_id, - &did_trigger_get_attributed, + &input_row.is_trigger_bit, + &ever_encountered_a_source_event, &tv, + attribution_window_seconds, + ×tamp, + &source_event_timestamp, ) .await?; @@ -162,9 +199,9 @@ impl InputsRequiredFromPrevRow { self.attributed_breakdown_key_bits = attributed_breakdown_key_bits.clone(); self.saturating_sum = updated_sum; self.difference_to_cap = difference_to_cap; + self.source_event_timestamp = source_event_timestamp; let outputs_for_aggregation = CappedAttributionOutputs { - did_trigger_get_attributed, attributed_breakdown_key_bits, capped_attributed_trigger_value, }; @@ -174,7 +211,6 @@ impl InputsRequiredFromPrevRow { #[derive(Debug)] pub struct CappedAttributionOutputs { - pub did_trigger_get_attributed: Replicated, pub attributed_breakdown_key_bits: BitDecomposed>, pub capped_attributed_trigger_value: BitDecomposed>, } @@ -210,6 +246,11 @@ pub(crate) enum Step { DidTriggerGetAttributed, AttributedBreakdownKey, AttributedTriggerValue, + AttributedEventCheckFlag, + CheckAttributionWindow, + ComputeTimeDelta, + CompareTimeDeltaToAttributionWindow, + SourceEventTimestamp, ComputeSaturatingSum, IsSaturatedAndPrevRowNotSaturated, ComputeDifferenceToCap, @@ -251,14 +292,15 @@ where context_per_row_depth } -fn chunk_rows_by_user( - input_rows: Vec>, -) -> Vec>> +fn chunk_rows_by_user( + input_rows: Vec>, +) -> Vec>> where BK: GaloisField, TV: GaloisField, + TS: GaloisField, { - let mut rows_for_user: Vec> = vec![]; + let mut rows_for_user: Vec> = vec![]; let mut rows_chunked_by_user = vec![]; for row in input_rows { @@ -293,20 +335,23 @@ where /// Propagates errors from multiplications /// # Panics /// Propagates errors from multiplications -pub async fn attribution_and_capping( +pub async fn attribution_and_capping( sh_ctx: C, - input_rows: Vec>, + input_rows: Vec>, num_saturating_sum_bits: usize, + attribution_window_seconds: Option, ) -> Result, Error> where C: UpgradableContext, C::UpgradedContext: UpgradedContext>, BK: GaloisField, TV: GaloisField, + TS: GaloisField, { assert!(num_saturating_sum_bits > TV::BITS as usize); assert!(TV::BITS > 0); assert!(BK::BITS > 0); + assert!(TS::BITS > 0); let rows_chunked_by_user = chunk_rows_by_user(input_rows); let histogram = compute_histogram_of_users_with_row_count(&rows_chunked_by_user); @@ -332,25 +377,28 @@ where .collect(), rows_for_user, num_saturating_sum_bits, + attribution_window_seconds, )); } - let outputs_chunked_by_user = seq_try_join_all(sh_ctx.active_work(), futures).await?; + let outputs_chunked_by_user = sh_ctx.parallel_join(futures).await?; Ok(outputs_chunked_by_user .into_iter() .flatten() .collect::>()) } -async fn evaluate_per_user_attribution_circuit( +async fn evaluate_per_user_attribution_circuit( ctx_for_row_number: &[C], record_id_for_each_depth: Vec, - rows_for_user: Vec>, + rows_for_user: Vec>, num_saturating_sum_bits: usize, + attribution_window_seconds: Option, ) -> Result, Error> where C: UpgradedContext>, BK: GaloisField, TV: GaloisField, + TS: GaloisField, { assert!(!rows_for_user.is_empty()); if rows_for_user.len() == 1 { @@ -374,6 +422,7 @@ where record_id_for_this_row_depth, row, num_saturating_sum_bits, + attribution_window_seconds, ) .await?; @@ -387,14 +436,15 @@ where /// Upon encountering the first row of data from a new user (as distinguished by a different OPRF of the match key) /// this function encapsulates the variables that must be initialized. No communication is required for this first row. /// -fn initialize_new_device_attribution_variables( +fn initialize_new_device_attribution_variables( share_of_one: Replicated, - input_row: &PrfShardedIpaInputRow, + input_row: &PrfShardedIpaInputRow, num_saturating_sum_bits: usize, ) -> InputsRequiredFromPrevRow where BK: GaloisField, TV: GaloisField, + TS: GaloisField, { InputsRequiredFromPrevRow { ever_encountered_a_source_event: share_of_one - &input_row.is_trigger_bit, @@ -408,6 +458,7 @@ where // This is incorrect in the case that the CAP is less than the maximum value of "trigger value" for a single row // Not a problem if you assume that's an invalid input difference_to_cap: BitDecomposed::new(vec![Replicated::ZERO; TV::BITS as usize]), + source_event_timestamp: BitDecomposed::new(vec![Replicated::ZERO; TS::BITS as usize]), } } @@ -416,9 +467,8 @@ where /// down to all of trigger events that follow it. /// /// The logic here is extremely simple. For each row: -/// (a) if it is a source event, take the breakdown key bits. -/// (b) if it is a trigger event, take the breakdown key bits from the preceding line -/// +/// (a) if it is a source event, take the current `breakdown_key`. +/// (b) if it is a trigger event, take the `breakdown_key` from the preceding line async fn breakdown_key_of_most_recent_source_event( ctx: C, record_id: RecordId, @@ -444,34 +494,102 @@ where )) } +/// Same as above but for timestamps. If `attribution_window_seconds` is `None`, just +/// return the previous row's timestamp. The bits aren't used but saves some multiplications. +async fn timestamp_of_most_recent_source_event( + ctx: C, + record_id: RecordId, + attribution_window_seconds: Option, + is_trigger_bit: &Replicated, + prev_row_timestamp_bits: &BitDecomposed>, + cur_row_timestamp_bits: &BitDecomposed>, +) -> Result>, Error> +where + C: UpgradedContext>, +{ + match attribution_window_seconds { + None => Ok(prev_row_timestamp_bits.clone()), + Some(_) => { + Ok(BitDecomposed::new( + ctx + .parallel_join( + cur_row_timestamp_bits + .iter() + .zip(prev_row_timestamp_bits.iter()) + .enumerate() + .map(|(i, (cur_bit, prev_bit))| { + let c = ctx.narrow(&BitOpStep::from(i)); + async move { + if_else(c, record_id, is_trigger_bit, prev_bit, cur_bit).await + } + }), + ) + .await?, + )) + } + } +} + /// /// In this simple "Last Touch Attribution" model, the `trigger_value` of a trigger event is either /// (a) Attributed to a single `breakdown_key` /// (b) Not attributed, and thus zeroed out /// -/// The logic here is extremely simple. There is a secret-shared bit indicating if a given row is an "attributed trigger event" -/// The bits of the `trigger_value` are all multiplied by this bit in order to zero out contributions from unattributed trigger events +/// The logic here is extremely simple. There is a secret-shared bit indicating if a given row is an "attributed trigger event" and +/// another secret-shared bit indicating if a given row is within the attribution window. We multiply these two bits together and +/// multiply it with the bits of the `trigger_value` in order to zero out contributions from unattributed trigger events. /// +#[allow(clippy::too_many_arguments)] async fn zero_out_trigger_value_unless_attributed( ctx: C, record_id: RecordId, - did_trigger_get_attributed: &Replicated, + is_trigger_bit: &Replicated, + ever_encountered_a_source_event: &Replicated, trigger_value: &BitDecomposed>, + attribution_window_seconds: Option, + trigger_event_timestamp: &BitDecomposed>, + source_event_timestamp: &BitDecomposed>, ) -> Result>, Error> where C: UpgradedContext>, { + let (did_trigger_get_attributed, is_trigger_within_window) = try_join( + is_trigger_bit.multiply( + ever_encountered_a_source_event, + ctx.narrow(&Step::DidTriggerGetAttributed), + record_id, + ), + is_trigger_event_within_attribution_window( + ctx.narrow(&Step::CheckAttributionWindow), + record_id, + attribution_window_seconds, + trigger_event_timestamp, + source_event_timestamp, + ), + ) + .await?; + + // save 1 multiplication if there is no attribution window + let zero_out_flag = if attribution_window_seconds.is_some() { + let c = ctx.narrow(&Step::AttributedEventCheckFlag); + did_trigger_get_attributed + .multiply(&is_trigger_within_window, c, record_id) + .await? + } else { + did_trigger_get_attributed.clone() + }; + Ok(BitDecomposed::new( ctx.parallel_join( trigger_value .iter() - .zip(repeat(did_trigger_get_attributed)) + .zip(repeat(zero_out_flag)) .enumerate() - .map(|(i, (trigger_value_bit, did_trigger_get_attributed))| { + .map(|(i, (trigger_value_bit, zero_out_flag))| { let c = ctx.narrow(&BitOpStep::from(i)); async move { trigger_value_bit - .multiply(did_trigger_get_attributed, c, record_id) + .multiply(&zero_out_flag, c, record_id) .await } }), @@ -480,6 +598,47 @@ where )) } +/// If the `attribution_window_seconds` is not `None`, we calculate the time +/// difference between the trigger event and the most recent source event, and +/// returns a secret-shared bit indicating if the trigger event is within the +/// attribution window. +async fn is_trigger_event_within_attribution_window( + ctx: C, + record_id: RecordId, + attribution_window_seconds: Option, + trigger_event_timestamp: &BitDecomposed>, + source_event_timestamp: &BitDecomposed>, +) -> Result, Error> +where + C: UpgradedContext>, +{ + if let Some(attribution_window_seconds) = attribution_window_seconds { + assert_eq!(trigger_event_timestamp.len(), source_event_timestamp.len()); + + let time_delta_bits = trigger_event_timestamp + .sub( + ctx.narrow(&Step::ComputeTimeDelta), + record_id, + source_event_timestamp, + ) + .await?; + + // The result is true if the time delta is `[0, attribution_window_seconds)` + // If we want to include the upper bound, we need to use `bitwise_greater_than_constant()` + // and negate the result. + bitwise_less_than_constant( + ctx.narrow(&Step::CompareTimeDeltaToAttributionWindow), + record_id, + &time_delta_bits, + u128::from(attribution_window_seconds.get()), + ) + .await + } else { + // if there is no attribution window, then all trigger events are attributed + Ok(Replicated::share_known_value(&ctx, Gf2::ONE)) + } +} + /// /// To provide a differential privacy guarantee, we need to bound the maximum contribution from any given user to some cap. /// @@ -549,10 +708,11 @@ where /// the results per breakdown key /// # Errors /// If there is an issue in multiplication, it will error -pub async fn attribution_and_capping_and_aggregation( +pub async fn attribution_and_capping_and_aggregation( sh_ctx: C, - input_rows: Vec>, + input_rows: Vec>, num_saturating_sum_bits: usize, + attribution_window_seconds: Option, ) -> Result, Error> where C: UpgradableContext, @@ -562,12 +722,18 @@ where F: PrimeField + ExtendableField, TV: GaloisField, BK: GaloisField, + TS: GaloisField, { let prime_field_validator = sh_ctx.narrow(&Step::BinaryValidator).validator::(); let prime_field_m_ctx = prime_field_validator.context(); - let user_level_attributions: Vec = - attribution_and_capping(sh_ctx, input_rows, num_saturating_sum_bits).await?; + let user_level_attributions: Vec = attribution_and_capping( + sh_ctx, + input_rows, + num_saturating_sum_bits, + attribution_window_seconds, + ) + .await?; do_aggregation::<_, BK, TV, F, S>(prime_field_m_ctx, user_level_attributions).await } @@ -592,6 +758,13 @@ where F: PrimeField + ExtendableField, { let num_records = user_level_attributions.len(); + + // in case no attributable conversion is found, return 0. + // as anyways the helpers know that no attributions resulted. + if num_records == 0 { + return Ok(vec![S::ZERO; 1 << BK::BITS]); + } + let (bk_vec, tv_vec): (Vec<_>, Vec<_>) = user_level_attributions .into_iter() .map(|row| { @@ -617,7 +790,7 @@ where 0..TV::BITS, ); - // tranform value bits to large field + // transform value bits to large field let large_field_values = converted_values .map(|val| BitDecomposed::to_additive_sharing_in_large_field_consuming(val.unwrap())); @@ -662,12 +835,14 @@ where #[cfg(all(test, unit_test))] pub mod tests { + use std::num::NonZeroU32; + use super::{attribution_and_capping, CappedAttributionOutputs, PrfShardedIpaInputRow}; use crate::{ - ff::{Field, Fp32BitPrime, GaloisField, Gf2, Gf3Bit, Gf5Bit}, + ff::{Field, Fp32BitPrime, GaloisField, Gf2, Gf20Bit, Gf3Bit, Gf5Bit}, protocol::{ context::{UpgradableContext, Validator}, - prf_sharding::{attribution_and_capping_and_aggregation, do_aggregation}, + ipa_prf::prf_sharding::{attribution_and_capping_and_aggregation, do_aggregation}, }, rand::Rng, secret_sharing::{ @@ -678,11 +853,12 @@ pub mod tests { test_fixture::{get_bits, Reconstruct, Runner, TestWorld}, }; - struct PreShardedAndSortedOPRFTestInput { + struct PreShardedAndSortedOPRFTestInput { prf_of_match_key: u64, is_trigger_bit: Gf2, breakdown_key: BK, trigger_value: TV, + timestamp: TS, } fn oprf_test_input( @@ -690,7 +866,23 @@ pub mod tests { is_trigger: bool, breakdown_key: u8, trigger_value: u8, - ) -> PreShardedAndSortedOPRFTestInput { + ) -> PreShardedAndSortedOPRFTestInput { + oprf_test_input_with_timestamp( + prf_of_match_key, + is_trigger, + breakdown_key, + trigger_value, + 0, + ) + } + + fn oprf_test_input_with_timestamp( + prf_of_match_key: u64, + is_trigger: bool, + breakdown_key: u8, + trigger_value: u8, + timestamp: u32, + ) -> PreShardedAndSortedOPRFTestInput { let is_trigger_bit = if is_trigger { Gf2::ONE } else { Gf2::ZERO }; PreShardedAndSortedOPRFTestInput { @@ -698,6 +890,7 @@ pub mod tests { is_trigger_bit, breakdown_key: Gf5Bit::truncate_from(breakdown_key), trigger_value: Gf3Bit::truncate_from(trigger_value), + timestamp: Gf20Bit::truncate_from(timestamp), } } @@ -743,23 +936,27 @@ pub mod tests { capped_attributed_trigger_value: BitDecomposed, } - impl IntoShares> for PreShardedAndSortedOPRFTestInput + impl IntoShares> + for PreShardedAndSortedOPRFTestInput where BK: GaloisField + IntoShares>, TV: GaloisField + IntoShares>, + TS: GaloisField + IntoShares>, { - fn share_with(self, rng: &mut R) -> [PrfShardedIpaInputRow; 3] { + fn share_with(self, rng: &mut R) -> [PrfShardedIpaInputRow; 3] { let PreShardedAndSortedOPRFTestInput { prf_of_match_key, is_trigger_bit, breakdown_key, trigger_value, + timestamp, } = self; let [is_trigger_bit0, is_trigger_bit1, is_trigger_bit2] = is_trigger_bit.share_with(rng); let [breakdown_key0, breakdown_key1, breakdown_key2] = breakdown_key.share_with(rng); let [trigger_value0, trigger_value1, trigger_value2] = trigger_value.share_with(rng); + let [timestamp0, timestamp1, timestamp2] = timestamp.share_with(rng); [ PrfShardedIpaInputRow { @@ -767,18 +964,21 @@ pub mod tests { is_trigger_bit: is_trigger_bit0, breakdown_key: breakdown_key0, trigger_value: trigger_value0, + timestamp: timestamp0, }, PrfShardedIpaInputRow { prf_of_match_key, is_trigger_bit: is_trigger_bit1, breakdown_key: breakdown_key1, trigger_value: trigger_value1, + timestamp: timestamp1, }, PrfShardedIpaInputRow { prf_of_match_key, is_trigger_bit: is_trigger_bit2, breakdown_key: breakdown_key2, trigger_value: trigger_value2, + timestamp: timestamp2, }, ] } @@ -791,27 +991,21 @@ pub mod tests { capped_attributed_trigger_value, } = self; - let did_trigger_get_attributed = Gf2::ONE; let [attributed_breakdown_key0, attributed_breakdown_key1, attributed_breakdown_key2] = attributed_breakdown_key.share_with(rng); let [capped_attributed_trigger_value0, capped_attributed_trigger_value1, capped_attributed_trigger_value2] = capped_attributed_trigger_value.share_with(rng); - let [did_trigger_get_attributed0, did_trigger_get_attributed1, did_trigger_get_attributed2] = - did_trigger_get_attributed.share_with(rng); [ CappedAttributionOutputs { - did_trigger_get_attributed: did_trigger_get_attributed0, attributed_breakdown_key_bits: attributed_breakdown_key0, capped_attributed_trigger_value: capped_attributed_trigger_value0, }, CappedAttributionOutputs { - did_trigger_get_attributed: did_trigger_get_attributed1, attributed_breakdown_key_bits: attributed_breakdown_key1, capped_attributed_trigger_value: capped_attributed_trigger_value1, }, CappedAttributionOutputs { - did_trigger_get_attributed: did_trigger_get_attributed2, attributed_breakdown_key_bits: attributed_breakdown_key2, capped_attributed_trigger_value: capped_attributed_trigger_value2, }, @@ -853,11 +1047,11 @@ pub mod tests { } #[test] - fn semi_honest_attribution_and_capping() { + fn semi_honest_attribution_and_capping_no_attribution_window() { run(|| async move { let world = TestWorld::default(); - let records: Vec> = vec![ + let records: Vec> = vec![ /* First User */ oprf_test_input(123, false, 17, 0), oprf_test_input(123, true, 0, 7), @@ -894,10 +1088,69 @@ pub mod tests { let result: Vec<_> = world .semi_honest(records.into_iter(), |ctx, input_rows| async move { - attribution_and_capping::<_, Gf5Bit, Gf3Bit>( + attribution_and_capping::<_, Gf5Bit, Gf3Bit, Gf20Bit>( + ctx, + input_rows, + num_saturating_bits, + None, + ) + .await + .unwrap() + }) + .await + .reconstruct(); + assert_eq!(result, &expected); + }); + } + + #[test] + fn semi_honest_with_attribution_window() { + run(|| async move { + let world = TestWorld::default(); + + let records: Vec> = vec![ + /* First User */ + oprf_test_input_with_timestamp(123, false, 17, 0, 0), + oprf_test_input_with_timestamp(123, true, 0, 7, 100), + oprf_test_input_with_timestamp(123, false, 20, 0, 200), + oprf_test_input_with_timestamp(123, true, 0, 3, 300), + /* Second User */ + oprf_test_input_with_timestamp(234, false, 12, 0, 0), + oprf_test_input_with_timestamp(234, true, 0, 5, 100), + /* Third User */ + oprf_test_input_with_timestamp(345, false, 20, 0, 0), + oprf_test_input_with_timestamp(345, true, 0, 7, 100), + oprf_test_input_with_timestamp(345, false, 18, 0, 200), + oprf_test_input_with_timestamp(345, false, 12, 0, 300), + oprf_test_input_with_timestamp(345, true, 0, 7, 400), + oprf_test_input_with_timestamp(345, true, 0, 7, 499), + // all the following events are ignored if the attribution window is <= 200s + oprf_test_input_with_timestamp(345, true, 0, 7, 600), + oprf_test_input_with_timestamp(345, true, 0, 7, 700), + ]; + + let expected: [PreAggregationTestOutputInDecimal; 11] = [ + decimal_bd_key_and_value(17, 7), + decimal_bd_key_and_value(20, 0), + decimal_bd_key_and_value(20, 3), + decimal_bd_key_and_value(12, 5), + decimal_bd_key_and_value(20, 7), + decimal_bd_key_and_value(18, 0), + decimal_bd_key_and_value(12, 0), + decimal_bd_key_and_value(12, 7), + decimal_bd_key_and_value(12, 7), + decimal_bd_key_and_value(12, 0), + decimal_bd_key_and_value(12, 0), + ]; + let num_saturating_bits: usize = 5; + + let result: Vec<_> = world + .semi_honest(records.into_iter(), |ctx, input_rows| async move { + attribution_and_capping::<_, Gf5Bit, Gf3Bit, Gf20Bit>( ctx, input_rows, num_saturating_bits, + NonZeroU32::new(200), ) .await .unwrap() @@ -913,7 +1166,7 @@ pub mod tests { run(|| async move { let world = TestWorld::default(); - let records: Vec> = vec![ + let records: Vec> = vec![ /* First User */ oprf_test_input(123, false, 17, 0), oprf_test_input(123, true, 0, 7), @@ -946,10 +1199,11 @@ pub mod tests { _, Gf5Bit, Gf3Bit, + Gf20Bit, Fp32BitPrime, _, Replicated, - >(ctx, input_rows, num_saturating_bits) + >(ctx, input_rows, num_saturating_bits, None) .await .unwrap() }) @@ -996,4 +1250,27 @@ pub mod tests { assert_eq!(result, &expected); }); } + + #[test] + fn semi_honest_aggregation_empty_input() { + run(|| async move { + let world = TestWorld::default(); + + let records: Vec = vec![]; + + let expected = [0_u128; 32]; + + let result: Vec<_> = world + .semi_honest(records.into_iter(), |ctx, input_rows| async move { + let validator = ctx.validator(); + let ctx = validator.context(); + do_aggregation::<_, Gf5Bit, Gf3Bit, Fp32BitPrime, _>(ctx, input_rows) + .await + .unwrap() + }) + .await + .reconstruct(); + assert_eq!(result, &expected); + }); + } } diff --git a/src/protocol/mod.rs b/src/protocol/mod.rs index 7931a1e37..cd46abdda 100644 --- a/src/protocol/mod.rs +++ b/src/protocol/mod.rs @@ -5,9 +5,9 @@ pub mod boolean; pub mod context; pub mod dp; pub mod ipa; -pub mod modulus_conversion; #[cfg(feature = "descriptive-gate")] -pub mod prf_sharding; +pub mod ipa_prf; +pub mod modulus_conversion; pub mod prss; pub mod sort; pub mod step; @@ -22,11 +22,13 @@ pub use basics::BasicProtocols; use crate::{ error::Error, - ff::{Gf40Bit, Gf8Bit}, + ff::{Gf20Bit, Gf3Bit, Gf40Bit, Gf8Bit}, }; pub type MatchKey = Gf40Bit; pub type BreakdownKey = Gf8Bit; +pub type TriggerValue = Gf3Bit; +pub type Timestamp = Gf20Bit; /// Unique identifier of the MPC query requested by report collectors /// TODO(615): Generating this unique id may be tricky as it may involve communication between helpers and @@ -85,6 +87,12 @@ impl TryFrom<&str> for QueryId { #[cfg_attr(feature = "enable-serde", derive(serde::Serialize, serde::Deserialize))] pub struct RecordId(u32); +impl Display for RecordId { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", self.0) + } +} + impl From for RecordId { fn from(v: u32) -> Self { RecordId(v) diff --git a/src/protocol/modulus_conversion/convert_shares.rs b/src/protocol/modulus_conversion/convert_shares.rs index 406c05fdc..87df09abf 100644 --- a/src/protocol/modulus_conversion/convert_shares.rs +++ b/src/protocol/modulus_conversion/convert_shares.rs @@ -96,11 +96,13 @@ impl BitConversionTriple> { } pub trait ToBitConversionTriples { + /// The type of a collection of fields that need to be carried in the stream without conversion. + type Residual: Send; // TODO: associated type defaults would be nice here. + /// Get the maximum number of bits that can be produced for this type. /// /// Note that this should be an associated constant, but one of the implementations would then need /// const generics to be more fully available in the language, so this is a method instead. For now. - fn bits(&self) -> u32; /// Produce a `BitConversionTriple` for the given role and bit index. fn triple(&self, role: Role, i: u32) -> BitConversionTriple>; @@ -116,9 +118,23 @@ pub trait ToBitConversionTriples { { BitDecomposed::new(indices.into_iter().map(|i| self.triple(role, i))) } + + fn into_triples( + self, + role: Role, + indices: I, + ) -> ( + BitDecomposed>>, + Self::Residual, + ) + where + F: PrimeField, + I: IntoIterator; } impl ToBitConversionTriples for Replicated { + type Residual = (); + fn bits(&self) -> u32 { B::BITS } @@ -126,9 +142,26 @@ impl ToBitConversionTriples for Replicated { fn triple(&self, role: Role, i: u32) -> BitConversionTriple> { BitConversionTriple::new(role, self.left()[i], self.right()[i]) } + + fn into_triples( + self, + role: Role, + indices: I, + ) -> ( + BitDecomposed>>, + Self::Residual, + ) + where + F: PrimeField, + I: IntoIterator, + { + (self.triple_range(role, indices), ()) + } } impl ToBitConversionTriples for BitDecomposed> { + type Residual = (); + fn bits(&self) -> u32 { u32::try_from(self.len()).unwrap() } @@ -138,13 +171,28 @@ impl ToBitConversionTriples for BitDecomposed> { let i = usize::try_from(i).unwrap(); BitConversionTriple::new(role, self[i].left()[BIT0], self[i].right()[BIT0]) } + + fn into_triples( + self, + role: Role, + indices: I, + ) -> ( + BitDecomposed>>, + Self::Residual, + ) + where + F: PrimeField, + I: IntoIterator, + { + (self.triple_range(role, indices), ()) + } } #[pin_project] -pub struct LocalBitConverter +pub struct LocalBitConverter where F: PrimeField, - V: ToBitConversionTriples, + V: ToBitConversionTriples, S: Stream + Send, { role: Role, @@ -154,10 +202,10 @@ where _f: PhantomData, } -impl LocalBitConverter +impl LocalBitConverter where F: PrimeField, - V: ToBitConversionTriples, + V: ToBitConversionTriples, S: Stream + Send, { pub fn new(role: Role, input: S, bits: Range) -> Self { @@ -170,19 +218,19 @@ where } } -impl Stream for LocalBitConverter +impl Stream for LocalBitConverter where F: PrimeField, - V: ToBitConversionTriples, + V: ToBitConversionTriples, S: Stream + Send, { - type Item = BitDecomposed>>; + type Item = (BitDecomposed>>, R); fn poll_next(self: Pin<&mut Self>, cx: &mut TaskContext<'_>) -> Poll> { let mut this = self.project(); match this.input.as_mut().poll_next(cx) { Poll::Ready(Some(input)) => { - Poll::Ready(Some(input.triple_range(*this.role, this.bits.clone()))) + Poll::Ready(Some(input.into_triples(*this.role, this.bits.clone()))) } Poll::Ready(None) => Poll::Ready(None), Poll::Pending => Poll::Pending, @@ -194,10 +242,10 @@ where } } -impl ExactSizeStream for LocalBitConverter +impl ExactSizeStream for LocalBitConverter where F: PrimeField, - V: ToBitConversionTriples, + V: ToBitConversionTriples, S: Stream + Send, { } @@ -251,7 +299,28 @@ pub fn convert_bits( ) -> impl Stream, Error>> where F: PrimeField, - V: ToBitConversionTriples, + V: ToBitConversionTriples, + C: UpgradedContext, + S: LinearSecretSharing + SecureMul, + VS: Stream + Unpin + Send, + for<'u> UpgradeContext<'u, C, F, RecordId>: + UpgradeToMalicious<'u, BitConversionTriple>, BitConversionTriple>, +{ + convert_some_bits(ctx, binary_shares, RecordId::FIRST, bit_range).map(|v| v.map(|(v, ())| v)) +} + +/// A version of `convert_bits` that allows for the retention of unconverted fields in the input. +/// Note that unconverted fields are not upgraded, so they might need to be upgraded either before or +/// after invoking this function. +#[tracing::instrument(name = "modulus_conversion", skip_all, fields(bits = ?bit_range, gate = %ctx.gate().as_ref()))] +pub fn convert_selected_bits( + ctx: C, + binary_shares: VS, + bit_range: Range, +) -> impl Stream, R), Error>> +where + F: PrimeField, + V: ToBitConversionTriples, C: UpgradedContext, S: LinearSecretSharing + SecureMul, VS: Stream + Unpin + Send, @@ -261,15 +330,15 @@ where convert_some_bits(ctx, binary_shares, RecordId::FIRST, bit_range) } -pub(crate) fn convert_some_bits( +pub(crate) fn convert_some_bits( ctx: C, binary_shares: VS, first_record: RecordId, bit_range: Range, -) -> impl Stream, Error>> +) -> impl Stream, R), Error>> where F: PrimeField, - V: ToBitConversionTriples, + V: ToBitConversionTriples, C: UpgradedContext, S: LinearSecretSharing + SecureMul, VS: Stream + Unpin + Send, @@ -288,7 +357,7 @@ where let stream = unfold( (ctx, locally_converted, first_record), |(ctx, mut locally_converted, record_id)| async move { - let Some(triple) = locally_converted.next().await else { + let Some((triple, residual)) = locally_converted.next().await else { return None; }; let bit_contexts = (0..).map(|i| ctx.narrow(&ConvertSharesStep::ConvertBit(i))); @@ -300,10 +369,15 @@ where .await?; convert_bit(ctx, record_id, &upgraded).await })); - Some((converted, (ctx, locally_converted, record_id + 1))) + Some(( + (converted, residual), + (ctx, locally_converted, record_id + 1), + )) }, ) - .map(|res| async move { res.await.map(|bits| BitDecomposed::new(bits)) }); + .map(|(row, residual)| async move { + row.await.map(|bits| (BitDecomposed::new(bits), residual)) + }); seq_join(active, stream) } @@ -315,16 +389,20 @@ mod tests { use crate::{ error::Error, - ff::{Field, Fp31, Fp32BitPrime}, + ff::{Field, Fp31, Fp32BitPrime, Gf2, PrimeField}, helpers::{Direction, Role}, protocol::{ context::{Context, UpgradableContext, UpgradedContext, Validator}, - modulus_conversion::{convert_bits, BitConversionTriple, LocalBitConverter}, + modulus_conversion::{ + convert_bits, convert_selected_bits, BitConversionTriple, LocalBitConverter, + ToBitConversionTriples, + }, MatchKey, RecordId, }, rand::{thread_rng, Rng}, - secret_sharing::replicated::{ - semi_honest::AdditiveShare as Replicated, ReplicatedSecretSharing, + secret_sharing::{ + replicated::{semi_honest::AdditiveShare as Replicated, ReplicatedSecretSharing}, + IntoShares, }, test_fixture::{Reconstruct, Runner, TestWorld}, }; @@ -356,6 +434,123 @@ mod tests { assert_eq!(Fp31::truncate_from(match_key[BITNUM]), result.reconstruct()); } + struct TwoBits { + convert: Replicated, + keep: Replicated, + } + + impl ToBitConversionTriples for TwoBits { + type Residual = Replicated; + + fn bits(&self) -> u32 { + 1 + } + + fn triple(&self, role: Role, i: u32) -> BitConversionTriple> { + assert_eq!(i, 0, "there is only one convertible bit in TwoBits"); + BitConversionTriple::new( + role, + self.convert.left() == Gf2::ONE, + self.convert.right() == Gf2::ONE, + ) + } + + fn into_triples( + self, + role: Role, + indices: I, + ) -> ( + crate::secret_sharing::BitDecomposed>>, + Self::Residual, + ) + where + F: PrimeField, + I: IntoIterator, + { + (self.triple_range(role, indices), self.keep) + } + } + + #[derive(Clone, Copy)] + struct TwoBitsRaw { + convert: bool, + keep: bool, + } + + impl rand::distributions::Distribution for rand::distributions::Standard { + fn sample(&self, rng: &mut R) -> TwoBitsRaw { + let r = rng.next_u32(); + TwoBitsRaw { + convert: r & 1 == 1, + keep: r & 2 == 2, + } + } + } + + impl IntoShares for TwoBitsRaw { + fn share_with(self, rng: &mut R) -> [TwoBits; 3] { + let r = rng.next_u32(); + let mut offset = 0; + let mut next_bit = || { + let b = (r >> offset) & 1 == 1; + offset += 1; + Gf2::from(b) + }; + + let c0 = next_bit(); + let c1 = next_bit(); + let k0 = next_bit(); + let k1 = next_bit(); + let c2 = c0 + c1 + Gf2::from(self.convert); + let k2 = k0 + k1 + Gf2::from(self.keep); + [ + TwoBits { + convert: Replicated::new(c0, c1), + keep: Replicated::new(k0, k1), + }, + TwoBits { + convert: Replicated::new(c1, c2), + keep: Replicated::new(k1, k2), + }, + TwoBits { + convert: Replicated::new(c2, c0), + keep: Replicated::new(k2, k0), + }, + ] + } + } + + #[tokio::test] + pub async fn retain() { + let mut rng = thread_rng(); + let world = TestWorld::default(); + let two_bits = rng.gen::(); + let result: [(Replicated, Replicated); 3] = world + .semi_honest(two_bits, |ctx, bits_share| async move { + let v = ctx.validator(); + let result = convert_selected_bits( + v.context().set_total_records(1), + once(ready(bits_share)), + 0..1, + ) + .try_collect::>() + .await + .unwrap(); + assert_eq!(result.len(), 1); + let (converted, kept) = result.into_iter().next().unwrap(); + assert_eq!(converted.len(), 1); + (converted.into_iter().next().unwrap(), kept) + }) + .await; + assert_eq!( + ( + Fp31::truncate_from(two_bits.convert), + Gf2::from(two_bits.keep) + ), + result.reconstruct() + ); + } + #[tokio::test] pub async fn one_bit_malicious() { const BITNUM: u32 = 4; @@ -426,14 +621,15 @@ mod tests { let match_key = rng.gen::(); world .malicious(match_key, |ctx, mk_share| async move { - let triples = LocalBitConverter::, _>::new( - ctx.role(), - once(ready(mk_share)), - 0..1, - ) - .collect::>() - .await; - let tweaked = tweak.flip_bit(ctx.role(), triples[0][0].clone()); + let triples = + LocalBitConverter::, _, ()>::new( + ctx.role(), + once(ready(mk_share)), + 0..1, + ) + .collect::>() + .await; + let tweaked = tweak.flip_bit(ctx.role(), triples[0].0[0].clone()); let v = ctx.validator(); let m_triples = v.context().upgrade([tweaked]).await.unwrap(); diff --git a/src/protocol/modulus_conversion/mod.rs b/src/protocol/modulus_conversion/mod.rs index 9e4d53716..67a5e8ef9 100644 --- a/src/protocol/modulus_conversion/mod.rs +++ b/src/protocol/modulus_conversion/mod.rs @@ -3,5 +3,6 @@ pub mod convert_shares; // TODO: wean usage off convert_some_bits. pub(crate) use convert_shares::convert_some_bits; pub use convert_shares::{ - convert_bits, BitConversionTriple, LocalBitConverter, ToBitConversionTriples, + convert_bits, convert_selected_bits, BitConversionTriple, LocalBitConverter, + ToBitConversionTriples, }; diff --git a/src/protocol/sort/generate_permutation.rs b/src/protocol/sort/generate_permutation.rs index 11b02ea3b..9a7cb969d 100644 --- a/src/protocol/sort/generate_permutation.rs +++ b/src/protocol/sort/generate_permutation.rs @@ -116,7 +116,7 @@ where S: LinearSecretSharing + BasicProtocols, F> + 'static, ShuffledPermutationWrapper>: DowngradeMalicious>, I: Stream, - I::Item: ToBitConversionTriples + Clone + Send + Sync, + I::Item: ToBitConversionTriples + Clone + Send + Sync, for<'u> UpgradeContext<'u, C::UpgradedContext, F, RecordId>: UpgradeToMalicious<'u, BitConversionTriple>, BitConversionTriple>, { diff --git a/src/protocol/sort/generate_permutation_opt.rs b/src/protocol/sort/generate_permutation_opt.rs index 6be3ce437..3d1db3dff 100644 --- a/src/protocol/sort/generate_permutation_opt.rs +++ b/src/protocol/sort/generate_permutation_opt.rs @@ -96,7 +96,7 @@ where C::UpgradedContext: UpgradedContext, S: LinearSecretSharing + BasicProtocols, F> + 'static, I: Stream, - I::Item: ToBitConversionTriples + Clone + Send + Sync, + I::Item: ToBitConversionTriples + Clone + Send + Sync, ShuffledPermutationWrapper>: DowngradeMalicious>, for<'u> UpgradeContext<'u, C::UpgradedContext, F, RecordId>: UpgradeToMalicious<'u, BitConversionTriple>, BitConversionTriple>, diff --git a/src/protocol/step/steps.txt b/src/protocol/step/steps.txt index d2bc41200..c5bafcded 100644 --- a/src/protocol/step/steps.txt +++ b/src/protocol/step/steps.txt @@ -8812,3 +8812,672 @@ ipa::protocol::ipa::Step::gen_sort_permutation_from_match_keys/ipa::protocol::so ipa::protocol::ipa::Step::gen_sort_permutation_from_match_keys/ipa::protocol::sort::SortStep::sort_keys/ipa::protocol::step::IpaProtocolStep::sort9/ipa::protocol::sort::SortStep::shuffle_reveal_permutation/ipa::protocol::sort::ShuffleRevealPermutationStep::shuffle/ipa::protocol::sort::ShuffleStep::shuffle1 ipa::protocol::ipa::Step::gen_sort_permutation_from_match_keys/ipa::protocol::sort::SortStep::sort_keys/ipa::protocol::step::IpaProtocolStep::sort9/ipa::protocol::sort::SortStep::shuffle_reveal_permutation/ipa::protocol::sort::ShuffleRevealPermutationStep::shuffle/ipa::protocol::sort::ShuffleStep::shuffle2 ipa::protocol::ipa::Step::gen_sort_permutation_from_match_keys/ipa::protocol::sort::SortStep::sort_keys/ipa::protocol::step::IpaProtocolStep::sort9/ipa::protocol::sort::SortStep::shuffle_reveal_permutation/ipa::protocol::sort::ShuffleRevealPermutationStep::shuffle/ipa::protocol::sort::ShuffleStep::shuffle3 +ipa::protocol::prf_sharding::Step::binary_validator +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::modulus_convert_breakdown_key_bits +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::modulus_convert_breakdown_key_bits/ipa::protocol::modulus_conversion::convert_shares::ConvertSharesStep::convert_bit0 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::modulus_convert_breakdown_key_bits/ipa::protocol::modulus_conversion::convert_shares::ConvertSharesStep::convert_bit0/ipa::protocol::modulus_conversion::convert_shares::ConvertSharesStep::upgrade +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::modulus_convert_breakdown_key_bits/ipa::protocol::modulus_conversion::convert_shares::ConvertSharesStep::convert_bit0/ipa::protocol::modulus_conversion::convert_shares::ConvertSharesStep::upgrade/ipa::protocol::context::semi_honest::UpgradeStep::upgrade_semi_honest +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::modulus_convert_breakdown_key_bits/ipa::protocol::modulus_conversion::convert_shares::ConvertSharesStep::convert_bit0/ipa::protocol::modulus_conversion::convert_shares::ConvertSharesStep::upgrade/ipa::protocol::context::semi_honest::UpgradeStep::upgrade_semi_honest/ipa::protocol::context::upgrade::UpgradeTripleStep::upgrade_bit_triple0 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::modulus_convert_breakdown_key_bits/ipa::protocol::modulus_conversion::convert_shares::ConvertSharesStep::convert_bit0/ipa::protocol::modulus_conversion::convert_shares::ConvertSharesStep::upgrade/ipa::protocol::context::semi_honest::UpgradeStep::upgrade_semi_honest/ipa::protocol::context::upgrade::UpgradeTripleStep::upgrade_bit_triple1 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::modulus_convert_breakdown_key_bits/ipa::protocol::modulus_conversion::convert_shares::ConvertSharesStep::convert_bit0/ipa::protocol::modulus_conversion::convert_shares::ConvertSharesStep::upgrade/ipa::protocol::context::semi_honest::UpgradeStep::upgrade_semi_honest/ipa::protocol::context::upgrade::UpgradeTripleStep::upgrade_bit_triple2 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::modulus_convert_breakdown_key_bits/ipa::protocol::modulus_conversion::convert_shares::ConvertSharesStep::convert_bit0/ipa::protocol::modulus_conversion::convert_shares::ConvertSharesStep::xor1 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::modulus_convert_breakdown_key_bits/ipa::protocol::modulus_conversion::convert_shares::ConvertSharesStep::convert_bit0/ipa::protocol::modulus_conversion::convert_shares::ConvertSharesStep::xor2 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::modulus_convert_breakdown_key_bits/ipa::protocol::modulus_conversion::convert_shares::ConvertSharesStep::convert_bit1 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::modulus_convert_breakdown_key_bits/ipa::protocol::modulus_conversion::convert_shares::ConvertSharesStep::convert_bit1/ipa::protocol::modulus_conversion::convert_shares::ConvertSharesStep::upgrade +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::modulus_convert_breakdown_key_bits/ipa::protocol::modulus_conversion::convert_shares::ConvertSharesStep::convert_bit1/ipa::protocol::modulus_conversion::convert_shares::ConvertSharesStep::upgrade/ipa::protocol::context::semi_honest::UpgradeStep::upgrade_semi_honest +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::modulus_convert_breakdown_key_bits/ipa::protocol::modulus_conversion::convert_shares::ConvertSharesStep::convert_bit1/ipa::protocol::modulus_conversion::convert_shares::ConvertSharesStep::upgrade/ipa::protocol::context::semi_honest::UpgradeStep::upgrade_semi_honest/ipa::protocol::context::upgrade::UpgradeTripleStep::upgrade_bit_triple0 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::modulus_convert_breakdown_key_bits/ipa::protocol::modulus_conversion::convert_shares::ConvertSharesStep::convert_bit1/ipa::protocol::modulus_conversion::convert_shares::ConvertSharesStep::upgrade/ipa::protocol::context::semi_honest::UpgradeStep::upgrade_semi_honest/ipa::protocol::context::upgrade::UpgradeTripleStep::upgrade_bit_triple1 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::modulus_convert_breakdown_key_bits/ipa::protocol::modulus_conversion::convert_shares::ConvertSharesStep::convert_bit1/ipa::protocol::modulus_conversion::convert_shares::ConvertSharesStep::upgrade/ipa::protocol::context::semi_honest::UpgradeStep::upgrade_semi_honest/ipa::protocol::context::upgrade::UpgradeTripleStep::upgrade_bit_triple2 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::modulus_convert_breakdown_key_bits/ipa::protocol::modulus_conversion::convert_shares::ConvertSharesStep::convert_bit1/ipa::protocol::modulus_conversion::convert_shares::ConvertSharesStep::xor1 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::modulus_convert_breakdown_key_bits/ipa::protocol::modulus_conversion::convert_shares::ConvertSharesStep::convert_bit1/ipa::protocol::modulus_conversion::convert_shares::ConvertSharesStep::xor2 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::modulus_convert_breakdown_key_bits/ipa::protocol::modulus_conversion::convert_shares::ConvertSharesStep::convert_bit2 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::modulus_convert_breakdown_key_bits/ipa::protocol::modulus_conversion::convert_shares::ConvertSharesStep::convert_bit2/ipa::protocol::modulus_conversion::convert_shares::ConvertSharesStep::upgrade +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::modulus_convert_breakdown_key_bits/ipa::protocol::modulus_conversion::convert_shares::ConvertSharesStep::convert_bit2/ipa::protocol::modulus_conversion::convert_shares::ConvertSharesStep::upgrade/ipa::protocol::context::semi_honest::UpgradeStep::upgrade_semi_honest +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::modulus_convert_breakdown_key_bits/ipa::protocol::modulus_conversion::convert_shares::ConvertSharesStep::convert_bit2/ipa::protocol::modulus_conversion::convert_shares::ConvertSharesStep::upgrade/ipa::protocol::context::semi_honest::UpgradeStep::upgrade_semi_honest/ipa::protocol::context::upgrade::UpgradeTripleStep::upgrade_bit_triple0 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::modulus_convert_breakdown_key_bits/ipa::protocol::modulus_conversion::convert_shares::ConvertSharesStep::convert_bit2/ipa::protocol::modulus_conversion::convert_shares::ConvertSharesStep::upgrade/ipa::protocol::context::semi_honest::UpgradeStep::upgrade_semi_honest/ipa::protocol::context::upgrade::UpgradeTripleStep::upgrade_bit_triple1 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::modulus_convert_breakdown_key_bits/ipa::protocol::modulus_conversion::convert_shares::ConvertSharesStep::convert_bit2/ipa::protocol::modulus_conversion::convert_shares::ConvertSharesStep::upgrade/ipa::protocol::context::semi_honest::UpgradeStep::upgrade_semi_honest/ipa::protocol::context::upgrade::UpgradeTripleStep::upgrade_bit_triple2 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::modulus_convert_breakdown_key_bits/ipa::protocol::modulus_conversion::convert_shares::ConvertSharesStep::convert_bit2/ipa::protocol::modulus_conversion::convert_shares::ConvertSharesStep::xor1 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::modulus_convert_breakdown_key_bits/ipa::protocol::modulus_conversion::convert_shares::ConvertSharesStep::convert_bit2/ipa::protocol::modulus_conversion::convert_shares::ConvertSharesStep::xor2 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::modulus_convert_breakdown_key_bits/ipa::protocol::modulus_conversion::convert_shares::ConvertSharesStep::convert_bit3 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::modulus_convert_breakdown_key_bits/ipa::protocol::modulus_conversion::convert_shares::ConvertSharesStep::convert_bit3/ipa::protocol::modulus_conversion::convert_shares::ConvertSharesStep::upgrade +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::modulus_convert_breakdown_key_bits/ipa::protocol::modulus_conversion::convert_shares::ConvertSharesStep::convert_bit3/ipa::protocol::modulus_conversion::convert_shares::ConvertSharesStep::upgrade/ipa::protocol::context::semi_honest::UpgradeStep::upgrade_semi_honest +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::modulus_convert_breakdown_key_bits/ipa::protocol::modulus_conversion::convert_shares::ConvertSharesStep::convert_bit3/ipa::protocol::modulus_conversion::convert_shares::ConvertSharesStep::upgrade/ipa::protocol::context::semi_honest::UpgradeStep::upgrade_semi_honest/ipa::protocol::context::upgrade::UpgradeTripleStep::upgrade_bit_triple0 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::modulus_convert_breakdown_key_bits/ipa::protocol::modulus_conversion::convert_shares::ConvertSharesStep::convert_bit3/ipa::protocol::modulus_conversion::convert_shares::ConvertSharesStep::upgrade/ipa::protocol::context::semi_honest::UpgradeStep::upgrade_semi_honest/ipa::protocol::context::upgrade::UpgradeTripleStep::upgrade_bit_triple1 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::modulus_convert_breakdown_key_bits/ipa::protocol::modulus_conversion::convert_shares::ConvertSharesStep::convert_bit3/ipa::protocol::modulus_conversion::convert_shares::ConvertSharesStep::upgrade/ipa::protocol::context::semi_honest::UpgradeStep::upgrade_semi_honest/ipa::protocol::context::upgrade::UpgradeTripleStep::upgrade_bit_triple2 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::modulus_convert_breakdown_key_bits/ipa::protocol::modulus_conversion::convert_shares::ConvertSharesStep::convert_bit3/ipa::protocol::modulus_conversion::convert_shares::ConvertSharesStep::xor1 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::modulus_convert_breakdown_key_bits/ipa::protocol::modulus_conversion::convert_shares::ConvertSharesStep::convert_bit3/ipa::protocol::modulus_conversion::convert_shares::ConvertSharesStep::xor2 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::modulus_convert_breakdown_key_bits/ipa::protocol::modulus_conversion::convert_shares::ConvertSharesStep::convert_bit4 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::modulus_convert_breakdown_key_bits/ipa::protocol::modulus_conversion::convert_shares::ConvertSharesStep::convert_bit4/ipa::protocol::modulus_conversion::convert_shares::ConvertSharesStep::upgrade +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::modulus_convert_breakdown_key_bits/ipa::protocol::modulus_conversion::convert_shares::ConvertSharesStep::convert_bit4/ipa::protocol::modulus_conversion::convert_shares::ConvertSharesStep::upgrade/ipa::protocol::context::semi_honest::UpgradeStep::upgrade_semi_honest +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::modulus_convert_breakdown_key_bits/ipa::protocol::modulus_conversion::convert_shares::ConvertSharesStep::convert_bit4/ipa::protocol::modulus_conversion::convert_shares::ConvertSharesStep::upgrade/ipa::protocol::context::semi_honest::UpgradeStep::upgrade_semi_honest/ipa::protocol::context::upgrade::UpgradeTripleStep::upgrade_bit_triple0 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::modulus_convert_breakdown_key_bits/ipa::protocol::modulus_conversion::convert_shares::ConvertSharesStep::convert_bit4/ipa::protocol::modulus_conversion::convert_shares::ConvertSharesStep::upgrade/ipa::protocol::context::semi_honest::UpgradeStep::upgrade_semi_honest/ipa::protocol::context::upgrade::UpgradeTripleStep::upgrade_bit_triple1 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::modulus_convert_breakdown_key_bits/ipa::protocol::modulus_conversion::convert_shares::ConvertSharesStep::convert_bit4/ipa::protocol::modulus_conversion::convert_shares::ConvertSharesStep::upgrade/ipa::protocol::context::semi_honest::UpgradeStep::upgrade_semi_honest/ipa::protocol::context::upgrade::UpgradeTripleStep::upgrade_bit_triple2 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::modulus_convert_breakdown_key_bits/ipa::protocol::modulus_conversion::convert_shares::ConvertSharesStep::convert_bit4/ipa::protocol::modulus_conversion::convert_shares::ConvertSharesStep::xor1 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::modulus_convert_breakdown_key_bits/ipa::protocol::modulus_conversion::convert_shares::ConvertSharesStep::convert_bit4/ipa::protocol::modulus_conversion::convert_shares::ConvertSharesStep::xor2 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::modulus_convert_breakdown_key_bits/ipa::protocol::modulus_conversion::convert_shares::ConvertSharesStep::convert_bit5 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::modulus_convert_breakdown_key_bits/ipa::protocol::modulus_conversion::convert_shares::ConvertSharesStep::convert_bit5/ipa::protocol::modulus_conversion::convert_shares::ConvertSharesStep::upgrade +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::modulus_convert_breakdown_key_bits/ipa::protocol::modulus_conversion::convert_shares::ConvertSharesStep::convert_bit5/ipa::protocol::modulus_conversion::convert_shares::ConvertSharesStep::upgrade/ipa::protocol::context::semi_honest::UpgradeStep::upgrade_semi_honest +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::modulus_convert_breakdown_key_bits/ipa::protocol::modulus_conversion::convert_shares::ConvertSharesStep::convert_bit5/ipa::protocol::modulus_conversion::convert_shares::ConvertSharesStep::upgrade/ipa::protocol::context::semi_honest::UpgradeStep::upgrade_semi_honest/ipa::protocol::context::upgrade::UpgradeTripleStep::upgrade_bit_triple0 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::modulus_convert_breakdown_key_bits/ipa::protocol::modulus_conversion::convert_shares::ConvertSharesStep::convert_bit5/ipa::protocol::modulus_conversion::convert_shares::ConvertSharesStep::upgrade/ipa::protocol::context::semi_honest::UpgradeStep::upgrade_semi_honest/ipa::protocol::context::upgrade::UpgradeTripleStep::upgrade_bit_triple1 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::modulus_convert_breakdown_key_bits/ipa::protocol::modulus_conversion::convert_shares::ConvertSharesStep::convert_bit5/ipa::protocol::modulus_conversion::convert_shares::ConvertSharesStep::upgrade/ipa::protocol::context::semi_honest::UpgradeStep::upgrade_semi_honest/ipa::protocol::context::upgrade::UpgradeTripleStep::upgrade_bit_triple2 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::modulus_convert_breakdown_key_bits/ipa::protocol::modulus_conversion::convert_shares::ConvertSharesStep::convert_bit5/ipa::protocol::modulus_conversion::convert_shares::ConvertSharesStep::xor1 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::modulus_convert_breakdown_key_bits/ipa::protocol::modulus_conversion::convert_shares::ConvertSharesStep::convert_bit5/ipa::protocol::modulus_conversion::convert_shares::ConvertSharesStep::xor2 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::modulus_convert_breakdown_key_bits/ipa::protocol::modulus_conversion::convert_shares::ConvertSharesStep::convert_bit6 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::modulus_convert_breakdown_key_bits/ipa::protocol::modulus_conversion::convert_shares::ConvertSharesStep::convert_bit6/ipa::protocol::modulus_conversion::convert_shares::ConvertSharesStep::upgrade +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::modulus_convert_breakdown_key_bits/ipa::protocol::modulus_conversion::convert_shares::ConvertSharesStep::convert_bit6/ipa::protocol::modulus_conversion::convert_shares::ConvertSharesStep::upgrade/ipa::protocol::context::semi_honest::UpgradeStep::upgrade_semi_honest +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::modulus_convert_breakdown_key_bits/ipa::protocol::modulus_conversion::convert_shares::ConvertSharesStep::convert_bit6/ipa::protocol::modulus_conversion::convert_shares::ConvertSharesStep::upgrade/ipa::protocol::context::semi_honest::UpgradeStep::upgrade_semi_honest/ipa::protocol::context::upgrade::UpgradeTripleStep::upgrade_bit_triple0 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::modulus_convert_breakdown_key_bits/ipa::protocol::modulus_conversion::convert_shares::ConvertSharesStep::convert_bit6/ipa::protocol::modulus_conversion::convert_shares::ConvertSharesStep::upgrade/ipa::protocol::context::semi_honest::UpgradeStep::upgrade_semi_honest/ipa::protocol::context::upgrade::UpgradeTripleStep::upgrade_bit_triple1 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::modulus_convert_breakdown_key_bits/ipa::protocol::modulus_conversion::convert_shares::ConvertSharesStep::convert_bit6/ipa::protocol::modulus_conversion::convert_shares::ConvertSharesStep::upgrade/ipa::protocol::context::semi_honest::UpgradeStep::upgrade_semi_honest/ipa::protocol::context::upgrade::UpgradeTripleStep::upgrade_bit_triple2 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::modulus_convert_breakdown_key_bits/ipa::protocol::modulus_conversion::convert_shares::ConvertSharesStep::convert_bit6/ipa::protocol::modulus_conversion::convert_shares::ConvertSharesStep::xor1 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::modulus_convert_breakdown_key_bits/ipa::protocol::modulus_conversion::convert_shares::ConvertSharesStep::convert_bit6/ipa::protocol::modulus_conversion::convert_shares::ConvertSharesStep::xor2 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::modulus_convert_breakdown_key_bits/ipa::protocol::modulus_conversion::convert_shares::ConvertSharesStep::convert_bit7 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::modulus_convert_breakdown_key_bits/ipa::protocol::modulus_conversion::convert_shares::ConvertSharesStep::convert_bit7/ipa::protocol::modulus_conversion::convert_shares::ConvertSharesStep::upgrade +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::modulus_convert_breakdown_key_bits/ipa::protocol::modulus_conversion::convert_shares::ConvertSharesStep::convert_bit7/ipa::protocol::modulus_conversion::convert_shares::ConvertSharesStep::upgrade/ipa::protocol::context::semi_honest::UpgradeStep::upgrade_semi_honest +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::modulus_convert_breakdown_key_bits/ipa::protocol::modulus_conversion::convert_shares::ConvertSharesStep::convert_bit7/ipa::protocol::modulus_conversion::convert_shares::ConvertSharesStep::upgrade/ipa::protocol::context::semi_honest::UpgradeStep::upgrade_semi_honest/ipa::protocol::context::upgrade::UpgradeTripleStep::upgrade_bit_triple0 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::modulus_convert_breakdown_key_bits/ipa::protocol::modulus_conversion::convert_shares::ConvertSharesStep::convert_bit7/ipa::protocol::modulus_conversion::convert_shares::ConvertSharesStep::upgrade/ipa::protocol::context::semi_honest::UpgradeStep::upgrade_semi_honest/ipa::protocol::context::upgrade::UpgradeTripleStep::upgrade_bit_triple1 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::modulus_convert_breakdown_key_bits/ipa::protocol::modulus_conversion::convert_shares::ConvertSharesStep::convert_bit7/ipa::protocol::modulus_conversion::convert_shares::ConvertSharesStep::upgrade/ipa::protocol::context::semi_honest::UpgradeStep::upgrade_semi_honest/ipa::protocol::context::upgrade::UpgradeTripleStep::upgrade_bit_triple2 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::modulus_convert_breakdown_key_bits/ipa::protocol::modulus_conversion::convert_shares::ConvertSharesStep::convert_bit7/ipa::protocol::modulus_conversion::convert_shares::ConvertSharesStep::xor1 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::modulus_convert_breakdown_key_bits/ipa::protocol::modulus_conversion::convert_shares::ConvertSharesStep::convert_bit7/ipa::protocol::modulus_conversion::convert_shares::ConvertSharesStep::xor2 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::modulus_convert_breakdown_key_bits/ipa::protocol::modulus_conversion::convert_shares::ConvertSharesStep::convert_bit8 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::modulus_convert_conversion_value_bits +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::modulus_convert_conversion_value_bits/ipa::protocol::modulus_conversion::convert_shares::ConvertSharesStep::convert_bit0 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::modulus_convert_conversion_value_bits/ipa::protocol::modulus_conversion::convert_shares::ConvertSharesStep::convert_bit0/ipa::protocol::modulus_conversion::convert_shares::ConvertSharesStep::upgrade +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::modulus_convert_conversion_value_bits/ipa::protocol::modulus_conversion::convert_shares::ConvertSharesStep::convert_bit0/ipa::protocol::modulus_conversion::convert_shares::ConvertSharesStep::upgrade/ipa::protocol::context::semi_honest::UpgradeStep::upgrade_semi_honest +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::modulus_convert_conversion_value_bits/ipa::protocol::modulus_conversion::convert_shares::ConvertSharesStep::convert_bit0/ipa::protocol::modulus_conversion::convert_shares::ConvertSharesStep::upgrade/ipa::protocol::context::semi_honest::UpgradeStep::upgrade_semi_honest/ipa::protocol::context::upgrade::UpgradeTripleStep::upgrade_bit_triple0 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::modulus_convert_conversion_value_bits/ipa::protocol::modulus_conversion::convert_shares::ConvertSharesStep::convert_bit0/ipa::protocol::modulus_conversion::convert_shares::ConvertSharesStep::upgrade/ipa::protocol::context::semi_honest::UpgradeStep::upgrade_semi_honest/ipa::protocol::context::upgrade::UpgradeTripleStep::upgrade_bit_triple1 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::modulus_convert_conversion_value_bits/ipa::protocol::modulus_conversion::convert_shares::ConvertSharesStep::convert_bit0/ipa::protocol::modulus_conversion::convert_shares::ConvertSharesStep::upgrade/ipa::protocol::context::semi_honest::UpgradeStep::upgrade_semi_honest/ipa::protocol::context::upgrade::UpgradeTripleStep::upgrade_bit_triple2 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::modulus_convert_conversion_value_bits/ipa::protocol::modulus_conversion::convert_shares::ConvertSharesStep::convert_bit0/ipa::protocol::modulus_conversion::convert_shares::ConvertSharesStep::xor1 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::modulus_convert_conversion_value_bits/ipa::protocol::modulus_conversion::convert_shares::ConvertSharesStep::convert_bit0/ipa::protocol::modulus_conversion::convert_shares::ConvertSharesStep::xor2 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::modulus_convert_conversion_value_bits/ipa::protocol::modulus_conversion::convert_shares::ConvertSharesStep::convert_bit1 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::modulus_convert_conversion_value_bits/ipa::protocol::modulus_conversion::convert_shares::ConvertSharesStep::convert_bit1/ipa::protocol::modulus_conversion::convert_shares::ConvertSharesStep::upgrade +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::modulus_convert_conversion_value_bits/ipa::protocol::modulus_conversion::convert_shares::ConvertSharesStep::convert_bit1/ipa::protocol::modulus_conversion::convert_shares::ConvertSharesStep::upgrade/ipa::protocol::context::semi_honest::UpgradeStep::upgrade_semi_honest +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::modulus_convert_conversion_value_bits/ipa::protocol::modulus_conversion::convert_shares::ConvertSharesStep::convert_bit1/ipa::protocol::modulus_conversion::convert_shares::ConvertSharesStep::upgrade/ipa::protocol::context::semi_honest::UpgradeStep::upgrade_semi_honest/ipa::protocol::context::upgrade::UpgradeTripleStep::upgrade_bit_triple0 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::modulus_convert_conversion_value_bits/ipa::protocol::modulus_conversion::convert_shares::ConvertSharesStep::convert_bit1/ipa::protocol::modulus_conversion::convert_shares::ConvertSharesStep::upgrade/ipa::protocol::context::semi_honest::UpgradeStep::upgrade_semi_honest/ipa::protocol::context::upgrade::UpgradeTripleStep::upgrade_bit_triple1 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::modulus_convert_conversion_value_bits/ipa::protocol::modulus_conversion::convert_shares::ConvertSharesStep::convert_bit1/ipa::protocol::modulus_conversion::convert_shares::ConvertSharesStep::upgrade/ipa::protocol::context::semi_honest::UpgradeStep::upgrade_semi_honest/ipa::protocol::context::upgrade::UpgradeTripleStep::upgrade_bit_triple2 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::modulus_convert_conversion_value_bits/ipa::protocol::modulus_conversion::convert_shares::ConvertSharesStep::convert_bit1/ipa::protocol::modulus_conversion::convert_shares::ConvertSharesStep::xor1 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::modulus_convert_conversion_value_bits/ipa::protocol::modulus_conversion::convert_shares::ConvertSharesStep::convert_bit1/ipa::protocol::modulus_conversion::convert_shares::ConvertSharesStep::xor2 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::modulus_convert_conversion_value_bits/ipa::protocol::modulus_conversion::convert_shares::ConvertSharesStep::convert_bit2 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::modulus_convert_conversion_value_bits/ipa::protocol::modulus_conversion::convert_shares::ConvertSharesStep::convert_bit2/ipa::protocol::modulus_conversion::convert_shares::ConvertSharesStep::upgrade +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::modulus_convert_conversion_value_bits/ipa::protocol::modulus_conversion::convert_shares::ConvertSharesStep::convert_bit2/ipa::protocol::modulus_conversion::convert_shares::ConvertSharesStep::upgrade/ipa::protocol::context::semi_honest::UpgradeStep::upgrade_semi_honest +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::modulus_convert_conversion_value_bits/ipa::protocol::modulus_conversion::convert_shares::ConvertSharesStep::convert_bit2/ipa::protocol::modulus_conversion::convert_shares::ConvertSharesStep::upgrade/ipa::protocol::context::semi_honest::UpgradeStep::upgrade_semi_honest/ipa::protocol::context::upgrade::UpgradeTripleStep::upgrade_bit_triple0 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::modulus_convert_conversion_value_bits/ipa::protocol::modulus_conversion::convert_shares::ConvertSharesStep::convert_bit2/ipa::protocol::modulus_conversion::convert_shares::ConvertSharesStep::upgrade/ipa::protocol::context::semi_honest::UpgradeStep::upgrade_semi_honest/ipa::protocol::context::upgrade::UpgradeTripleStep::upgrade_bit_triple1 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::modulus_convert_conversion_value_bits/ipa::protocol::modulus_conversion::convert_shares::ConvertSharesStep::convert_bit2/ipa::protocol::modulus_conversion::convert_shares::ConvertSharesStep::upgrade/ipa::protocol::context::semi_honest::UpgradeStep::upgrade_semi_honest/ipa::protocol::context::upgrade::UpgradeTripleStep::upgrade_bit_triple2 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::modulus_convert_conversion_value_bits/ipa::protocol::modulus_conversion::convert_shares::ConvertSharesStep::convert_bit2/ipa::protocol::modulus_conversion::convert_shares::ConvertSharesStep::xor1 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::modulus_convert_conversion_value_bits/ipa::protocol::modulus_conversion::convert_shares::ConvertSharesStep::convert_bit2/ipa::protocol::modulus_conversion::convert_shares::ConvertSharesStep::xor2 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::modulus_convert_conversion_value_bits/ipa::protocol::modulus_conversion::convert_shares::ConvertSharesStep::convert_bit3 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth0 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth0/ipa::protocol::prf_sharding::bucket::BucketStep::bit0 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth0/ipa::protocol::prf_sharding::bucket::BucketStep::bit1 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth0/ipa::protocol::prf_sharding::bucket::BucketStep::bit10 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth0/ipa::protocol::prf_sharding::bucket::BucketStep::bit100 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth0/ipa::protocol::prf_sharding::bucket::BucketStep::bit101 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth0/ipa::protocol::prf_sharding::bucket::BucketStep::bit102 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth0/ipa::protocol::prf_sharding::bucket::BucketStep::bit103 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth0/ipa::protocol::prf_sharding::bucket::BucketStep::bit104 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth0/ipa::protocol::prf_sharding::bucket::BucketStep::bit105 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth0/ipa::protocol::prf_sharding::bucket::BucketStep::bit106 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth0/ipa::protocol::prf_sharding::bucket::BucketStep::bit107 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth0/ipa::protocol::prf_sharding::bucket::BucketStep::bit108 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth0/ipa::protocol::prf_sharding::bucket::BucketStep::bit109 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth0/ipa::protocol::prf_sharding::bucket::BucketStep::bit11 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth0/ipa::protocol::prf_sharding::bucket::BucketStep::bit110 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth0/ipa::protocol::prf_sharding::bucket::BucketStep::bit111 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth0/ipa::protocol::prf_sharding::bucket::BucketStep::bit112 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth0/ipa::protocol::prf_sharding::bucket::BucketStep::bit113 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth0/ipa::protocol::prf_sharding::bucket::BucketStep::bit114 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth0/ipa::protocol::prf_sharding::bucket::BucketStep::bit115 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth0/ipa::protocol::prf_sharding::bucket::BucketStep::bit116 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth0/ipa::protocol::prf_sharding::bucket::BucketStep::bit117 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth0/ipa::protocol::prf_sharding::bucket::BucketStep::bit118 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth0/ipa::protocol::prf_sharding::bucket::BucketStep::bit119 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth0/ipa::protocol::prf_sharding::bucket::BucketStep::bit12 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth0/ipa::protocol::prf_sharding::bucket::BucketStep::bit120 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth0/ipa::protocol::prf_sharding::bucket::BucketStep::bit121 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth0/ipa::protocol::prf_sharding::bucket::BucketStep::bit122 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth0/ipa::protocol::prf_sharding::bucket::BucketStep::bit123 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth0/ipa::protocol::prf_sharding::bucket::BucketStep::bit124 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth0/ipa::protocol::prf_sharding::bucket::BucketStep::bit125 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth0/ipa::protocol::prf_sharding::bucket::BucketStep::bit126 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth0/ipa::protocol::prf_sharding::bucket::BucketStep::bit127 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth0/ipa::protocol::prf_sharding::bucket::BucketStep::bit13 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth0/ipa::protocol::prf_sharding::bucket::BucketStep::bit14 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth0/ipa::protocol::prf_sharding::bucket::BucketStep::bit15 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth0/ipa::protocol::prf_sharding::bucket::BucketStep::bit16 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth0/ipa::protocol::prf_sharding::bucket::BucketStep::bit17 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth0/ipa::protocol::prf_sharding::bucket::BucketStep::bit18 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth0/ipa::protocol::prf_sharding::bucket::BucketStep::bit19 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth0/ipa::protocol::prf_sharding::bucket::BucketStep::bit2 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth0/ipa::protocol::prf_sharding::bucket::BucketStep::bit20 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth0/ipa::protocol::prf_sharding::bucket::BucketStep::bit21 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth0/ipa::protocol::prf_sharding::bucket::BucketStep::bit22 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth0/ipa::protocol::prf_sharding::bucket::BucketStep::bit23 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth0/ipa::protocol::prf_sharding::bucket::BucketStep::bit24 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth0/ipa::protocol::prf_sharding::bucket::BucketStep::bit25 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth0/ipa::protocol::prf_sharding::bucket::BucketStep::bit26 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth0/ipa::protocol::prf_sharding::bucket::BucketStep::bit27 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth0/ipa::protocol::prf_sharding::bucket::BucketStep::bit28 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth0/ipa::protocol::prf_sharding::bucket::BucketStep::bit29 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth0/ipa::protocol::prf_sharding::bucket::BucketStep::bit3 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth0/ipa::protocol::prf_sharding::bucket::BucketStep::bit30 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth0/ipa::protocol::prf_sharding::bucket::BucketStep::bit31 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth0/ipa::protocol::prf_sharding::bucket::BucketStep::bit32 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth0/ipa::protocol::prf_sharding::bucket::BucketStep::bit33 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth0/ipa::protocol::prf_sharding::bucket::BucketStep::bit34 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth0/ipa::protocol::prf_sharding::bucket::BucketStep::bit35 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth0/ipa::protocol::prf_sharding::bucket::BucketStep::bit36 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth0/ipa::protocol::prf_sharding::bucket::BucketStep::bit37 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth0/ipa::protocol::prf_sharding::bucket::BucketStep::bit38 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth0/ipa::protocol::prf_sharding::bucket::BucketStep::bit39 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth0/ipa::protocol::prf_sharding::bucket::BucketStep::bit4 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth0/ipa::protocol::prf_sharding::bucket::BucketStep::bit40 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth0/ipa::protocol::prf_sharding::bucket::BucketStep::bit41 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth0/ipa::protocol::prf_sharding::bucket::BucketStep::bit42 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth0/ipa::protocol::prf_sharding::bucket::BucketStep::bit43 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth0/ipa::protocol::prf_sharding::bucket::BucketStep::bit44 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth0/ipa::protocol::prf_sharding::bucket::BucketStep::bit45 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth0/ipa::protocol::prf_sharding::bucket::BucketStep::bit46 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth0/ipa::protocol::prf_sharding::bucket::BucketStep::bit47 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth0/ipa::protocol::prf_sharding::bucket::BucketStep::bit48 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth0/ipa::protocol::prf_sharding::bucket::BucketStep::bit49 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth0/ipa::protocol::prf_sharding::bucket::BucketStep::bit5 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth0/ipa::protocol::prf_sharding::bucket::BucketStep::bit50 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth0/ipa::protocol::prf_sharding::bucket::BucketStep::bit51 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth0/ipa::protocol::prf_sharding::bucket::BucketStep::bit52 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth0/ipa::protocol::prf_sharding::bucket::BucketStep::bit53 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth0/ipa::protocol::prf_sharding::bucket::BucketStep::bit54 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth0/ipa::protocol::prf_sharding::bucket::BucketStep::bit55 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth0/ipa::protocol::prf_sharding::bucket::BucketStep::bit56 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth0/ipa::protocol::prf_sharding::bucket::BucketStep::bit57 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth0/ipa::protocol::prf_sharding::bucket::BucketStep::bit58 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth0/ipa::protocol::prf_sharding::bucket::BucketStep::bit59 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth0/ipa::protocol::prf_sharding::bucket::BucketStep::bit6 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth0/ipa::protocol::prf_sharding::bucket::BucketStep::bit60 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth0/ipa::protocol::prf_sharding::bucket::BucketStep::bit61 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth0/ipa::protocol::prf_sharding::bucket::BucketStep::bit62 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth0/ipa::protocol::prf_sharding::bucket::BucketStep::bit63 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth0/ipa::protocol::prf_sharding::bucket::BucketStep::bit64 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth0/ipa::protocol::prf_sharding::bucket::BucketStep::bit65 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth0/ipa::protocol::prf_sharding::bucket::BucketStep::bit66 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth0/ipa::protocol::prf_sharding::bucket::BucketStep::bit67 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth0/ipa::protocol::prf_sharding::bucket::BucketStep::bit68 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth0/ipa::protocol::prf_sharding::bucket::BucketStep::bit69 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth0/ipa::protocol::prf_sharding::bucket::BucketStep::bit7 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth0/ipa::protocol::prf_sharding::bucket::BucketStep::bit70 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth0/ipa::protocol::prf_sharding::bucket::BucketStep::bit71 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth0/ipa::protocol::prf_sharding::bucket::BucketStep::bit72 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth0/ipa::protocol::prf_sharding::bucket::BucketStep::bit73 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth0/ipa::protocol::prf_sharding::bucket::BucketStep::bit74 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth0/ipa::protocol::prf_sharding::bucket::BucketStep::bit75 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth0/ipa::protocol::prf_sharding::bucket::BucketStep::bit76 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth0/ipa::protocol::prf_sharding::bucket::BucketStep::bit77 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth0/ipa::protocol::prf_sharding::bucket::BucketStep::bit78 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth0/ipa::protocol::prf_sharding::bucket::BucketStep::bit79 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth0/ipa::protocol::prf_sharding::bucket::BucketStep::bit8 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth0/ipa::protocol::prf_sharding::bucket::BucketStep::bit80 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth0/ipa::protocol::prf_sharding::bucket::BucketStep::bit81 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth0/ipa::protocol::prf_sharding::bucket::BucketStep::bit82 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth0/ipa::protocol::prf_sharding::bucket::BucketStep::bit83 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth0/ipa::protocol::prf_sharding::bucket::BucketStep::bit84 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth0/ipa::protocol::prf_sharding::bucket::BucketStep::bit85 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth0/ipa::protocol::prf_sharding::bucket::BucketStep::bit86 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth0/ipa::protocol::prf_sharding::bucket::BucketStep::bit87 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth0/ipa::protocol::prf_sharding::bucket::BucketStep::bit88 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth0/ipa::protocol::prf_sharding::bucket::BucketStep::bit89 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth0/ipa::protocol::prf_sharding::bucket::BucketStep::bit9 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth0/ipa::protocol::prf_sharding::bucket::BucketStep::bit90 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth0/ipa::protocol::prf_sharding::bucket::BucketStep::bit91 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth0/ipa::protocol::prf_sharding::bucket::BucketStep::bit92 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth0/ipa::protocol::prf_sharding::bucket::BucketStep::bit93 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth0/ipa::protocol::prf_sharding::bucket::BucketStep::bit94 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth0/ipa::protocol::prf_sharding::bucket::BucketStep::bit95 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth0/ipa::protocol::prf_sharding::bucket::BucketStep::bit96 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth0/ipa::protocol::prf_sharding::bucket::BucketStep::bit97 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth0/ipa::protocol::prf_sharding::bucket::BucketStep::bit98 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth0/ipa::protocol::prf_sharding::bucket::BucketStep::bit99 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth1 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth1/ipa::protocol::prf_sharding::bucket::BucketStep::bit0 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth1/ipa::protocol::prf_sharding::bucket::BucketStep::bit1 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth1/ipa::protocol::prf_sharding::bucket::BucketStep::bit10 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth1/ipa::protocol::prf_sharding::bucket::BucketStep::bit11 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth1/ipa::protocol::prf_sharding::bucket::BucketStep::bit12 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth1/ipa::protocol::prf_sharding::bucket::BucketStep::bit13 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth1/ipa::protocol::prf_sharding::bucket::BucketStep::bit14 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth1/ipa::protocol::prf_sharding::bucket::BucketStep::bit15 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth1/ipa::protocol::prf_sharding::bucket::BucketStep::bit16 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth1/ipa::protocol::prf_sharding::bucket::BucketStep::bit17 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth1/ipa::protocol::prf_sharding::bucket::BucketStep::bit18 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth1/ipa::protocol::prf_sharding::bucket::BucketStep::bit19 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth1/ipa::protocol::prf_sharding::bucket::BucketStep::bit2 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth1/ipa::protocol::prf_sharding::bucket::BucketStep::bit20 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth1/ipa::protocol::prf_sharding::bucket::BucketStep::bit21 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth1/ipa::protocol::prf_sharding::bucket::BucketStep::bit22 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth1/ipa::protocol::prf_sharding::bucket::BucketStep::bit23 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth1/ipa::protocol::prf_sharding::bucket::BucketStep::bit24 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth1/ipa::protocol::prf_sharding::bucket::BucketStep::bit25 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth1/ipa::protocol::prf_sharding::bucket::BucketStep::bit26 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth1/ipa::protocol::prf_sharding::bucket::BucketStep::bit27 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth1/ipa::protocol::prf_sharding::bucket::BucketStep::bit28 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth1/ipa::protocol::prf_sharding::bucket::BucketStep::bit29 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth1/ipa::protocol::prf_sharding::bucket::BucketStep::bit3 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth1/ipa::protocol::prf_sharding::bucket::BucketStep::bit30 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth1/ipa::protocol::prf_sharding::bucket::BucketStep::bit31 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth1/ipa::protocol::prf_sharding::bucket::BucketStep::bit32 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth1/ipa::protocol::prf_sharding::bucket::BucketStep::bit33 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth1/ipa::protocol::prf_sharding::bucket::BucketStep::bit34 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth1/ipa::protocol::prf_sharding::bucket::BucketStep::bit35 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth1/ipa::protocol::prf_sharding::bucket::BucketStep::bit36 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth1/ipa::protocol::prf_sharding::bucket::BucketStep::bit37 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth1/ipa::protocol::prf_sharding::bucket::BucketStep::bit38 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth1/ipa::protocol::prf_sharding::bucket::BucketStep::bit39 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth1/ipa::protocol::prf_sharding::bucket::BucketStep::bit4 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth1/ipa::protocol::prf_sharding::bucket::BucketStep::bit40 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth1/ipa::protocol::prf_sharding::bucket::BucketStep::bit41 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth1/ipa::protocol::prf_sharding::bucket::BucketStep::bit42 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth1/ipa::protocol::prf_sharding::bucket::BucketStep::bit43 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth1/ipa::protocol::prf_sharding::bucket::BucketStep::bit44 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth1/ipa::protocol::prf_sharding::bucket::BucketStep::bit45 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth1/ipa::protocol::prf_sharding::bucket::BucketStep::bit46 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth1/ipa::protocol::prf_sharding::bucket::BucketStep::bit47 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth1/ipa::protocol::prf_sharding::bucket::BucketStep::bit48 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth1/ipa::protocol::prf_sharding::bucket::BucketStep::bit49 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth1/ipa::protocol::prf_sharding::bucket::BucketStep::bit5 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth1/ipa::protocol::prf_sharding::bucket::BucketStep::bit50 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth1/ipa::protocol::prf_sharding::bucket::BucketStep::bit51 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth1/ipa::protocol::prf_sharding::bucket::BucketStep::bit52 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth1/ipa::protocol::prf_sharding::bucket::BucketStep::bit53 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth1/ipa::protocol::prf_sharding::bucket::BucketStep::bit54 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth1/ipa::protocol::prf_sharding::bucket::BucketStep::bit55 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth1/ipa::protocol::prf_sharding::bucket::BucketStep::bit56 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth1/ipa::protocol::prf_sharding::bucket::BucketStep::bit57 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth1/ipa::protocol::prf_sharding::bucket::BucketStep::bit58 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth1/ipa::protocol::prf_sharding::bucket::BucketStep::bit59 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth1/ipa::protocol::prf_sharding::bucket::BucketStep::bit6 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth1/ipa::protocol::prf_sharding::bucket::BucketStep::bit60 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth1/ipa::protocol::prf_sharding::bucket::BucketStep::bit61 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth1/ipa::protocol::prf_sharding::bucket::BucketStep::bit62 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth1/ipa::protocol::prf_sharding::bucket::BucketStep::bit63 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth1/ipa::protocol::prf_sharding::bucket::BucketStep::bit7 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth1/ipa::protocol::prf_sharding::bucket::BucketStep::bit8 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth1/ipa::protocol::prf_sharding::bucket::BucketStep::bit9 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth2 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth2/ipa::protocol::prf_sharding::bucket::BucketStep::bit0 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth2/ipa::protocol::prf_sharding::bucket::BucketStep::bit1 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth2/ipa::protocol::prf_sharding::bucket::BucketStep::bit10 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth2/ipa::protocol::prf_sharding::bucket::BucketStep::bit11 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth2/ipa::protocol::prf_sharding::bucket::BucketStep::bit12 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth2/ipa::protocol::prf_sharding::bucket::BucketStep::bit13 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth2/ipa::protocol::prf_sharding::bucket::BucketStep::bit14 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth2/ipa::protocol::prf_sharding::bucket::BucketStep::bit15 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth2/ipa::protocol::prf_sharding::bucket::BucketStep::bit16 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth2/ipa::protocol::prf_sharding::bucket::BucketStep::bit17 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth2/ipa::protocol::prf_sharding::bucket::BucketStep::bit18 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth2/ipa::protocol::prf_sharding::bucket::BucketStep::bit19 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth2/ipa::protocol::prf_sharding::bucket::BucketStep::bit2 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth2/ipa::protocol::prf_sharding::bucket::BucketStep::bit20 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth2/ipa::protocol::prf_sharding::bucket::BucketStep::bit21 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth2/ipa::protocol::prf_sharding::bucket::BucketStep::bit22 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth2/ipa::protocol::prf_sharding::bucket::BucketStep::bit23 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth2/ipa::protocol::prf_sharding::bucket::BucketStep::bit24 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth2/ipa::protocol::prf_sharding::bucket::BucketStep::bit25 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth2/ipa::protocol::prf_sharding::bucket::BucketStep::bit26 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth2/ipa::protocol::prf_sharding::bucket::BucketStep::bit27 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth2/ipa::protocol::prf_sharding::bucket::BucketStep::bit28 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth2/ipa::protocol::prf_sharding::bucket::BucketStep::bit29 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth2/ipa::protocol::prf_sharding::bucket::BucketStep::bit3 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth2/ipa::protocol::prf_sharding::bucket::BucketStep::bit30 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth2/ipa::protocol::prf_sharding::bucket::BucketStep::bit31 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth2/ipa::protocol::prf_sharding::bucket::BucketStep::bit4 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth2/ipa::protocol::prf_sharding::bucket::BucketStep::bit5 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth2/ipa::protocol::prf_sharding::bucket::BucketStep::bit6 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth2/ipa::protocol::prf_sharding::bucket::BucketStep::bit7 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth2/ipa::protocol::prf_sharding::bucket::BucketStep::bit8 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth2/ipa::protocol::prf_sharding::bucket::BucketStep::bit9 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth3 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth3/ipa::protocol::prf_sharding::bucket::BucketStep::bit0 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth3/ipa::protocol::prf_sharding::bucket::BucketStep::bit1 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth3/ipa::protocol::prf_sharding::bucket::BucketStep::bit10 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth3/ipa::protocol::prf_sharding::bucket::BucketStep::bit11 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth3/ipa::protocol::prf_sharding::bucket::BucketStep::bit12 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth3/ipa::protocol::prf_sharding::bucket::BucketStep::bit13 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth3/ipa::protocol::prf_sharding::bucket::BucketStep::bit14 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth3/ipa::protocol::prf_sharding::bucket::BucketStep::bit15 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth3/ipa::protocol::prf_sharding::bucket::BucketStep::bit2 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth3/ipa::protocol::prf_sharding::bucket::BucketStep::bit3 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth3/ipa::protocol::prf_sharding::bucket::BucketStep::bit4 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth3/ipa::protocol::prf_sharding::bucket::BucketStep::bit5 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth3/ipa::protocol::prf_sharding::bucket::BucketStep::bit6 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth3/ipa::protocol::prf_sharding::bucket::BucketStep::bit7 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth3/ipa::protocol::prf_sharding::bucket::BucketStep::bit8 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth3/ipa::protocol::prf_sharding::bucket::BucketStep::bit9 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth4 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth4/ipa::protocol::prf_sharding::bucket::BucketStep::bit0 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth4/ipa::protocol::prf_sharding::bucket::BucketStep::bit1 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth4/ipa::protocol::prf_sharding::bucket::BucketStep::bit2 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth4/ipa::protocol::prf_sharding::bucket::BucketStep::bit3 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth4/ipa::protocol::prf_sharding::bucket::BucketStep::bit4 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth4/ipa::protocol::prf_sharding::bucket::BucketStep::bit5 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth4/ipa::protocol::prf_sharding::bucket::BucketStep::bit6 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth4/ipa::protocol::prf_sharding::bucket::BucketStep::bit7 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth5 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth5/ipa::protocol::prf_sharding::bucket::BucketStep::bit0 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth5/ipa::protocol::prf_sharding::bucket::BucketStep::bit1 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth5/ipa::protocol::prf_sharding::bucket::BucketStep::bit2 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth5/ipa::protocol::prf_sharding::bucket::BucketStep::bit3 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth6 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth6/ipa::protocol::prf_sharding::bucket::BucketStep::bit0 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth6/ipa::protocol::prf_sharding::bucket::BucketStep::bit1 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth7 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::Step::move_value_to_correct_breakdown/ipa::protocol::prf_sharding::BinaryTreeDepthStep::depth7/ipa::protocol::prf_sharding::bucket::BucketStep::bit0 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row1 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row1/ipa::protocol::prf_sharding::Step::attributed_breakdown_key +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row1/ipa::protocol::prf_sharding::Step::attributed_breakdown_key/ipa::protocol::step::BitOpStep::bit0 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row1/ipa::protocol::prf_sharding::Step::attributed_breakdown_key/ipa::protocol::step::BitOpStep::bit1 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row1/ipa::protocol::prf_sharding::Step::attributed_breakdown_key/ipa::protocol::step::BitOpStep::bit2 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row1/ipa::protocol::prf_sharding::Step::attributed_breakdown_key/ipa::protocol::step::BitOpStep::bit3 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row1/ipa::protocol::prf_sharding::Step::attributed_breakdown_key/ipa::protocol::step::BitOpStep::bit4 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row1/ipa::protocol::prf_sharding::Step::attributed_breakdown_key/ipa::protocol::step::BitOpStep::bit5 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row1/ipa::protocol::prf_sharding::Step::attributed_breakdown_key/ipa::protocol::step::BitOpStep::bit6 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row1/ipa::protocol::prf_sharding::Step::attributed_breakdown_key/ipa::protocol::step::BitOpStep::bit7 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row1/ipa::protocol::prf_sharding::Step::attributed_trigger_value +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row1/ipa::protocol::prf_sharding::Step::attributed_trigger_value/ipa::protocol::prf_sharding::Step::attributed_event_check_flag +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row1/ipa::protocol::prf_sharding::Step::attributed_trigger_value/ipa::protocol::prf_sharding::Step::check_attribution_window +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row1/ipa::protocol::prf_sharding::Step::attributed_trigger_value/ipa::protocol::prf_sharding::Step::check_attribution_window/ipa::protocol::prf_sharding::Step::compare_time_delta_to_attribution_window +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row1/ipa::protocol::prf_sharding::Step::attributed_trigger_value/ipa::protocol::prf_sharding::Step::check_attribution_window/ipa::protocol::prf_sharding::Step::compare_time_delta_to_attribution_window/ipa::protocol::boolean::comparison::Step::dot_product +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row1/ipa::protocol::prf_sharding::Step::attributed_trigger_value/ipa::protocol::prf_sharding::Step::check_attribution_window/ipa::protocol::prf_sharding::Step::compare_time_delta_to_attribution_window/ipa::protocol::boolean::comparison::Step::prefix_or +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row1/ipa::protocol::prf_sharding::Step::attributed_trigger_value/ipa::protocol::prf_sharding::Step::check_attribution_window/ipa::protocol::prf_sharding::Step::compare_time_delta_to_attribution_window/ipa::protocol::boolean::comparison::Step::prefix_or/ipa::protocol::step::BitOpStep::bit0 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row1/ipa::protocol::prf_sharding::Step::attributed_trigger_value/ipa::protocol::prf_sharding::Step::check_attribution_window/ipa::protocol::prf_sharding::Step::compare_time_delta_to_attribution_window/ipa::protocol::boolean::comparison::Step::prefix_or/ipa::protocol::step::BitOpStep::bit1 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row1/ipa::protocol::prf_sharding::Step::attributed_trigger_value/ipa::protocol::prf_sharding::Step::check_attribution_window/ipa::protocol::prf_sharding::Step::compare_time_delta_to_attribution_window/ipa::protocol::boolean::comparison::Step::prefix_or/ipa::protocol::step::BitOpStep::bit10 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row1/ipa::protocol::prf_sharding::Step::attributed_trigger_value/ipa::protocol::prf_sharding::Step::check_attribution_window/ipa::protocol::prf_sharding::Step::compare_time_delta_to_attribution_window/ipa::protocol::boolean::comparison::Step::prefix_or/ipa::protocol::step::BitOpStep::bit11 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row1/ipa::protocol::prf_sharding::Step::attributed_trigger_value/ipa::protocol::prf_sharding::Step::check_attribution_window/ipa::protocol::prf_sharding::Step::compare_time_delta_to_attribution_window/ipa::protocol::boolean::comparison::Step::prefix_or/ipa::protocol::step::BitOpStep::bit12 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row1/ipa::protocol::prf_sharding::Step::attributed_trigger_value/ipa::protocol::prf_sharding::Step::check_attribution_window/ipa::protocol::prf_sharding::Step::compare_time_delta_to_attribution_window/ipa::protocol::boolean::comparison::Step::prefix_or/ipa::protocol::step::BitOpStep::bit13 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row1/ipa::protocol::prf_sharding::Step::attributed_trigger_value/ipa::protocol::prf_sharding::Step::check_attribution_window/ipa::protocol::prf_sharding::Step::compare_time_delta_to_attribution_window/ipa::protocol::boolean::comparison::Step::prefix_or/ipa::protocol::step::BitOpStep::bit14 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row1/ipa::protocol::prf_sharding::Step::attributed_trigger_value/ipa::protocol::prf_sharding::Step::check_attribution_window/ipa::protocol::prf_sharding::Step::compare_time_delta_to_attribution_window/ipa::protocol::boolean::comparison::Step::prefix_or/ipa::protocol::step::BitOpStep::bit15 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row1/ipa::protocol::prf_sharding::Step::attributed_trigger_value/ipa::protocol::prf_sharding::Step::check_attribution_window/ipa::protocol::prf_sharding::Step::compare_time_delta_to_attribution_window/ipa::protocol::boolean::comparison::Step::prefix_or/ipa::protocol::step::BitOpStep::bit16 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row1/ipa::protocol::prf_sharding::Step::attributed_trigger_value/ipa::protocol::prf_sharding::Step::check_attribution_window/ipa::protocol::prf_sharding::Step::compare_time_delta_to_attribution_window/ipa::protocol::boolean::comparison::Step::prefix_or/ipa::protocol::step::BitOpStep::bit17 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row1/ipa::protocol::prf_sharding::Step::attributed_trigger_value/ipa::protocol::prf_sharding::Step::check_attribution_window/ipa::protocol::prf_sharding::Step::compare_time_delta_to_attribution_window/ipa::protocol::boolean::comparison::Step::prefix_or/ipa::protocol::step::BitOpStep::bit18 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row1/ipa::protocol::prf_sharding::Step::attributed_trigger_value/ipa::protocol::prf_sharding::Step::check_attribution_window/ipa::protocol::prf_sharding::Step::compare_time_delta_to_attribution_window/ipa::protocol::boolean::comparison::Step::prefix_or/ipa::protocol::step::BitOpStep::bit2 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row1/ipa::protocol::prf_sharding::Step::attributed_trigger_value/ipa::protocol::prf_sharding::Step::check_attribution_window/ipa::protocol::prf_sharding::Step::compare_time_delta_to_attribution_window/ipa::protocol::boolean::comparison::Step::prefix_or/ipa::protocol::step::BitOpStep::bit3 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row1/ipa::protocol::prf_sharding::Step::attributed_trigger_value/ipa::protocol::prf_sharding::Step::check_attribution_window/ipa::protocol::prf_sharding::Step::compare_time_delta_to_attribution_window/ipa::protocol::boolean::comparison::Step::prefix_or/ipa::protocol::step::BitOpStep::bit4 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row1/ipa::protocol::prf_sharding::Step::attributed_trigger_value/ipa::protocol::prf_sharding::Step::check_attribution_window/ipa::protocol::prf_sharding::Step::compare_time_delta_to_attribution_window/ipa::protocol::boolean::comparison::Step::prefix_or/ipa::protocol::step::BitOpStep::bit5 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row1/ipa::protocol::prf_sharding::Step::attributed_trigger_value/ipa::protocol::prf_sharding::Step::check_attribution_window/ipa::protocol::prf_sharding::Step::compare_time_delta_to_attribution_window/ipa::protocol::boolean::comparison::Step::prefix_or/ipa::protocol::step::BitOpStep::bit6 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row1/ipa::protocol::prf_sharding::Step::attributed_trigger_value/ipa::protocol::prf_sharding::Step::check_attribution_window/ipa::protocol::prf_sharding::Step::compare_time_delta_to_attribution_window/ipa::protocol::boolean::comparison::Step::prefix_or/ipa::protocol::step::BitOpStep::bit7 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row1/ipa::protocol::prf_sharding::Step::attributed_trigger_value/ipa::protocol::prf_sharding::Step::check_attribution_window/ipa::protocol::prf_sharding::Step::compare_time_delta_to_attribution_window/ipa::protocol::boolean::comparison::Step::prefix_or/ipa::protocol::step::BitOpStep::bit8 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row1/ipa::protocol::prf_sharding::Step::attributed_trigger_value/ipa::protocol::prf_sharding::Step::check_attribution_window/ipa::protocol::prf_sharding::Step::compare_time_delta_to_attribution_window/ipa::protocol::boolean::comparison::Step::prefix_or/ipa::protocol::step::BitOpStep::bit9 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row1/ipa::protocol::prf_sharding::Step::attributed_trigger_value/ipa::protocol::prf_sharding::Step::check_attribution_window/ipa::protocol::prf_sharding::Step::compute_time_delta +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row1/ipa::protocol::prf_sharding::Step::attributed_trigger_value/ipa::protocol::prf_sharding::Step::check_attribution_window/ipa::protocol::prf_sharding::Step::compute_time_delta/ipa::protocol::step::BitOpStep::bit0 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row1/ipa::protocol::prf_sharding::Step::attributed_trigger_value/ipa::protocol::prf_sharding::Step::check_attribution_window/ipa::protocol::prf_sharding::Step::compute_time_delta/ipa::protocol::step::BitOpStep::bit1 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row1/ipa::protocol::prf_sharding::Step::attributed_trigger_value/ipa::protocol::prf_sharding::Step::check_attribution_window/ipa::protocol::prf_sharding::Step::compute_time_delta/ipa::protocol::step::BitOpStep::bit10 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row1/ipa::protocol::prf_sharding::Step::attributed_trigger_value/ipa::protocol::prf_sharding::Step::check_attribution_window/ipa::protocol::prf_sharding::Step::compute_time_delta/ipa::protocol::step::BitOpStep::bit11 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row1/ipa::protocol::prf_sharding::Step::attributed_trigger_value/ipa::protocol::prf_sharding::Step::check_attribution_window/ipa::protocol::prf_sharding::Step::compute_time_delta/ipa::protocol::step::BitOpStep::bit12 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row1/ipa::protocol::prf_sharding::Step::attributed_trigger_value/ipa::protocol::prf_sharding::Step::check_attribution_window/ipa::protocol::prf_sharding::Step::compute_time_delta/ipa::protocol::step::BitOpStep::bit13 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row1/ipa::protocol::prf_sharding::Step::attributed_trigger_value/ipa::protocol::prf_sharding::Step::check_attribution_window/ipa::protocol::prf_sharding::Step::compute_time_delta/ipa::protocol::step::BitOpStep::bit14 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row1/ipa::protocol::prf_sharding::Step::attributed_trigger_value/ipa::protocol::prf_sharding::Step::check_attribution_window/ipa::protocol::prf_sharding::Step::compute_time_delta/ipa::protocol::step::BitOpStep::bit15 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row1/ipa::protocol::prf_sharding::Step::attributed_trigger_value/ipa::protocol::prf_sharding::Step::check_attribution_window/ipa::protocol::prf_sharding::Step::compute_time_delta/ipa::protocol::step::BitOpStep::bit16 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row1/ipa::protocol::prf_sharding::Step::attributed_trigger_value/ipa::protocol::prf_sharding::Step::check_attribution_window/ipa::protocol::prf_sharding::Step::compute_time_delta/ipa::protocol::step::BitOpStep::bit17 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row1/ipa::protocol::prf_sharding::Step::attributed_trigger_value/ipa::protocol::prf_sharding::Step::check_attribution_window/ipa::protocol::prf_sharding::Step::compute_time_delta/ipa::protocol::step::BitOpStep::bit18 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row1/ipa::protocol::prf_sharding::Step::attributed_trigger_value/ipa::protocol::prf_sharding::Step::check_attribution_window/ipa::protocol::prf_sharding::Step::compute_time_delta/ipa::protocol::step::BitOpStep::bit19 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row1/ipa::protocol::prf_sharding::Step::attributed_trigger_value/ipa::protocol::prf_sharding::Step::check_attribution_window/ipa::protocol::prf_sharding::Step::compute_time_delta/ipa::protocol::step::BitOpStep::bit2 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row1/ipa::protocol::prf_sharding::Step::attributed_trigger_value/ipa::protocol::prf_sharding::Step::check_attribution_window/ipa::protocol::prf_sharding::Step::compute_time_delta/ipa::protocol::step::BitOpStep::bit3 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row1/ipa::protocol::prf_sharding::Step::attributed_trigger_value/ipa::protocol::prf_sharding::Step::check_attribution_window/ipa::protocol::prf_sharding::Step::compute_time_delta/ipa::protocol::step::BitOpStep::bit4 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row1/ipa::protocol::prf_sharding::Step::attributed_trigger_value/ipa::protocol::prf_sharding::Step::check_attribution_window/ipa::protocol::prf_sharding::Step::compute_time_delta/ipa::protocol::step::BitOpStep::bit5 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row1/ipa::protocol::prf_sharding::Step::attributed_trigger_value/ipa::protocol::prf_sharding::Step::check_attribution_window/ipa::protocol::prf_sharding::Step::compute_time_delta/ipa::protocol::step::BitOpStep::bit6 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row1/ipa::protocol::prf_sharding::Step::attributed_trigger_value/ipa::protocol::prf_sharding::Step::check_attribution_window/ipa::protocol::prf_sharding::Step::compute_time_delta/ipa::protocol::step::BitOpStep::bit7 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row1/ipa::protocol::prf_sharding::Step::attributed_trigger_value/ipa::protocol::prf_sharding::Step::check_attribution_window/ipa::protocol::prf_sharding::Step::compute_time_delta/ipa::protocol::step::BitOpStep::bit8 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row1/ipa::protocol::prf_sharding::Step::attributed_trigger_value/ipa::protocol::prf_sharding::Step::check_attribution_window/ipa::protocol::prf_sharding::Step::compute_time_delta/ipa::protocol::step::BitOpStep::bit9 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row1/ipa::protocol::prf_sharding::Step::attributed_trigger_value/ipa::protocol::prf_sharding::Step::did_trigger_get_attributed +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row1/ipa::protocol::prf_sharding::Step::attributed_trigger_value/ipa::protocol::step::BitOpStep::bit0 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row1/ipa::protocol::prf_sharding::Step::attributed_trigger_value/ipa::protocol::step::BitOpStep::bit1 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row1/ipa::protocol::prf_sharding::Step::attributed_trigger_value/ipa::protocol::step::BitOpStep::bit2 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row1/ipa::protocol::prf_sharding::Step::compute_difference_to_cap +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row1/ipa::protocol::prf_sharding::Step::compute_difference_to_cap/ipa::protocol::step::BitOpStep::bit0 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row1/ipa::protocol::prf_sharding::Step::compute_difference_to_cap/ipa::protocol::step::BitOpStep::bit1 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row1/ipa::protocol::prf_sharding::Step::compute_difference_to_cap/ipa::protocol::step::BitOpStep::bit2 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row1/ipa::protocol::prf_sharding::Step::compute_saturating_sum +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row1/ipa::protocol::prf_sharding::Step::compute_saturating_sum/ipa::protocol::step::BitOpStep::bit0 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row1/ipa::protocol::prf_sharding::Step::compute_saturating_sum/ipa::protocol::step::BitOpStep::bit1 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row1/ipa::protocol::prf_sharding::Step::compute_saturating_sum/ipa::protocol::step::BitOpStep::bit2 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row1/ipa::protocol::prf_sharding::Step::compute_saturating_sum/ipa::protocol::step::BitOpStep::bit3 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row1/ipa::protocol::prf_sharding::Step::compute_saturating_sum/ipa::protocol::step::BitOpStep::bit4 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row1/ipa::protocol::prf_sharding::Step::compute_saturating_sum/ipa::protocol::step::BitOpStep::bit5 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row1/ipa::protocol::prf_sharding::Step::compute_saturating_sum/ipa::protocol::step::BitOpStep::bit6 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row1/ipa::protocol::prf_sharding::Step::compute_saturating_sum/ipa::protocol::step::BitOpStep::bit7 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row1/ipa::protocol::prf_sharding::Step::computed_capped_attributed_trigger_value_just_saturated_case +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row1/ipa::protocol::prf_sharding::Step::computed_capped_attributed_trigger_value_just_saturated_case/ipa::protocol::step::BitOpStep::bit0 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row1/ipa::protocol::prf_sharding::Step::computed_capped_attributed_trigger_value_just_saturated_case/ipa::protocol::step::BitOpStep::bit1 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row1/ipa::protocol::prf_sharding::Step::computed_capped_attributed_trigger_value_just_saturated_case/ipa::protocol::step::BitOpStep::bit2 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row1/ipa::protocol::prf_sharding::Step::computed_capped_attributed_trigger_value_not_saturated_case +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row1/ipa::protocol::prf_sharding::Step::computed_capped_attributed_trigger_value_not_saturated_case/ipa::protocol::step::BitOpStep::bit0 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row1/ipa::protocol::prf_sharding::Step::computed_capped_attributed_trigger_value_not_saturated_case/ipa::protocol::step::BitOpStep::bit1 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row1/ipa::protocol::prf_sharding::Step::computed_capped_attributed_trigger_value_not_saturated_case/ipa::protocol::step::BitOpStep::bit2 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row1/ipa::protocol::prf_sharding::Step::ever_encountered_source_event +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row1/ipa::protocol::prf_sharding::Step::is_saturated_and_prev_row_not_saturated +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row1/ipa::protocol::prf_sharding::Step::source_event_timestamp +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row1/ipa::protocol::prf_sharding::Step::source_event_timestamp/ipa::protocol::step::BitOpStep::bit0 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row1/ipa::protocol::prf_sharding::Step::source_event_timestamp/ipa::protocol::step::BitOpStep::bit1 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row1/ipa::protocol::prf_sharding::Step::source_event_timestamp/ipa::protocol::step::BitOpStep::bit10 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row1/ipa::protocol::prf_sharding::Step::source_event_timestamp/ipa::protocol::step::BitOpStep::bit11 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row1/ipa::protocol::prf_sharding::Step::source_event_timestamp/ipa::protocol::step::BitOpStep::bit12 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row1/ipa::protocol::prf_sharding::Step::source_event_timestamp/ipa::protocol::step::BitOpStep::bit13 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row1/ipa::protocol::prf_sharding::Step::source_event_timestamp/ipa::protocol::step::BitOpStep::bit14 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row1/ipa::protocol::prf_sharding::Step::source_event_timestamp/ipa::protocol::step::BitOpStep::bit15 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row1/ipa::protocol::prf_sharding::Step::source_event_timestamp/ipa::protocol::step::BitOpStep::bit16 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row1/ipa::protocol::prf_sharding::Step::source_event_timestamp/ipa::protocol::step::BitOpStep::bit17 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row1/ipa::protocol::prf_sharding::Step::source_event_timestamp/ipa::protocol::step::BitOpStep::bit18 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row1/ipa::protocol::prf_sharding::Step::source_event_timestamp/ipa::protocol::step::BitOpStep::bit19 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row1/ipa::protocol::prf_sharding::Step::source_event_timestamp/ipa::protocol::step::BitOpStep::bit2 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row1/ipa::protocol::prf_sharding::Step::source_event_timestamp/ipa::protocol::step::BitOpStep::bit3 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row1/ipa::protocol::prf_sharding::Step::source_event_timestamp/ipa::protocol::step::BitOpStep::bit4 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row1/ipa::protocol::prf_sharding::Step::source_event_timestamp/ipa::protocol::step::BitOpStep::bit5 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row1/ipa::protocol::prf_sharding::Step::source_event_timestamp/ipa::protocol::step::BitOpStep::bit6 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row1/ipa::protocol::prf_sharding::Step::source_event_timestamp/ipa::protocol::step::BitOpStep::bit7 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row1/ipa::protocol::prf_sharding::Step::source_event_timestamp/ipa::protocol::step::BitOpStep::bit8 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row1/ipa::protocol::prf_sharding::Step::source_event_timestamp/ipa::protocol::step::BitOpStep::bit9 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row2 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row2/ipa::protocol::prf_sharding::Step::attributed_breakdown_key +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row2/ipa::protocol::prf_sharding::Step::attributed_breakdown_key/ipa::protocol::step::BitOpStep::bit0 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row2/ipa::protocol::prf_sharding::Step::attributed_breakdown_key/ipa::protocol::step::BitOpStep::bit1 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row2/ipa::protocol::prf_sharding::Step::attributed_breakdown_key/ipa::protocol::step::BitOpStep::bit2 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row2/ipa::protocol::prf_sharding::Step::attributed_breakdown_key/ipa::protocol::step::BitOpStep::bit3 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row2/ipa::protocol::prf_sharding::Step::attributed_breakdown_key/ipa::protocol::step::BitOpStep::bit4 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row2/ipa::protocol::prf_sharding::Step::attributed_breakdown_key/ipa::protocol::step::BitOpStep::bit5 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row2/ipa::protocol::prf_sharding::Step::attributed_breakdown_key/ipa::protocol::step::BitOpStep::bit6 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row2/ipa::protocol::prf_sharding::Step::attributed_breakdown_key/ipa::protocol::step::BitOpStep::bit7 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row2/ipa::protocol::prf_sharding::Step::attributed_trigger_value +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row2/ipa::protocol::prf_sharding::Step::attributed_trigger_value/ipa::protocol::prf_sharding::Step::attributed_event_check_flag +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row2/ipa::protocol::prf_sharding::Step::attributed_trigger_value/ipa::protocol::prf_sharding::Step::check_attribution_window +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row2/ipa::protocol::prf_sharding::Step::attributed_trigger_value/ipa::protocol::prf_sharding::Step::check_attribution_window/ipa::protocol::prf_sharding::Step::compare_time_delta_to_attribution_window +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row2/ipa::protocol::prf_sharding::Step::attributed_trigger_value/ipa::protocol::prf_sharding::Step::check_attribution_window/ipa::protocol::prf_sharding::Step::compare_time_delta_to_attribution_window/ipa::protocol::boolean::comparison::Step::dot_product +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row2/ipa::protocol::prf_sharding::Step::attributed_trigger_value/ipa::protocol::prf_sharding::Step::check_attribution_window/ipa::protocol::prf_sharding::Step::compare_time_delta_to_attribution_window/ipa::protocol::boolean::comparison::Step::prefix_or +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row2/ipa::protocol::prf_sharding::Step::attributed_trigger_value/ipa::protocol::prf_sharding::Step::check_attribution_window/ipa::protocol::prf_sharding::Step::compare_time_delta_to_attribution_window/ipa::protocol::boolean::comparison::Step::prefix_or/ipa::protocol::step::BitOpStep::bit0 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row2/ipa::protocol::prf_sharding::Step::attributed_trigger_value/ipa::protocol::prf_sharding::Step::check_attribution_window/ipa::protocol::prf_sharding::Step::compare_time_delta_to_attribution_window/ipa::protocol::boolean::comparison::Step::prefix_or/ipa::protocol::step::BitOpStep::bit1 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row2/ipa::protocol::prf_sharding::Step::attributed_trigger_value/ipa::protocol::prf_sharding::Step::check_attribution_window/ipa::protocol::prf_sharding::Step::compare_time_delta_to_attribution_window/ipa::protocol::boolean::comparison::Step::prefix_or/ipa::protocol::step::BitOpStep::bit10 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row2/ipa::protocol::prf_sharding::Step::attributed_trigger_value/ipa::protocol::prf_sharding::Step::check_attribution_window/ipa::protocol::prf_sharding::Step::compare_time_delta_to_attribution_window/ipa::protocol::boolean::comparison::Step::prefix_or/ipa::protocol::step::BitOpStep::bit11 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row2/ipa::protocol::prf_sharding::Step::attributed_trigger_value/ipa::protocol::prf_sharding::Step::check_attribution_window/ipa::protocol::prf_sharding::Step::compare_time_delta_to_attribution_window/ipa::protocol::boolean::comparison::Step::prefix_or/ipa::protocol::step::BitOpStep::bit12 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row2/ipa::protocol::prf_sharding::Step::attributed_trigger_value/ipa::protocol::prf_sharding::Step::check_attribution_window/ipa::protocol::prf_sharding::Step::compare_time_delta_to_attribution_window/ipa::protocol::boolean::comparison::Step::prefix_or/ipa::protocol::step::BitOpStep::bit13 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row2/ipa::protocol::prf_sharding::Step::attributed_trigger_value/ipa::protocol::prf_sharding::Step::check_attribution_window/ipa::protocol::prf_sharding::Step::compare_time_delta_to_attribution_window/ipa::protocol::boolean::comparison::Step::prefix_or/ipa::protocol::step::BitOpStep::bit14 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row2/ipa::protocol::prf_sharding::Step::attributed_trigger_value/ipa::protocol::prf_sharding::Step::check_attribution_window/ipa::protocol::prf_sharding::Step::compare_time_delta_to_attribution_window/ipa::protocol::boolean::comparison::Step::prefix_or/ipa::protocol::step::BitOpStep::bit15 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row2/ipa::protocol::prf_sharding::Step::attributed_trigger_value/ipa::protocol::prf_sharding::Step::check_attribution_window/ipa::protocol::prf_sharding::Step::compare_time_delta_to_attribution_window/ipa::protocol::boolean::comparison::Step::prefix_or/ipa::protocol::step::BitOpStep::bit16 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row2/ipa::protocol::prf_sharding::Step::attributed_trigger_value/ipa::protocol::prf_sharding::Step::check_attribution_window/ipa::protocol::prf_sharding::Step::compare_time_delta_to_attribution_window/ipa::protocol::boolean::comparison::Step::prefix_or/ipa::protocol::step::BitOpStep::bit17 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row2/ipa::protocol::prf_sharding::Step::attributed_trigger_value/ipa::protocol::prf_sharding::Step::check_attribution_window/ipa::protocol::prf_sharding::Step::compare_time_delta_to_attribution_window/ipa::protocol::boolean::comparison::Step::prefix_or/ipa::protocol::step::BitOpStep::bit18 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row2/ipa::protocol::prf_sharding::Step::attributed_trigger_value/ipa::protocol::prf_sharding::Step::check_attribution_window/ipa::protocol::prf_sharding::Step::compare_time_delta_to_attribution_window/ipa::protocol::boolean::comparison::Step::prefix_or/ipa::protocol::step::BitOpStep::bit2 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row2/ipa::protocol::prf_sharding::Step::attributed_trigger_value/ipa::protocol::prf_sharding::Step::check_attribution_window/ipa::protocol::prf_sharding::Step::compare_time_delta_to_attribution_window/ipa::protocol::boolean::comparison::Step::prefix_or/ipa::protocol::step::BitOpStep::bit3 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row2/ipa::protocol::prf_sharding::Step::attributed_trigger_value/ipa::protocol::prf_sharding::Step::check_attribution_window/ipa::protocol::prf_sharding::Step::compare_time_delta_to_attribution_window/ipa::protocol::boolean::comparison::Step::prefix_or/ipa::protocol::step::BitOpStep::bit4 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row2/ipa::protocol::prf_sharding::Step::attributed_trigger_value/ipa::protocol::prf_sharding::Step::check_attribution_window/ipa::protocol::prf_sharding::Step::compare_time_delta_to_attribution_window/ipa::protocol::boolean::comparison::Step::prefix_or/ipa::protocol::step::BitOpStep::bit5 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row2/ipa::protocol::prf_sharding::Step::attributed_trigger_value/ipa::protocol::prf_sharding::Step::check_attribution_window/ipa::protocol::prf_sharding::Step::compare_time_delta_to_attribution_window/ipa::protocol::boolean::comparison::Step::prefix_or/ipa::protocol::step::BitOpStep::bit6 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row2/ipa::protocol::prf_sharding::Step::attributed_trigger_value/ipa::protocol::prf_sharding::Step::check_attribution_window/ipa::protocol::prf_sharding::Step::compare_time_delta_to_attribution_window/ipa::protocol::boolean::comparison::Step::prefix_or/ipa::protocol::step::BitOpStep::bit7 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row2/ipa::protocol::prf_sharding::Step::attributed_trigger_value/ipa::protocol::prf_sharding::Step::check_attribution_window/ipa::protocol::prf_sharding::Step::compare_time_delta_to_attribution_window/ipa::protocol::boolean::comparison::Step::prefix_or/ipa::protocol::step::BitOpStep::bit8 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row2/ipa::protocol::prf_sharding::Step::attributed_trigger_value/ipa::protocol::prf_sharding::Step::check_attribution_window/ipa::protocol::prf_sharding::Step::compare_time_delta_to_attribution_window/ipa::protocol::boolean::comparison::Step::prefix_or/ipa::protocol::step::BitOpStep::bit9 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row2/ipa::protocol::prf_sharding::Step::attributed_trigger_value/ipa::protocol::prf_sharding::Step::check_attribution_window/ipa::protocol::prf_sharding::Step::compute_time_delta +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row2/ipa::protocol::prf_sharding::Step::attributed_trigger_value/ipa::protocol::prf_sharding::Step::check_attribution_window/ipa::protocol::prf_sharding::Step::compute_time_delta/ipa::protocol::step::BitOpStep::bit0 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row2/ipa::protocol::prf_sharding::Step::attributed_trigger_value/ipa::protocol::prf_sharding::Step::check_attribution_window/ipa::protocol::prf_sharding::Step::compute_time_delta/ipa::protocol::step::BitOpStep::bit1 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row2/ipa::protocol::prf_sharding::Step::attributed_trigger_value/ipa::protocol::prf_sharding::Step::check_attribution_window/ipa::protocol::prf_sharding::Step::compute_time_delta/ipa::protocol::step::BitOpStep::bit10 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row2/ipa::protocol::prf_sharding::Step::attributed_trigger_value/ipa::protocol::prf_sharding::Step::check_attribution_window/ipa::protocol::prf_sharding::Step::compute_time_delta/ipa::protocol::step::BitOpStep::bit11 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row2/ipa::protocol::prf_sharding::Step::attributed_trigger_value/ipa::protocol::prf_sharding::Step::check_attribution_window/ipa::protocol::prf_sharding::Step::compute_time_delta/ipa::protocol::step::BitOpStep::bit12 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row2/ipa::protocol::prf_sharding::Step::attributed_trigger_value/ipa::protocol::prf_sharding::Step::check_attribution_window/ipa::protocol::prf_sharding::Step::compute_time_delta/ipa::protocol::step::BitOpStep::bit13 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row2/ipa::protocol::prf_sharding::Step::attributed_trigger_value/ipa::protocol::prf_sharding::Step::check_attribution_window/ipa::protocol::prf_sharding::Step::compute_time_delta/ipa::protocol::step::BitOpStep::bit14 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row2/ipa::protocol::prf_sharding::Step::attributed_trigger_value/ipa::protocol::prf_sharding::Step::check_attribution_window/ipa::protocol::prf_sharding::Step::compute_time_delta/ipa::protocol::step::BitOpStep::bit15 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row2/ipa::protocol::prf_sharding::Step::attributed_trigger_value/ipa::protocol::prf_sharding::Step::check_attribution_window/ipa::protocol::prf_sharding::Step::compute_time_delta/ipa::protocol::step::BitOpStep::bit16 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row2/ipa::protocol::prf_sharding::Step::attributed_trigger_value/ipa::protocol::prf_sharding::Step::check_attribution_window/ipa::protocol::prf_sharding::Step::compute_time_delta/ipa::protocol::step::BitOpStep::bit17 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row2/ipa::protocol::prf_sharding::Step::attributed_trigger_value/ipa::protocol::prf_sharding::Step::check_attribution_window/ipa::protocol::prf_sharding::Step::compute_time_delta/ipa::protocol::step::BitOpStep::bit18 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row2/ipa::protocol::prf_sharding::Step::attributed_trigger_value/ipa::protocol::prf_sharding::Step::check_attribution_window/ipa::protocol::prf_sharding::Step::compute_time_delta/ipa::protocol::step::BitOpStep::bit19 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row2/ipa::protocol::prf_sharding::Step::attributed_trigger_value/ipa::protocol::prf_sharding::Step::check_attribution_window/ipa::protocol::prf_sharding::Step::compute_time_delta/ipa::protocol::step::BitOpStep::bit2 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row2/ipa::protocol::prf_sharding::Step::attributed_trigger_value/ipa::protocol::prf_sharding::Step::check_attribution_window/ipa::protocol::prf_sharding::Step::compute_time_delta/ipa::protocol::step::BitOpStep::bit3 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row2/ipa::protocol::prf_sharding::Step::attributed_trigger_value/ipa::protocol::prf_sharding::Step::check_attribution_window/ipa::protocol::prf_sharding::Step::compute_time_delta/ipa::protocol::step::BitOpStep::bit4 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row2/ipa::protocol::prf_sharding::Step::attributed_trigger_value/ipa::protocol::prf_sharding::Step::check_attribution_window/ipa::protocol::prf_sharding::Step::compute_time_delta/ipa::protocol::step::BitOpStep::bit5 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row2/ipa::protocol::prf_sharding::Step::attributed_trigger_value/ipa::protocol::prf_sharding::Step::check_attribution_window/ipa::protocol::prf_sharding::Step::compute_time_delta/ipa::protocol::step::BitOpStep::bit6 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row2/ipa::protocol::prf_sharding::Step::attributed_trigger_value/ipa::protocol::prf_sharding::Step::check_attribution_window/ipa::protocol::prf_sharding::Step::compute_time_delta/ipa::protocol::step::BitOpStep::bit7 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row2/ipa::protocol::prf_sharding::Step::attributed_trigger_value/ipa::protocol::prf_sharding::Step::check_attribution_window/ipa::protocol::prf_sharding::Step::compute_time_delta/ipa::protocol::step::BitOpStep::bit8 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row2/ipa::protocol::prf_sharding::Step::attributed_trigger_value/ipa::protocol::prf_sharding::Step::check_attribution_window/ipa::protocol::prf_sharding::Step::compute_time_delta/ipa::protocol::step::BitOpStep::bit9 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row2/ipa::protocol::prf_sharding::Step::attributed_trigger_value/ipa::protocol::prf_sharding::Step::did_trigger_get_attributed +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row2/ipa::protocol::prf_sharding::Step::attributed_trigger_value/ipa::protocol::step::BitOpStep::bit0 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row2/ipa::protocol::prf_sharding::Step::attributed_trigger_value/ipa::protocol::step::BitOpStep::bit1 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row2/ipa::protocol::prf_sharding::Step::attributed_trigger_value/ipa::protocol::step::BitOpStep::bit2 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row2/ipa::protocol::prf_sharding::Step::compute_difference_to_cap +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row2/ipa::protocol::prf_sharding::Step::compute_difference_to_cap/ipa::protocol::step::BitOpStep::bit0 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row2/ipa::protocol::prf_sharding::Step::compute_difference_to_cap/ipa::protocol::step::BitOpStep::bit1 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row2/ipa::protocol::prf_sharding::Step::compute_difference_to_cap/ipa::protocol::step::BitOpStep::bit2 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row2/ipa::protocol::prf_sharding::Step::compute_saturating_sum +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row2/ipa::protocol::prf_sharding::Step::compute_saturating_sum/ipa::protocol::step::BitOpStep::bit0 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row2/ipa::protocol::prf_sharding::Step::compute_saturating_sum/ipa::protocol::step::BitOpStep::bit1 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row2/ipa::protocol::prf_sharding::Step::compute_saturating_sum/ipa::protocol::step::BitOpStep::bit2 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row2/ipa::protocol::prf_sharding::Step::compute_saturating_sum/ipa::protocol::step::BitOpStep::bit3 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row2/ipa::protocol::prf_sharding::Step::compute_saturating_sum/ipa::protocol::step::BitOpStep::bit4 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row2/ipa::protocol::prf_sharding::Step::compute_saturating_sum/ipa::protocol::step::BitOpStep::bit5 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row2/ipa::protocol::prf_sharding::Step::compute_saturating_sum/ipa::protocol::step::BitOpStep::bit6 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row2/ipa::protocol::prf_sharding::Step::compute_saturating_sum/ipa::protocol::step::BitOpStep::bit7 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row2/ipa::protocol::prf_sharding::Step::computed_capped_attributed_trigger_value_just_saturated_case +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row2/ipa::protocol::prf_sharding::Step::computed_capped_attributed_trigger_value_just_saturated_case/ipa::protocol::step::BitOpStep::bit0 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row2/ipa::protocol::prf_sharding::Step::computed_capped_attributed_trigger_value_just_saturated_case/ipa::protocol::step::BitOpStep::bit1 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row2/ipa::protocol::prf_sharding::Step::computed_capped_attributed_trigger_value_just_saturated_case/ipa::protocol::step::BitOpStep::bit2 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row2/ipa::protocol::prf_sharding::Step::computed_capped_attributed_trigger_value_not_saturated_case +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row2/ipa::protocol::prf_sharding::Step::computed_capped_attributed_trigger_value_not_saturated_case/ipa::protocol::step::BitOpStep::bit0 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row2/ipa::protocol::prf_sharding::Step::computed_capped_attributed_trigger_value_not_saturated_case/ipa::protocol::step::BitOpStep::bit1 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row2/ipa::protocol::prf_sharding::Step::computed_capped_attributed_trigger_value_not_saturated_case/ipa::protocol::step::BitOpStep::bit2 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row2/ipa::protocol::prf_sharding::Step::ever_encountered_source_event +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row2/ipa::protocol::prf_sharding::Step::is_saturated_and_prev_row_not_saturated +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row2/ipa::protocol::prf_sharding::Step::source_event_timestamp +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row2/ipa::protocol::prf_sharding::Step::source_event_timestamp/ipa::protocol::step::BitOpStep::bit0 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row2/ipa::protocol::prf_sharding::Step::source_event_timestamp/ipa::protocol::step::BitOpStep::bit1 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row2/ipa::protocol::prf_sharding::Step::source_event_timestamp/ipa::protocol::step::BitOpStep::bit10 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row2/ipa::protocol::prf_sharding::Step::source_event_timestamp/ipa::protocol::step::BitOpStep::bit11 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row2/ipa::protocol::prf_sharding::Step::source_event_timestamp/ipa::protocol::step::BitOpStep::bit12 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row2/ipa::protocol::prf_sharding::Step::source_event_timestamp/ipa::protocol::step::BitOpStep::bit13 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row2/ipa::protocol::prf_sharding::Step::source_event_timestamp/ipa::protocol::step::BitOpStep::bit14 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row2/ipa::protocol::prf_sharding::Step::source_event_timestamp/ipa::protocol::step::BitOpStep::bit15 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row2/ipa::protocol::prf_sharding::Step::source_event_timestamp/ipa::protocol::step::BitOpStep::bit16 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row2/ipa::protocol::prf_sharding::Step::source_event_timestamp/ipa::protocol::step::BitOpStep::bit17 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row2/ipa::protocol::prf_sharding::Step::source_event_timestamp/ipa::protocol::step::BitOpStep::bit18 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row2/ipa::protocol::prf_sharding::Step::source_event_timestamp/ipa::protocol::step::BitOpStep::bit19 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row2/ipa::protocol::prf_sharding::Step::source_event_timestamp/ipa::protocol::step::BitOpStep::bit2 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row2/ipa::protocol::prf_sharding::Step::source_event_timestamp/ipa::protocol::step::BitOpStep::bit3 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row2/ipa::protocol::prf_sharding::Step::source_event_timestamp/ipa::protocol::step::BitOpStep::bit4 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row2/ipa::protocol::prf_sharding::Step::source_event_timestamp/ipa::protocol::step::BitOpStep::bit5 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row2/ipa::protocol::prf_sharding::Step::source_event_timestamp/ipa::protocol::step::BitOpStep::bit6 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row2/ipa::protocol::prf_sharding::Step::source_event_timestamp/ipa::protocol::step::BitOpStep::bit7 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row2/ipa::protocol::prf_sharding::Step::source_event_timestamp/ipa::protocol::step::BitOpStep::bit8 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row2/ipa::protocol::prf_sharding::Step::source_event_timestamp/ipa::protocol::step::BitOpStep::bit9 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row3 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row3/ipa::protocol::prf_sharding::Step::attributed_breakdown_key +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row3/ipa::protocol::prf_sharding::Step::attributed_breakdown_key/ipa::protocol::step::BitOpStep::bit0 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row3/ipa::protocol::prf_sharding::Step::attributed_breakdown_key/ipa::protocol::step::BitOpStep::bit1 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row3/ipa::protocol::prf_sharding::Step::attributed_breakdown_key/ipa::protocol::step::BitOpStep::bit2 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row3/ipa::protocol::prf_sharding::Step::attributed_breakdown_key/ipa::protocol::step::BitOpStep::bit3 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row3/ipa::protocol::prf_sharding::Step::attributed_breakdown_key/ipa::protocol::step::BitOpStep::bit4 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row3/ipa::protocol::prf_sharding::Step::attributed_breakdown_key/ipa::protocol::step::BitOpStep::bit5 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row3/ipa::protocol::prf_sharding::Step::attributed_breakdown_key/ipa::protocol::step::BitOpStep::bit6 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row3/ipa::protocol::prf_sharding::Step::attributed_breakdown_key/ipa::protocol::step::BitOpStep::bit7 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row3/ipa::protocol::prf_sharding::Step::attributed_trigger_value +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row3/ipa::protocol::prf_sharding::Step::attributed_trigger_value/ipa::protocol::prf_sharding::Step::attributed_event_check_flag +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row3/ipa::protocol::prf_sharding::Step::attributed_trigger_value/ipa::protocol::prf_sharding::Step::check_attribution_window +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row3/ipa::protocol::prf_sharding::Step::attributed_trigger_value/ipa::protocol::prf_sharding::Step::check_attribution_window/ipa::protocol::prf_sharding::Step::compare_time_delta_to_attribution_window +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row3/ipa::protocol::prf_sharding::Step::attributed_trigger_value/ipa::protocol::prf_sharding::Step::check_attribution_window/ipa::protocol::prf_sharding::Step::compare_time_delta_to_attribution_window/ipa::protocol::boolean::comparison::Step::dot_product +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row3/ipa::protocol::prf_sharding::Step::attributed_trigger_value/ipa::protocol::prf_sharding::Step::check_attribution_window/ipa::protocol::prf_sharding::Step::compare_time_delta_to_attribution_window/ipa::protocol::boolean::comparison::Step::prefix_or +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row3/ipa::protocol::prf_sharding::Step::attributed_trigger_value/ipa::protocol::prf_sharding::Step::check_attribution_window/ipa::protocol::prf_sharding::Step::compare_time_delta_to_attribution_window/ipa::protocol::boolean::comparison::Step::prefix_or/ipa::protocol::step::BitOpStep::bit0 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row3/ipa::protocol::prf_sharding::Step::attributed_trigger_value/ipa::protocol::prf_sharding::Step::check_attribution_window/ipa::protocol::prf_sharding::Step::compare_time_delta_to_attribution_window/ipa::protocol::boolean::comparison::Step::prefix_or/ipa::protocol::step::BitOpStep::bit1 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row3/ipa::protocol::prf_sharding::Step::attributed_trigger_value/ipa::protocol::prf_sharding::Step::check_attribution_window/ipa::protocol::prf_sharding::Step::compare_time_delta_to_attribution_window/ipa::protocol::boolean::comparison::Step::prefix_or/ipa::protocol::step::BitOpStep::bit10 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row3/ipa::protocol::prf_sharding::Step::attributed_trigger_value/ipa::protocol::prf_sharding::Step::check_attribution_window/ipa::protocol::prf_sharding::Step::compare_time_delta_to_attribution_window/ipa::protocol::boolean::comparison::Step::prefix_or/ipa::protocol::step::BitOpStep::bit11 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row3/ipa::protocol::prf_sharding::Step::attributed_trigger_value/ipa::protocol::prf_sharding::Step::check_attribution_window/ipa::protocol::prf_sharding::Step::compare_time_delta_to_attribution_window/ipa::protocol::boolean::comparison::Step::prefix_or/ipa::protocol::step::BitOpStep::bit12 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row3/ipa::protocol::prf_sharding::Step::attributed_trigger_value/ipa::protocol::prf_sharding::Step::check_attribution_window/ipa::protocol::prf_sharding::Step::compare_time_delta_to_attribution_window/ipa::protocol::boolean::comparison::Step::prefix_or/ipa::protocol::step::BitOpStep::bit13 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row3/ipa::protocol::prf_sharding::Step::attributed_trigger_value/ipa::protocol::prf_sharding::Step::check_attribution_window/ipa::protocol::prf_sharding::Step::compare_time_delta_to_attribution_window/ipa::protocol::boolean::comparison::Step::prefix_or/ipa::protocol::step::BitOpStep::bit14 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row3/ipa::protocol::prf_sharding::Step::attributed_trigger_value/ipa::protocol::prf_sharding::Step::check_attribution_window/ipa::protocol::prf_sharding::Step::compare_time_delta_to_attribution_window/ipa::protocol::boolean::comparison::Step::prefix_or/ipa::protocol::step::BitOpStep::bit15 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row3/ipa::protocol::prf_sharding::Step::attributed_trigger_value/ipa::protocol::prf_sharding::Step::check_attribution_window/ipa::protocol::prf_sharding::Step::compare_time_delta_to_attribution_window/ipa::protocol::boolean::comparison::Step::prefix_or/ipa::protocol::step::BitOpStep::bit16 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row3/ipa::protocol::prf_sharding::Step::attributed_trigger_value/ipa::protocol::prf_sharding::Step::check_attribution_window/ipa::protocol::prf_sharding::Step::compare_time_delta_to_attribution_window/ipa::protocol::boolean::comparison::Step::prefix_or/ipa::protocol::step::BitOpStep::bit17 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row3/ipa::protocol::prf_sharding::Step::attributed_trigger_value/ipa::protocol::prf_sharding::Step::check_attribution_window/ipa::protocol::prf_sharding::Step::compare_time_delta_to_attribution_window/ipa::protocol::boolean::comparison::Step::prefix_or/ipa::protocol::step::BitOpStep::bit18 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row3/ipa::protocol::prf_sharding::Step::attributed_trigger_value/ipa::protocol::prf_sharding::Step::check_attribution_window/ipa::protocol::prf_sharding::Step::compare_time_delta_to_attribution_window/ipa::protocol::boolean::comparison::Step::prefix_or/ipa::protocol::step::BitOpStep::bit2 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row3/ipa::protocol::prf_sharding::Step::attributed_trigger_value/ipa::protocol::prf_sharding::Step::check_attribution_window/ipa::protocol::prf_sharding::Step::compare_time_delta_to_attribution_window/ipa::protocol::boolean::comparison::Step::prefix_or/ipa::protocol::step::BitOpStep::bit3 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row3/ipa::protocol::prf_sharding::Step::attributed_trigger_value/ipa::protocol::prf_sharding::Step::check_attribution_window/ipa::protocol::prf_sharding::Step::compare_time_delta_to_attribution_window/ipa::protocol::boolean::comparison::Step::prefix_or/ipa::protocol::step::BitOpStep::bit4 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row3/ipa::protocol::prf_sharding::Step::attributed_trigger_value/ipa::protocol::prf_sharding::Step::check_attribution_window/ipa::protocol::prf_sharding::Step::compare_time_delta_to_attribution_window/ipa::protocol::boolean::comparison::Step::prefix_or/ipa::protocol::step::BitOpStep::bit5 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row3/ipa::protocol::prf_sharding::Step::attributed_trigger_value/ipa::protocol::prf_sharding::Step::check_attribution_window/ipa::protocol::prf_sharding::Step::compare_time_delta_to_attribution_window/ipa::protocol::boolean::comparison::Step::prefix_or/ipa::protocol::step::BitOpStep::bit6 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row3/ipa::protocol::prf_sharding::Step::attributed_trigger_value/ipa::protocol::prf_sharding::Step::check_attribution_window/ipa::protocol::prf_sharding::Step::compare_time_delta_to_attribution_window/ipa::protocol::boolean::comparison::Step::prefix_or/ipa::protocol::step::BitOpStep::bit7 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row3/ipa::protocol::prf_sharding::Step::attributed_trigger_value/ipa::protocol::prf_sharding::Step::check_attribution_window/ipa::protocol::prf_sharding::Step::compare_time_delta_to_attribution_window/ipa::protocol::boolean::comparison::Step::prefix_or/ipa::protocol::step::BitOpStep::bit8 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row3/ipa::protocol::prf_sharding::Step::attributed_trigger_value/ipa::protocol::prf_sharding::Step::check_attribution_window/ipa::protocol::prf_sharding::Step::compare_time_delta_to_attribution_window/ipa::protocol::boolean::comparison::Step::prefix_or/ipa::protocol::step::BitOpStep::bit9 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row3/ipa::protocol::prf_sharding::Step::attributed_trigger_value/ipa::protocol::prf_sharding::Step::check_attribution_window/ipa::protocol::prf_sharding::Step::compute_time_delta +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row3/ipa::protocol::prf_sharding::Step::attributed_trigger_value/ipa::protocol::prf_sharding::Step::check_attribution_window/ipa::protocol::prf_sharding::Step::compute_time_delta/ipa::protocol::step::BitOpStep::bit0 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row3/ipa::protocol::prf_sharding::Step::attributed_trigger_value/ipa::protocol::prf_sharding::Step::check_attribution_window/ipa::protocol::prf_sharding::Step::compute_time_delta/ipa::protocol::step::BitOpStep::bit1 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row3/ipa::protocol::prf_sharding::Step::attributed_trigger_value/ipa::protocol::prf_sharding::Step::check_attribution_window/ipa::protocol::prf_sharding::Step::compute_time_delta/ipa::protocol::step::BitOpStep::bit10 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row3/ipa::protocol::prf_sharding::Step::attributed_trigger_value/ipa::protocol::prf_sharding::Step::check_attribution_window/ipa::protocol::prf_sharding::Step::compute_time_delta/ipa::protocol::step::BitOpStep::bit11 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row3/ipa::protocol::prf_sharding::Step::attributed_trigger_value/ipa::protocol::prf_sharding::Step::check_attribution_window/ipa::protocol::prf_sharding::Step::compute_time_delta/ipa::protocol::step::BitOpStep::bit12 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row3/ipa::protocol::prf_sharding::Step::attributed_trigger_value/ipa::protocol::prf_sharding::Step::check_attribution_window/ipa::protocol::prf_sharding::Step::compute_time_delta/ipa::protocol::step::BitOpStep::bit13 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row3/ipa::protocol::prf_sharding::Step::attributed_trigger_value/ipa::protocol::prf_sharding::Step::check_attribution_window/ipa::protocol::prf_sharding::Step::compute_time_delta/ipa::protocol::step::BitOpStep::bit14 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row3/ipa::protocol::prf_sharding::Step::attributed_trigger_value/ipa::protocol::prf_sharding::Step::check_attribution_window/ipa::protocol::prf_sharding::Step::compute_time_delta/ipa::protocol::step::BitOpStep::bit15 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row3/ipa::protocol::prf_sharding::Step::attributed_trigger_value/ipa::protocol::prf_sharding::Step::check_attribution_window/ipa::protocol::prf_sharding::Step::compute_time_delta/ipa::protocol::step::BitOpStep::bit16 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row3/ipa::protocol::prf_sharding::Step::attributed_trigger_value/ipa::protocol::prf_sharding::Step::check_attribution_window/ipa::protocol::prf_sharding::Step::compute_time_delta/ipa::protocol::step::BitOpStep::bit17 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row3/ipa::protocol::prf_sharding::Step::attributed_trigger_value/ipa::protocol::prf_sharding::Step::check_attribution_window/ipa::protocol::prf_sharding::Step::compute_time_delta/ipa::protocol::step::BitOpStep::bit18 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row3/ipa::protocol::prf_sharding::Step::attributed_trigger_value/ipa::protocol::prf_sharding::Step::check_attribution_window/ipa::protocol::prf_sharding::Step::compute_time_delta/ipa::protocol::step::BitOpStep::bit19 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row3/ipa::protocol::prf_sharding::Step::attributed_trigger_value/ipa::protocol::prf_sharding::Step::check_attribution_window/ipa::protocol::prf_sharding::Step::compute_time_delta/ipa::protocol::step::BitOpStep::bit2 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row3/ipa::protocol::prf_sharding::Step::attributed_trigger_value/ipa::protocol::prf_sharding::Step::check_attribution_window/ipa::protocol::prf_sharding::Step::compute_time_delta/ipa::protocol::step::BitOpStep::bit3 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row3/ipa::protocol::prf_sharding::Step::attributed_trigger_value/ipa::protocol::prf_sharding::Step::check_attribution_window/ipa::protocol::prf_sharding::Step::compute_time_delta/ipa::protocol::step::BitOpStep::bit4 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row3/ipa::protocol::prf_sharding::Step::attributed_trigger_value/ipa::protocol::prf_sharding::Step::check_attribution_window/ipa::protocol::prf_sharding::Step::compute_time_delta/ipa::protocol::step::BitOpStep::bit5 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row3/ipa::protocol::prf_sharding::Step::attributed_trigger_value/ipa::protocol::prf_sharding::Step::check_attribution_window/ipa::protocol::prf_sharding::Step::compute_time_delta/ipa::protocol::step::BitOpStep::bit6 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row3/ipa::protocol::prf_sharding::Step::attributed_trigger_value/ipa::protocol::prf_sharding::Step::check_attribution_window/ipa::protocol::prf_sharding::Step::compute_time_delta/ipa::protocol::step::BitOpStep::bit7 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row3/ipa::protocol::prf_sharding::Step::attributed_trigger_value/ipa::protocol::prf_sharding::Step::check_attribution_window/ipa::protocol::prf_sharding::Step::compute_time_delta/ipa::protocol::step::BitOpStep::bit8 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row3/ipa::protocol::prf_sharding::Step::attributed_trigger_value/ipa::protocol::prf_sharding::Step::check_attribution_window/ipa::protocol::prf_sharding::Step::compute_time_delta/ipa::protocol::step::BitOpStep::bit9 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row3/ipa::protocol::prf_sharding::Step::attributed_trigger_value/ipa::protocol::prf_sharding::Step::did_trigger_get_attributed +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row3/ipa::protocol::prf_sharding::Step::attributed_trigger_value/ipa::protocol::step::BitOpStep::bit0 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row3/ipa::protocol::prf_sharding::Step::attributed_trigger_value/ipa::protocol::step::BitOpStep::bit1 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row3/ipa::protocol::prf_sharding::Step::attributed_trigger_value/ipa::protocol::step::BitOpStep::bit2 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row3/ipa::protocol::prf_sharding::Step::compute_difference_to_cap +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row3/ipa::protocol::prf_sharding::Step::compute_difference_to_cap/ipa::protocol::step::BitOpStep::bit0 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row3/ipa::protocol::prf_sharding::Step::compute_difference_to_cap/ipa::protocol::step::BitOpStep::bit1 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row3/ipa::protocol::prf_sharding::Step::compute_difference_to_cap/ipa::protocol::step::BitOpStep::bit2 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row3/ipa::protocol::prf_sharding::Step::compute_saturating_sum +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row3/ipa::protocol::prf_sharding::Step::compute_saturating_sum/ipa::protocol::step::BitOpStep::bit0 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row3/ipa::protocol::prf_sharding::Step::compute_saturating_sum/ipa::protocol::step::BitOpStep::bit1 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row3/ipa::protocol::prf_sharding::Step::compute_saturating_sum/ipa::protocol::step::BitOpStep::bit2 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row3/ipa::protocol::prf_sharding::Step::compute_saturating_sum/ipa::protocol::step::BitOpStep::bit3 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row3/ipa::protocol::prf_sharding::Step::compute_saturating_sum/ipa::protocol::step::BitOpStep::bit4 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row3/ipa::protocol::prf_sharding::Step::compute_saturating_sum/ipa::protocol::step::BitOpStep::bit5 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row3/ipa::protocol::prf_sharding::Step::compute_saturating_sum/ipa::protocol::step::BitOpStep::bit6 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row3/ipa::protocol::prf_sharding::Step::compute_saturating_sum/ipa::protocol::step::BitOpStep::bit7 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row3/ipa::protocol::prf_sharding::Step::computed_capped_attributed_trigger_value_just_saturated_case +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row3/ipa::protocol::prf_sharding::Step::computed_capped_attributed_trigger_value_just_saturated_case/ipa::protocol::step::BitOpStep::bit0 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row3/ipa::protocol::prf_sharding::Step::computed_capped_attributed_trigger_value_just_saturated_case/ipa::protocol::step::BitOpStep::bit1 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row3/ipa::protocol::prf_sharding::Step::computed_capped_attributed_trigger_value_just_saturated_case/ipa::protocol::step::BitOpStep::bit2 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row3/ipa::protocol::prf_sharding::Step::computed_capped_attributed_trigger_value_not_saturated_case +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row3/ipa::protocol::prf_sharding::Step::computed_capped_attributed_trigger_value_not_saturated_case/ipa::protocol::step::BitOpStep::bit0 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row3/ipa::protocol::prf_sharding::Step::computed_capped_attributed_trigger_value_not_saturated_case/ipa::protocol::step::BitOpStep::bit1 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row3/ipa::protocol::prf_sharding::Step::computed_capped_attributed_trigger_value_not_saturated_case/ipa::protocol::step::BitOpStep::bit2 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row3/ipa::protocol::prf_sharding::Step::ever_encountered_source_event +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row3/ipa::protocol::prf_sharding::Step::is_saturated_and_prev_row_not_saturated +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row3/ipa::protocol::prf_sharding::Step::source_event_timestamp +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row3/ipa::protocol::prf_sharding::Step::source_event_timestamp/ipa::protocol::step::BitOpStep::bit0 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row3/ipa::protocol::prf_sharding::Step::source_event_timestamp/ipa::protocol::step::BitOpStep::bit1 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row3/ipa::protocol::prf_sharding::Step::source_event_timestamp/ipa::protocol::step::BitOpStep::bit10 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row3/ipa::protocol::prf_sharding::Step::source_event_timestamp/ipa::protocol::step::BitOpStep::bit11 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row3/ipa::protocol::prf_sharding::Step::source_event_timestamp/ipa::protocol::step::BitOpStep::bit12 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row3/ipa::protocol::prf_sharding::Step::source_event_timestamp/ipa::protocol::step::BitOpStep::bit13 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row3/ipa::protocol::prf_sharding::Step::source_event_timestamp/ipa::protocol::step::BitOpStep::bit14 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row3/ipa::protocol::prf_sharding::Step::source_event_timestamp/ipa::protocol::step::BitOpStep::bit15 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row3/ipa::protocol::prf_sharding::Step::source_event_timestamp/ipa::protocol::step::BitOpStep::bit16 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row3/ipa::protocol::prf_sharding::Step::source_event_timestamp/ipa::protocol::step::BitOpStep::bit17 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row3/ipa::protocol::prf_sharding::Step::source_event_timestamp/ipa::protocol::step::BitOpStep::bit18 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row3/ipa::protocol::prf_sharding::Step::source_event_timestamp/ipa::protocol::step::BitOpStep::bit19 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row3/ipa::protocol::prf_sharding::Step::source_event_timestamp/ipa::protocol::step::BitOpStep::bit2 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row3/ipa::protocol::prf_sharding::Step::source_event_timestamp/ipa::protocol::step::BitOpStep::bit3 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row3/ipa::protocol::prf_sharding::Step::source_event_timestamp/ipa::protocol::step::BitOpStep::bit4 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row3/ipa::protocol::prf_sharding::Step::source_event_timestamp/ipa::protocol::step::BitOpStep::bit5 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row3/ipa::protocol::prf_sharding::Step::source_event_timestamp/ipa::protocol::step::BitOpStep::bit6 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row3/ipa::protocol::prf_sharding::Step::source_event_timestamp/ipa::protocol::step::BitOpStep::bit7 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row3/ipa::protocol::prf_sharding::Step::source_event_timestamp/ipa::protocol::step::BitOpStep::bit8 +ipa::protocol::prf_sharding::Step::binary_validator/ipa::protocol::prf_sharding::UserNthRowStep::row3/ipa::protocol::prf_sharding::Step::source_event_timestamp/ipa::protocol::step::BitOpStep::bit9 diff --git a/src/query/executor.rs b/src/query/executor.rs index d99e6df4f..4da5f7a6c 100644 --- a/src/query/executor.rs +++ b/src/query/executor.rs @@ -14,6 +14,7 @@ use rand_core::SeedableRng; use shuttle::future as tokio; use typenum::Unsigned; +use super::runner::OprfIpaQuery; #[cfg(any(test, feature = "cli", feature = "test-fixture"))] use crate::query::runner::execute_test_multiply; use crate::{ @@ -202,6 +203,33 @@ pub fn execute( }, ) } + (QueryType::OprfIpa(ipa_config), FieldType::Fp32BitPrime) => do_query( + config, + gateway, + input, + move |prss, gateway, config, input| { + let ctx = SemiHonestContext::new(prss, gateway); + Box::pin( + OprfIpaQuery::<_, Fp32BitPrime>::new(ipa_config) + .execute(ctx, config.size, input) + .then(|res| ready(res.map(|out| Box::new(out) as Box))), + ) + }, + ), + #[cfg(any(test, feature = "weak-field"))] + (QueryType::OprfIpa(ipa_config), FieldType::Fp31) => do_query( + config, + gateway, + input, + move |prss, gateway, config, input| { + let ctx = SemiHonestContext::new(prss, gateway); + Box::pin( + OprfIpaQuery::<_, Fp32BitPrime>::new(ipa_config) + .execute(ctx, config.size, input) + .then(|res| ready(res.map(|out| Box::new(out) as Box))), + ) + }, + ), } } diff --git a/src/query/runner/aggregate.rs b/src/query/runner/aggregate.rs index e0dee3550..23cd6e7ba 100644 --- a/src/query/runner/aggregate.rs +++ b/src/query/runner/aggregate.rs @@ -2,7 +2,6 @@ use std::marker::PhantomData; use futures_util::TryStreamExt; -use super::ipa::assert_stream_send; use crate::{ error::Error, ff::{Gf2, Gf8Bit, PrimeField, Serializable}, @@ -83,10 +82,9 @@ where let input = { //TODO: Replace `Gf8Bit` with an appropriate type specified by the config `contribution_bits` - let mut v = assert_stream_send(RecordsStream::< - SparseAggregateInputRow, - _, - >::new(input_stream)) + let mut v = RecordsStream::, _>::new( + input_stream, + ) .try_concat() .await?; v.truncate(sz); diff --git a/src/query/runner/ipa.rs b/src/query/runner/ipa.rs index 2b19ead23..ed4a3da43 100644 --- a/src/query/runner/ipa.rs +++ b/src/query/runner/ipa.rs @@ -2,7 +2,7 @@ use std::marker::PhantomData; use futures::{ stream::{iter, repeat}, - Stream, StreamExt, TryStreamExt, + StreamExt, TryStreamExt, }; use crate::{ @@ -89,19 +89,16 @@ where let sz = usize::from(query_size); let input = if config.plaintext_match_keys { - let mut v = assert_stream_send(RecordsStream::< - IPAInputRow, - _, - >::new(input_stream)) - .try_concat() - .await?; + let mut v = + RecordsStream::, _>::new(input_stream) + .try_concat() + .await?; v.truncate(sz); v } else { - assert_stream_send(LengthDelimitedStream::< - EncryptedReport, - _, - >::new(input_stream)) + LengthDelimitedStream::, _>::new( + input_stream, + ) .map_err(Into::::into) .map_ok(|enc_reports| { iter(enc_reports.into_iter().map(|enc_report| { @@ -147,16 +144,6 @@ where } } -/// Helps to convince the compiler that things are `Send`. Like `seq_join::assert_send`, but for -/// streams. -/// -/// -pub fn assert_stream_send<'a, T>( - st: impl Stream + Send + 'a, -) -> impl Stream + Send + 'a { - st -} - /// no dependency on `weak-field` feature because it is enabled in tests by default #[cfg(all(test, unit_test))] mod tests { diff --git a/src/query/runner/mod.rs b/src/query/runner/mod.rs index bcba34275..d9eb28f8f 100644 --- a/src/query/runner/mod.rs +++ b/src/query/runner/mod.rs @@ -1,12 +1,14 @@ mod aggregate; mod ipa; +mod oprf_ipa; + #[cfg(any(test, feature = "cli", feature = "test-fixture"))] mod test_multiply; #[cfg(any(test, feature = "cli", feature = "test-fixture"))] pub(super) use test_multiply::execute_test_multiply; -pub(super) use self::{aggregate::SparseAggregateQuery, ipa::IpaQuery}; +pub(super) use self::{aggregate::SparseAggregateQuery, ipa::IpaQuery, oprf_ipa::OprfIpaQuery}; use crate::{error::Error, query::ProtocolResult}; pub(super) type QueryResult = Result, Error>; diff --git a/src/query/runner/oprf_ipa.rs b/src/query/runner/oprf_ipa.rs new file mode 100644 index 000000000..d2951f0f1 --- /dev/null +++ b/src/query/runner/oprf_ipa.rs @@ -0,0 +1,116 @@ +use std::marker::PhantomData; + +use futures::TryStreamExt; + +use crate::{ + error::Error, + ff::{Field, Gf2, PrimeField, Serializable}, + helpers::{ + query::{IpaQueryConfig, QuerySize}, + BodyStream, RecordsStream, + }, + protocol::{ + basics::ShareKnownValue, + context::{UpgradableContext, UpgradedContext}, + ipa_prf::prf_sharding::{attribution_and_capping_and_aggregation, PrfShardedIpaInputRow}, + BreakdownKey, Timestamp, TriggerValue, + }, + report::{EventType, OprfReport}, + secret_sharing::{ + replicated::{malicious::ExtendableField, semi_honest::AdditiveShare as Replicated}, + SharedValue, + }, +}; + +pub struct OprfIpaQuery { + config: IpaQueryConfig, + phantom_data: PhantomData<(C, F)>, +} + +impl OprfIpaQuery { + pub fn new(config: IpaQueryConfig) -> Self { + Self { + config, + phantom_data: PhantomData, + } + } +} + +impl OprfIpaQuery +where + C: UpgradableContext, + C::UpgradedContext: UpgradedContext>, + C::UpgradedContext: UpgradedContext>, + F: PrimeField + ExtendableField, + Replicated: Serializable + ShareKnownValue, + Replicated: Serializable + ShareKnownValue, +{ + #[tracing::instrument("oprf_ipa_query", skip_all, fields(sz=%query_size))] + pub async fn execute<'a>( + self, + ctx: C, + query_size: QuerySize, + input_stream: BodyStream, + ) -> Result>, Error> { + let Self { + config, + phantom_data: _, + } = self; + tracing::info!("New query: {config:?}"); + let sz = usize::from(query_size); + + let input = if config.plaintext_match_keys { + let mut v = RecordsStream::, _>::new( + input_stream, + ) + .try_concat() + .await?; + v.truncate(sz); + v + } else { + panic!("Encrypted match key handling is not handled for OPRF flow as yet"); + }; + + // TODO: Compute OPRFs and shuffle and add dummies and stuff (Daniel's code will be called here) + let sharded_input = input + .into_iter() + .map(|single_row| { + let is_trigger_bit_share = if single_row.event_type == EventType::Trigger { + Replicated::share_known_value(&ctx, Gf2::ONE) + } else { + Replicated::share_known_value(&ctx, Gf2::ZERO) + }; + PrfShardedIpaInputRow { + prf_of_match_key: single_row.mk_oprf, + is_trigger_bit: is_trigger_bit_share, + breakdown_key: single_row.breakdown_key, + trigger_value: single_row.trigger_value, + timestamp: single_row.timestamp, + } + }) + .collect::>(); + // Until then, we convert the output to something next function is happy about. + + let user_cap: i32 = config.per_user_credit_cap.try_into().unwrap(); + assert!( + user_cap & (user_cap - 1) == 0, + "This code only works for a user cap which is a power of 2" + ); + + attribution_and_capping_and_aggregation::< + C, + BreakdownKey, + TriggerValue, + Timestamp, + F, + _, + Replicated, + >( + ctx, + sharded_input, + user_cap.ilog2().try_into().unwrap(), + config.attribution_window_seconds, + ) + .await + } +} diff --git a/src/report.rs b/src/report.rs index 094a31997..5c8ada0ae 100644 --- a/src/report.rs +++ b/src/report.rs @@ -1,14 +1,15 @@ use std::{ fmt::{Display, Formatter}, marker::PhantomData, - ops::Deref, + mem::size_of, + ops::{Add, Deref}, }; use bytes::{BufMut, Bytes}; -use generic_array::GenericArray; +use generic_array::{ArrayLength, GenericArray}; use hpke::Serializable as _; use rand_core::{CryptoRng, RngCore}; -use typenum::Unsigned; +use typenum::{Unsigned, U1, U8, U9}; use crate::{ ff::{GaloisField, Gf40Bit, Gf8Bit, PrimeField, Serializable}, @@ -47,6 +48,29 @@ pub enum EventType { Source, } +impl Serializable for EventType { + type Size = U1; + + fn serialize(&self, buf: &mut GenericArray) { + let raw: &[u8] = match self { + EventType::Trigger => &[0], + EventType::Source => &[1], + }; + buf.copy_from_slice(raw); + } + + fn deserialize(buf: &GenericArray) -> Self { + let mut buf_to = [0u8; 1]; + buf_to[..buf.len()].copy_from_slice(buf); + + match buf[0] { + 0 => EventType::Trigger, + 1 => EventType::Source, + 2_u8..=u8::MAX => panic!("Unreachable code"), + } + } +} + #[derive(Debug, PartialEq, Eq)] pub struct ParseEventTypeError(u8); @@ -386,6 +410,120 @@ where } } +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct OprfReport +where + TS: GaloisField, + BK: GaloisField, + TV: GaloisField, +{ + pub timestamp: Replicated, + pub mk_oprf: u64, + pub event_type: EventType, + pub breakdown_key: Replicated, + pub trigger_value: Replicated, +} + +impl Serializable for u64 { + type Size = U8; + + fn serialize(&self, buf: &mut GenericArray) { + let raw = &self.to_le_bytes()[..buf.len()]; + buf.copy_from_slice(raw); + } + + fn deserialize(buf: &GenericArray) -> Self { + let mut buf_to = [0u8; 8]; + buf_to[..buf.len()].copy_from_slice(buf); + u64::from_le_bytes(buf_to) + } +} + +impl Serializable for OprfReport +where + Replicated: Serializable, + Replicated: Serializable, + Replicated: Serializable, + as Serializable>::Size: Add, + as Serializable>::Size: + Add<< as Serializable>::Size as Add>::Output>, + as Serializable>::Size: Add< + < as Serializable>::Size as Add< + < as Serializable>::Size as Add>::Output, + >>::Output, + >, + < as Serializable>::Size as Add< + < as Serializable>::Size as Add< + < as Serializable>::Size as Add>::Output, + >>::Output, + >>::Output: ArrayLength, +{ + type Size = < as Serializable>::Size as Add< + < as Serializable>::Size as Add< + < as Serializable>::Size as Add>::Output, + >>::Output, + >>::Output; + + fn serialize(&self, buf: &mut GenericArray) { + let sizeof_u64 = size_of::(); + let sizeof_eventtype = size_of::(); + let ts_sz = as Serializable>::Size::USIZE; + let bk_sz = as Serializable>::Size::USIZE; + let tv_sz = as Serializable>::Size::USIZE; + + self.mk_oprf + .serialize(GenericArray::from_mut_slice(&mut buf[..sizeof_u64])); + + self.timestamp.serialize(GenericArray::from_mut_slice( + &mut buf[sizeof_u64..sizeof_u64 + ts_sz], + )); + + self.breakdown_key.serialize(GenericArray::from_mut_slice( + &mut buf[sizeof_u64 + ts_sz..sizeof_u64 + ts_sz + bk_sz], + )); + + self.trigger_value.serialize(GenericArray::from_mut_slice( + &mut buf[sizeof_u64 + ts_sz + bk_sz..sizeof_u64 + ts_sz + bk_sz + tv_sz], + )); + + self.event_type.serialize(GenericArray::from_mut_slice( + &mut buf[sizeof_u64 + ts_sz + bk_sz + tv_sz + ..sizeof_u64 + ts_sz + bk_sz + tv_sz + sizeof_eventtype], + )); + } + + fn deserialize(buf: &GenericArray) -> Self { + let sizeof_u64 = size_of::(); + let sizeof_eventtype = size_of::(); + + let ts_sz = as Serializable>::Size::USIZE; + let bk_sz = as Serializable>::Size::USIZE; + let tv_sz = as Serializable>::Size::USIZE; + + let mk_oprf = u64::deserialize(GenericArray::from_slice(&buf[..sizeof_u64])); + let timestamp = Replicated::::deserialize(GenericArray::from_slice( + &buf[sizeof_u64..sizeof_u64 + ts_sz], + )); + let breakdown_key = Replicated::::deserialize(GenericArray::from_slice( + &buf[sizeof_u64 + ts_sz..sizeof_u64 + ts_sz + bk_sz], + )); + let trigger_value = Replicated::::deserialize(GenericArray::from_slice( + &buf[sizeof_u64 + ts_sz + bk_sz..sizeof_u64 + ts_sz + bk_sz + tv_sz], + )); + let event_type = EventType::deserialize(GenericArray::from_slice( + &buf[sizeof_u64 + ts_sz + bk_sz + tv_sz + ..sizeof_u64 + ts_sz + bk_sz + tv_sz + sizeof_eventtype], + )); + Self { + timestamp, + mk_oprf, + event_type, + breakdown_key, + trigger_value, + } + } +} + #[cfg(all(test, unit_test))] mod test { use rand::{distributions::Alphanumeric, rngs::StdRng, Rng}; diff --git a/src/secret_sharing/decomposed.rs b/src/secret_sharing/decomposed.rs index 6a3f7d28d..1fc87d2c6 100644 --- a/src/secret_sharing/decomposed.rs +++ b/src/secret_sharing/decomposed.rs @@ -2,7 +2,11 @@ use std::{fmt::Debug, ops::Deref}; use crate::{ error::Error, - ff::PrimeField, + ff::{Field, Gf2, PrimeField}, + protocol::{ + boolean::saturating_sum::one_bit_subtractor, context::Context, step::BitOpStep, + BasicProtocols, RecordId, + }, secret_sharing::{Linear as LinearSecretSharing, LinearRefOps}, }; @@ -79,6 +83,50 @@ impl BitDecomposed { acc + (b * F::truncate_from(1_u128 << i)) }) } + + /// Subtraction of two bit-wise secret shares, `self - rhs`, in two's complement. + /// Subtracting a value larger than `self` value will cause the result to overflow. + /// Be especially careful as the overflow is not checked and could lead to a privacy + /// violation (e.g., invalid capping). + /// + /// # Errors + /// If one of the multiplications errors + /// # Panics + /// If something try to subtract a bit decomposed value larger than this `BitDecomposed` can accommodate + pub async fn sub( + &self, + ctx: C, + record_id: RecordId, + rhs: &BitDecomposed, + ) -> Result, Error> + where + C: Context, + S: LinearSecretSharing + BasicProtocols, + for<'a> &'a S: LinearRefOps<'a, S, Gf2>, + { + assert!(self.len() >= rhs.len()); + + let mut output = vec![]; + let mut carry_in = S::share_known_value(&ctx, Gf2::ONE); + let zero = S::ZERO; + for i in 0..self.len() { + let c = ctx.narrow(&BitOpStep::from(i)); + let compute_carry_out = i < self.len() - 1; + let difference_bit = one_bit_subtractor( + c, + record_id, + &self[i], + rhs.get(i).unwrap_or(&zero), + &mut carry_in, + compute_carry_out, + ) + .await?; + + output.push(difference_bit); + } + + Ok(BitDecomposed::new(output)) + } } impl TryFrom> for BitDecomposed { @@ -106,3 +154,54 @@ impl IntoIterator for BitDecomposed { self.bits.into_iter() } } + +#[cfg(all(test, unit_test))] +mod tests { + use crate::{ + ff::Gf2, + protocol::{context::Context, RecordId}, + secret_sharing::BitDecomposed, + test_fixture::{get_bits, Reconstruct, Runner, TestWorld}, + }; + + #[tokio::test] + pub async fn subtraction() { + // `lhs >= rhs` + assert_eq!(0, subtract(1, 2, 1, 2).await); + assert_eq!(1, subtract(2, 2, 1, 2).await); + assert_eq!(1, subtract(3, 2, 2, 2).await); + assert_eq!(2, subtract(3, 2, 1, 2).await); + assert_eq!(3, subtract(3, 2, 0, 2).await); + assert_eq!(2, subtract(3, 5, 1, 5).await); + assert_eq!(6, subtract(7, 5, 1, 2).await); + assert_eq!(6, subtract(7, 5, 1, 5).await); + + // `lhs < rhs` so the result is an unsigned integer in two's complement + // representation in whatever many bits of the `lhs` + assert_eq!(3, subtract(0, 2, 1, 2).await); + assert_eq!(31, subtract(1, 5, 2, 2).await); + assert_eq!(30, subtract(1, 5, 3, 2).await); + assert_eq!(26, subtract(1, 5, 7, 5).await); + } + + async fn subtract(a: u32, num_a_bits: u32, b: u32, num_b_bits: u32) -> u128 { + let world = TestWorld::default(); + + let a_bits = get_bits::(a, num_a_bits); + let b_bits = get_bits::(b, num_b_bits); + + let foo = world + .semi_honest( + (a_bits, b_bits), + |ctx, (a_bits, b_bits): (BitDecomposed<_>, BitDecomposed<_>)| async move { + a_bits + .sub(ctx.set_total_records(1), RecordId::from(0), &b_bits) + .await + .unwrap() + }, + ) + .await; + + foo.reconstruct() + } +} diff --git a/src/secret_sharing/mod.rs b/src/secret_sharing/mod.rs index f366c870c..441fe1f21 100644 --- a/src/secret_sharing/mod.rs +++ b/src/secret_sharing/mod.rs @@ -23,22 +23,25 @@ pub use scheme::{Bitwise, Linear, LinearRefOps, SecretSharing}; use crate::ff::{AddSub, AddSubAssign, Serializable}; +/// Operations supported for weak shared values. +pub trait Additive: + AddSub + AddSubAssign + Neg +{ +} + +impl Additive for T where + T: AddSub + AddSubAssign + Neg +{ +} + /// Operations supported for shared values. pub trait Arithmetic: - AddSub - + AddSubAssign - + Mul - + MulAssign - + Neg + Additive + Mul + MulAssign { } impl Arithmetic for T where - T: AddSub - + AddSubAssign - + Mul - + MulAssign - + Neg + T: Additive + Mul + MulAssign { } @@ -48,6 +51,18 @@ pub trait Block: Sized + Copy + Debug { type Size: ArrayLength; } +///allows basic secret sharing operations +pub trait WeakSharedValue: + Clone + Copy + PartialEq + Debug + Send + Sync + Sized + Additive + Serializable + 'static +{ + type Storage: Block; + + const BITS: u32; + + const ZERO: Self; +} + +///allows advanced secret sharing operations, requires multiplication pub trait SharedValue: Clone + Copy + PartialEq + Debug + Send + Sync + Sized + Arithmetic + Serializable + 'static { @@ -58,10 +73,22 @@ pub trait SharedValue: const ZERO: Self; } +///any `SharedValue` is also a `WeakSharedValue` +impl WeakSharedValue for T +where + T: SharedValue, +{ + type Storage = T::Storage; + + const BITS: u32 = T::BITS; + + const ZERO: Self = T::ZERO; +} + #[cfg(any(test, feature = "test-fixture", feature = "cli"))] impl IntoShares> for V where - V: SharedValue, + V: WeakSharedValue, Standard: Distribution, { fn share_with(self, rng: &mut R) -> [AdditiveShare; 3] { diff --git a/src/secret_sharing/replicated/mod.rs b/src/secret_sharing/replicated/mod.rs index dcf51494e..80c8167b0 100644 --- a/src/secret_sharing/replicated/mod.rs +++ b/src/secret_sharing/replicated/mod.rs @@ -1,9 +1,9 @@ pub mod malicious; pub mod semi_honest; -use super::{SecretSharing, SharedValue}; +use super::{SecretSharing, SharedValue, WeakSharedValue}; -pub trait ReplicatedSecretSharing: SecretSharing { +pub trait ReplicatedSecretSharing: SecretSharing { fn new(a: V, b: V) -> Self; fn left(&self) -> V; fn right(&self) -> V; diff --git a/src/secret_sharing/replicated/semi_honest/additive_share.rs b/src/secret_sharing/replicated/semi_honest/additive_share.rs index 10b8b2b39..0ae455ea9 100644 --- a/src/secret_sharing/replicated/semi_honest/additive_share.rs +++ b/src/secret_sharing/replicated/semi_honest/additive_share.rs @@ -10,32 +10,32 @@ use crate::{ ff::Serializable, secret_sharing::{ replicated::ReplicatedSecretSharing, Linear as LinearSecretSharing, SecretSharing, - SharedValue, + SharedValue, WeakSharedValue, }, }; #[derive(Clone, PartialEq, Eq)] -pub struct AdditiveShare(V, V); +pub struct AdditiveShare(V, V); -impl SecretSharing for AdditiveShare { +impl SecretSharing for AdditiveShare { const ZERO: Self = AdditiveShare::ZERO; } impl LinearSecretSharing for AdditiveShare {} -impl Debug for AdditiveShare { +impl Debug for AdditiveShare { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { write!(f, "({:?}, {:?})", self.0, self.1) } } -impl Default for AdditiveShare { +impl Default for AdditiveShare { fn default() -> Self { AdditiveShare::new(V::ZERO, V::ZERO) } } -impl AdditiveShare { +impl AdditiveShare { /// Replicated secret share where both left and right values are `F::ZERO` pub const ZERO: Self = Self(V::ZERO, V::ZERO); @@ -44,7 +44,7 @@ impl AdditiveShare { } } -impl ReplicatedSecretSharing for AdditiveShare { +impl ReplicatedSecretSharing for AdditiveShare { fn new(a: V, b: V) -> Self { Self(a, b) } @@ -58,7 +58,7 @@ impl ReplicatedSecretSharing for AdditiveShare { } } -impl AdditiveShare +impl AdditiveShare where Self: Serializable, { @@ -73,7 +73,7 @@ where } } -impl<'a, 'b, V: SharedValue> Add<&'b AdditiveShare> for &'a AdditiveShare { +impl<'a, 'b, V: WeakSharedValue> Add<&'b AdditiveShare> for &'a AdditiveShare { type Output = AdditiveShare; fn add(self, rhs: &'b AdditiveShare) -> Self::Output { @@ -81,7 +81,7 @@ impl<'a, 'b, V: SharedValue> Add<&'b AdditiveShare> for &'a AdditiveShare } } -impl Add for AdditiveShare { +impl Add for AdditiveShare { type Output = Self; fn add(self, rhs: Self) -> Self::Output { @@ -89,7 +89,7 @@ impl Add for AdditiveShare { } } -impl Add> for &AdditiveShare { +impl Add> for &AdditiveShare { type Output = AdditiveShare; fn add(self, rhs: AdditiveShare) -> Self::Output { @@ -97,7 +97,7 @@ impl Add> for &AdditiveShare { } } -impl Add<&AdditiveShare> for AdditiveShare { +impl Add<&AdditiveShare> for AdditiveShare { type Output = Self; fn add(self, rhs: &Self) -> Self::Output { @@ -105,20 +105,20 @@ impl Add<&AdditiveShare> for AdditiveShare { } } -impl AddAssign<&Self> for AdditiveShare { +impl AddAssign<&Self> for AdditiveShare { fn add_assign(&mut self, rhs: &Self) { self.0 += rhs.0; self.1 += rhs.1; } } -impl AddAssign for AdditiveShare { +impl AddAssign for AdditiveShare { fn add_assign(&mut self, rhs: Self) { AddAssign::add_assign(self, &rhs); } } -impl Neg for &AdditiveShare { +impl Neg for &AdditiveShare { type Output = AdditiveShare; fn neg(self) -> Self::Output { @@ -126,7 +126,7 @@ impl Neg for &AdditiveShare { } } -impl Neg for AdditiveShare { +impl Neg for AdditiveShare { type Output = Self; fn neg(self) -> Self::Output { @@ -134,7 +134,7 @@ impl Neg for AdditiveShare { } } -impl Sub for &AdditiveShare { +impl Sub for &AdditiveShare { type Output = AdditiveShare; fn sub(self, rhs: Self) -> Self::Output { @@ -142,7 +142,7 @@ impl Sub for &AdditiveShare { } } -impl Sub for AdditiveShare { +impl Sub for AdditiveShare { type Output = Self; fn sub(self, rhs: Self) -> Self::Output { @@ -150,7 +150,7 @@ impl Sub for AdditiveShare { } } -impl Sub<&Self> for AdditiveShare { +impl Sub<&Self> for AdditiveShare { type Output = Self; fn sub(self, rhs: &Self) -> Self::Output { @@ -158,7 +158,7 @@ impl Sub<&Self> for AdditiveShare { } } -impl Sub> for &AdditiveShare { +impl Sub> for &AdditiveShare { type Output = AdditiveShare; fn sub(self, rhs: AdditiveShare) -> Self::Output { @@ -166,14 +166,14 @@ impl Sub> for &AdditiveShare { } } -impl SubAssign<&Self> for AdditiveShare { +impl SubAssign<&Self> for AdditiveShare { fn sub_assign(&mut self, rhs: &Self) { self.0 -= rhs.0; self.1 -= rhs.1; } } -impl SubAssign for AdditiveShare { +impl SubAssign for AdditiveShare { fn sub_assign(&mut self, rhs: Self) { SubAssign::sub_assign(self, &rhs); } diff --git a/src/secret_sharing/scheme.rs b/src/secret_sharing/scheme.rs index cd6556211..0d2131eeb 100644 --- a/src/secret_sharing/scheme.rs +++ b/src/secret_sharing/scheme.rs @@ -3,11 +3,11 @@ use std::{ ops::{Mul, Neg}, }; -use super::SharedValue; +use super::{SharedValue, WeakSharedValue}; use crate::ff::{AddSub, AddSubAssign, GaloisField}; /// Secret sharing scheme i.e. Replicated secret sharing -pub trait SecretSharing: Clone + Debug + Sized + Send + Sync { +pub trait SecretSharing: Clone + Debug + Sized + Send + Sync { const ZERO: Self; } diff --git a/src/test_fixture/input/sharing.rs b/src/test_fixture/input/sharing.rs index f21dc4920..e5e306e7d 100644 --- a/src/test_fixture/input/sharing.rs +++ b/src/test_fixture/input/sharing.rs @@ -12,7 +12,7 @@ use crate::{ BreakdownKey, MatchKey, }, rand::Rng, - report::{EventType, Report}, + report::{EventType, OprfReport, Report}, secret_sharing::{replicated::semi_honest::AdditiveShare as Replicated, IntoShares}, test_fixture::{ input::{GenericReportShare, GenericReportTestInput}, @@ -354,3 +354,38 @@ where } } } + +impl IntoShares> for TestRawDataRecord +where + TS: GaloisField + IntoShares>, + BK: GaloisField + IntoShares>, + TV: GaloisField + IntoShares>, +{ + fn share_with(self, rng: &mut R) -> [OprfReport; 3] { + let event_type = if self.is_trigger_report { + EventType::Trigger + } else { + EventType::Source + }; + let timestamp: [Replicated; 3] = + TS::try_from(self.timestamp.into()).unwrap().share_with(rng); + let breakdown_key = BK::try_from(self.breakdown_key.into()) + .unwrap() + .share_with(rng); + let trigger_value = TV::try_from(self.trigger_value.into()) + .unwrap() + .share_with(rng); + + zip(zip(timestamp, breakdown_key), trigger_value) + .map(|((ts_share, bk_share), tv_share)| OprfReport { + timestamp: ts_share, + mk_oprf: self.user_id, + event_type, + breakdown_key: bk_share, + trigger_value: tv_share, + }) + .collect::>() + .try_into() + .unwrap() + } +} diff --git a/src/test_fixture/ipa.rs b/src/test_fixture/ipa.rs index 37e31b535..7668881c8 100644 --- a/src/test_fixture/ipa.rs +++ b/src/test_fixture/ipa.rs @@ -5,9 +5,13 @@ use crate::{ ff::{PrimeField, Serializable}, helpers::query::IpaQueryConfig, ipa_test_input, - protocol::{ipa::ipa, BreakdownKey, MatchKey}, + protocol::{ipa::ipa, BreakdownKey, MatchKey, Timestamp, TriggerValue}, + report::OprfReport, secret_sharing::{ - replicated::{malicious, malicious::ExtendableField, semi_honest}, + replicated::{ + malicious, malicious::ExtendableField, semi_honest, + semi_honest::AdditiveShare as Replicated, + }, IntoShares, }, test_fixture::{input::GenericReportTestInput, Reconstruct}, @@ -20,6 +24,11 @@ pub enum IpaSecurityModel { Malicious, } +pub enum IpaQueryStyle { + SortInMpc, + Oprf, +} + #[derive(Debug, Clone)] pub struct TestRawDataRecord { pub timestamp: u64, @@ -44,6 +53,7 @@ pub fn ipa_in_the_clear( per_user_cap: u32, attribution_window: Option, max_breakdown: u32, + order: &CappingOrder, ) -> Vec { // build a view that is convenient for attribution. match key -> events sorted by timestamp in reverse // that is more memory intensive, but should be faster to compute. We can always opt-out and @@ -77,12 +87,18 @@ pub fn ipa_in_the_clear( &mut breakdowns, per_user_cap, attribution_window, + order, ); } breakdowns } +pub enum CappingOrder { + CapOldestFirst, + CapMostRecentFirst, +} + /// Assumes records all belong to the same user, and are in reverse chronological order /// Will give incorrect results if this is not true #[allow(clippy::missing_panics_doc)] @@ -91,6 +107,7 @@ fn update_expected_output_for_user<'a, I: IntoIterator, + order: &CappingOrder, ) { let within_window = |value: u64| -> bool { if let Some(window) = attribution_window_seconds { @@ -102,17 +119,13 @@ fn update_expected_output_for_user<'a, I: IntoIterator= per_user_cap { - break; - } - if record.is_trigger_report { pending_trigger_reports.push(record); } else if !pending_trigger_reports.is_empty() { - for trigger_report in &pending_trigger_reports { + for trigger_report in pending_trigger_reports { let time_delta_to_source_report = trigger_report.timestamp - record.timestamp; // only count trigger reports that are within the attribution window @@ -121,15 +134,36 @@ fn update_expected_output_for_user<'a, I: IntoIterator { + update_breakdowns(attributed_triggers, expected_results, per_user_cap); } + CappingOrder::CapMostRecentFirst => update_breakdowns( + attributed_triggers.into_iter().rev(), + expected_results, + per_user_cap, + ), + } +} + +fn update_breakdowns<'a, I>(attributed_triggers: I, expected_results: &mut [u32], per_user_cap: u32) +where + I: IntoIterator, +{ + let mut total_contribution = 0; + for (trigger_report, source_report) in attributed_triggers { + let delta_to_per_user_cap = per_user_cap - total_contribution; + let capped_contribution = + std::cmp::min(delta_to_per_user_cap, trigger_report.trigger_value); + let bk: usize = source_report.breakdown_key.try_into().unwrap(); + expected_results[bk] += capped_contribution; + total_contribution += capped_contribution; } } @@ -191,3 +225,91 @@ pub async fn test_ipa( .collect::>(); assert_eq!(result, expected_results); } + +/// # Panics +/// If any of the IPA protocol modules panic +#[cfg(feature = "in-memory-infra")] +pub async fn test_oprf_ipa( + world: &super::TestWorld, + mut records: Vec, + expected_results: &[u32], + config: IpaQueryConfig, +) where + F: PrimeField + ExtendableField + IntoShares>, + rand::distributions::Standard: rand::distributions::Distribution, + semi_honest::AdditiveShare: Serializable, +{ + use crate::{ + ff::{Field, Gf2}, + protocol::{ + basics::ShareKnownValue, + ipa_prf::prf_sharding::{ + attribution_and_capping_and_aggregation, PrfShardedIpaInputRow, + }, + }, + report::EventType, + secret_sharing::SharedValue, + test_fixture::Runner, + }; + + let user_cap: i32 = config.per_user_credit_cap.try_into().unwrap(); + assert!( + user_cap & (user_cap - 1) == 0, + "This code only works for a user cap which is a power of 2" + ); + + //TODO(richaj) This manual sorting will be removed once we have the PRF sharding in place + records.sort_by(|a, b| b.user_id.cmp(&a.user_id)); + + let result: Vec = world + .semi_honest( + records.into_iter(), + |ctx, input_rows: Vec>| async move { + let sharded_input = input_rows + .into_iter() + .map(|single_row| { + let is_trigger_bit_share = if single_row.event_type == EventType::Trigger { + Replicated::share_known_value(&ctx, Gf2::ONE) + } else { + Replicated::share_known_value(&ctx, Gf2::ZERO) + }; + PrfShardedIpaInputRow { + prf_of_match_key: single_row.mk_oprf, + is_trigger_bit: is_trigger_bit_share, + breakdown_key: single_row.breakdown_key, + trigger_value: single_row.trigger_value, + timestamp: single_row.timestamp, + } + }) + .collect::>(); + + attribution_and_capping_and_aggregation::< + _, + BreakdownKey, + TriggerValue, + Timestamp, + F, + _, + Replicated, + >( + ctx, + sharded_input, + user_cap.ilog2().try_into().unwrap(), + config.attribution_window_seconds, + ) + .await + .unwrap() + }, + ) + .await + .reconstruct(); + + let mut result = result + .into_iter() + .map(|v| u32::try_from(v.as_u128()).unwrap()) + .collect::>(); + + //TODO(richaj): To be removed once the function supports non power of 2 breakdowns + let _ = result.split_off(expected_results.len()); + assert_eq!(result, expected_results); +}