Skip to content

Commit 96e76cc

Browse files
committed
test(ferret): per-phase profiler (ignored)
Drives the real phase functions at production LPN params and reports per-phase timings; compares Uniform vs Regular. Run with `cargo test -p mpz-ot-core --release --features rayon ferret::profile -- --ignored --nocapture`.
1 parent a0c7e1f commit 96e76cc

2 files changed

Lines changed: 141 additions & 0 deletions

File tree

crates/ot-core/src/ferret.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
mod config;
44
pub(crate) mod cuckoo;
55
pub(crate) mod mpcot;
6+
#[cfg(test)]
7+
mod profile;
68
mod receiver;
79
mod sender;
810
pub(crate) mod spcot;
Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
//! Temporary per-phase profiling harness for the Ferret extension.
2+
//!
3+
//! Run with:
4+
//! cargo test -p mpz-ot-core --release --features rayon \
5+
//! ferret::profile -- --nocapture --ignored
6+
//!
7+
//! Drives the *real* phase functions (cuckoo bucket construction, SPCOT GGM
8+
//! generation, MPCOT combine, consistency check, LPN encode) at production LPN
9+
//! parameters and reports the wall-clock spent in each, so we can attribute
10+
//! cost without protocol/network/serialization overhead.
11+
12+
use std::time::Instant;
13+
14+
use rand::{RngExt, SeedableRng, rngs::StdRng};
15+
16+
use mpz_core::{
17+
Block,
18+
bitvec::BitVec,
19+
lpn::{LpnEncoder, LpnParameters, LpnType, sample_error_indices},
20+
};
21+
22+
use crate::ferret::{
23+
config::{CSP, REGULAR_PARAMS, UNIFORM_PARAMS},
24+
mpcot::{MPCOTReceiver, MPCOTSender},
25+
spcot::SPCOTSender,
26+
};
27+
28+
fn ms(d: std::time::Duration) -> f64 {
29+
d.as_secs_f64() * 1e3
30+
}
31+
32+
#[test]
33+
#[ignore = "profiling harness, run explicitly with --ignored --nocapture"]
34+
fn profile_ferret_phases() {
35+
let param_indices = [0usize, 2, 4];
36+
37+
for (lpn_type, params) in [
38+
(LpnType::Uniform, UNIFORM_PARAMS),
39+
(LpnType::Regular, REGULAR_PARAMS),
40+
] {
41+
println!("\n=== LpnType::{lpn_type:?} ===");
42+
println!(
43+
"{:>9} {:>9} {:>11} | {:>10} {:>10} {:>8} {:>8} {:>8} {:>8} | {:>10}",
44+
"n",
45+
"k",
46+
"ggm_leaves",
47+
"cuckoo_snd",
48+
"cuckoo_rcv",
49+
"spcot",
50+
"combine",
51+
"check",
52+
"lpn_enc",
53+
"SIDE_TOTAL",
54+
);
55+
56+
for &pi in &param_indices {
57+
profile_one(lpn_type, params[pi]);
58+
}
59+
}
60+
println!("\n(all times in ms; rayon = {})", cfg!(feature = "rayon"));
61+
}
62+
63+
fn profile_one(lpn_type: LpnType, params: LpnParameters) {
64+
let LpnParameters { n, k, t } = params;
65+
{
66+
let mut rng = StdRng::seed_from_u64(0);
67+
let delta: Block = rng.random();
68+
let cuckoo_seed: Block = rng.random();
69+
70+
// ---- sender cuckoo bucket construction ----
71+
let t0 = Instant::now();
72+
let (mpcot_send, log2_lengths) = MPCOTSender::new(cuckoo_seed, lpn_type)
73+
.start_extend(t, n)
74+
.unwrap();
75+
let t_cuckoo_send = t0.elapsed();
76+
77+
// ---- receiver cuckoo (CuckooHash insert + Buckets) ----
78+
let idxs = sample_error_indices(&mut rng, lpn_type, n, t);
79+
let t0 = Instant::now();
80+
let _ = MPCOTReceiver::new(cuckoo_seed, lpn_type)
81+
.start_extend(&idxs, n)
82+
.unwrap();
83+
let t_cuckoo_recv = t0.elapsed();
84+
85+
// SPCOT inputs sized exactly as the protocol would.
86+
let sum_log2: usize = log2_lengths.iter().sum();
87+
let keys: Vec<Block> = (0..sum_log2).map(|_| rng.random()).collect();
88+
let masks: BitVec = (0..sum_log2).map(|_| rng.random::<bool>()).collect();
89+
let ggm_leaves: usize = log2_lengths.iter().map(|l| 1usize << l).sum();
90+
91+
// ---- SPCOT sender extend (GGM gen + fixed-key AES) ----
92+
let mut spcot = SPCOTSender::new(delta);
93+
let t0 = Instant::now();
94+
let (vs, _ms_out, _sums) = spcot
95+
.extend(&mut rng, &log2_lengths, &keys, &masks)
96+
.unwrap();
97+
let t_spcot = t0.elapsed();
98+
99+
// ---- MPCOT combine (random-access XOR gather) ----
100+
let t0 = Instant::now();
101+
let res = mpcot_send.extend(vs).unwrap();
102+
let t_combine = t0.elapsed();
103+
debug_assert_eq!(res.len(), n);
104+
105+
// ---- consistency check (chi gen + O(leaves) inner product) ----
106+
let check_keys: Vec<Block> = (0..CSP).map(|_| rng.random()).collect();
107+
let check_masks: BitVec = (0..CSP).map(|_| rng.random::<bool>()).collect();
108+
let t0 = Instant::now();
109+
let _hashed = spcot.check(&check_keys, &check_masks).unwrap();
110+
let t_check = t0.elapsed();
111+
112+
// ---- LPN encode y = A*v + s ----
113+
let x: Vec<Block> = (0..k).map(|_| rng.random()).collect();
114+
let mut y = res;
115+
let enc = LpnEncoder::<10>::new(k as u32);
116+
let lpn_seed: Block = rng.random();
117+
let t0 = Instant::now();
118+
enc.compute(lpn_seed, &mut y, &x);
119+
let t_lpn = t0.elapsed();
120+
std::hint::black_box(&y);
121+
122+
// One party (sender) pays: cuckoo + spcot + combine + check + lpn.
123+
let side_total = t_cuckoo_send + t_spcot + t_combine + t_check + t_lpn;
124+
125+
println!(
126+
"{:>9} {:>9} {:>11} | {:>10.1} {:>10.1} {:>8.1} {:>8.1} {:>8.1} {:>8.1} | {:>10.1}",
127+
n,
128+
k,
129+
ggm_leaves,
130+
ms(t_cuckoo_send),
131+
ms(t_cuckoo_recv),
132+
ms(t_spcot),
133+
ms(t_combine),
134+
ms(t_check),
135+
ms(t_lpn),
136+
ms(side_total),
137+
);
138+
}
139+
}

0 commit comments

Comments
 (0)