1use crate::{
4 FancyArithmetic, FancyBinary,
5 fancy::{Fancy, FancyInput, FancyReveal, HasModulus},
6};
7use std::collections::{HashMap, HashSet};
8use swanky_channel::Channel;
9
10pub struct Informer<F: Fancy> {
13 pub underlying: F,
15 stats: InformerStats,
16}
17
18#[derive(Clone, Debug)]
20pub struct InformerStats {
21 garbler_input_moduli: Vec<u16>,
22 evaluator_input_moduli: Vec<u16>,
23 constants: HashSet<(u16, u16)>,
24 outputs: Vec<u16>,
25 nadds: usize,
26 nsubs: usize,
27 ncmuls: usize,
28 nmuls: usize,
29 nprojs: usize,
30 nciphertexts: usize,
31 moduli: HashMap<u16, usize>,
32}
33
34impl InformerStats {
35 pub fn num_garbler_inputs(&self) -> usize {
37 self.garbler_input_moduli.len()
38 }
39
40 pub fn garbler_input_moduli(&self) -> Vec<u16> {
42 self.garbler_input_moduli.clone()
43 }
44
45 pub fn num_evaluator_inputs(&self) -> usize {
47 self.evaluator_input_moduli.len()
48 }
49
50 pub fn evaluator_input_moduli(&self) -> Vec<u16> {
52 self.evaluator_input_moduli.clone()
53 }
54
55 pub fn num_consts(&self) -> usize {
57 self.constants.len()
58 }
59
60 pub fn num_outputs(&self) -> usize {
62 self.outputs.len()
63 }
64
65 pub fn num_output_ciphertexts(&self) -> usize {
67 self.outputs.iter().map(|&m| m as usize).sum()
68 }
69
70 pub fn num_adds(&self) -> usize {
72 self.nadds
73 }
74
75 pub fn num_subs(&self) -> usize {
77 self.nsubs
78 }
79
80 pub fn num_cmuls(&self) -> usize {
82 self.ncmuls
83 }
84
85 pub fn num_muls(&self) -> usize {
87 self.nmuls
88 }
89
90 pub fn num_projs(&self) -> usize {
92 self.nprojs
93 }
94
95 pub fn num_ciphertexts(&self) -> usize {
97 self.nciphertexts
98 }
99}
100
101impl std::fmt::Display for InformerStats {
102 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
121 let mut total = 0.0;
122 writeln!(f, "computation info:")?;
123 let comm = self.num_garbler_inputs() as f64 * 128.0 / 1000.0;
124
125 writeln!(
126 f,
127 " garbler inputs: {:16} // communication: {:.2} Kb",
128 self.num_garbler_inputs(),
129 comm
130 )?;
131 total += comm;
132 let comm = self.evaluator_input_moduli.iter().fold(0.0, |acc, q| {
136 acc + (*q as f64).log2().ceil() * 384.0 / 1000.0
137 });
138
139 writeln!(
140 f,
141 " evaluator inputs: {:16} // communication: {:.2} Kb",
142 self.num_evaluator_inputs(),
143 comm
144 )?;
145 total += comm;
146 let comm = self.num_output_ciphertexts() as f64 * 128.0 / 1000.0;
147
148 writeln!(f, " outputs: {:16}", self.num_outputs())?;
149 writeln!(
150 f,
151 " output ciphertexts: {:16} // communication: {:.2} Kb",
152 self.num_output_ciphertexts(),
153 comm
154 )?;
155 total += comm;
156 let comm = self.num_consts() as f64 * 128.0 / 1000.0;
157
158 writeln!(
159 f,
160 " constants: {:16} // communication: {:.2} Kb",
161 self.num_consts(),
162 comm
163 )?;
164 total += comm;
165
166 writeln!(f, " additions: {:16}", self.num_adds())?;
167 writeln!(f, " subtractions: {:16}", self.num_subs())?;
168 writeln!(f, " cmuls: {:16}", self.num_cmuls())?;
169 writeln!(f, " projections: {:16}", self.num_projs())?;
170 writeln!(f, " multiplications: {:16}", self.num_muls())?;
171 let cs = self.num_ciphertexts();
172 let kb = cs as f64 * 128.0 / 1000.0;
173 let mb = kb / 1000.0;
174 writeln!(
175 f,
176 " ciphertexts: {:16} // communication: {:.2} Mb ({:.2} Kb)",
177 cs, mb, kb
178 )?;
179 total += kb;
180
181 let mb = total / 1000.0;
182 writeln!(f, " total communication: {:11.2} Mb", mb)?;
183 writeln!(f, " wire moduli: {:#?}", self.moduli)?;
184 Ok(())
185 }
186}
187
188impl<F: Fancy> Informer<F> {
189 pub fn new(underlying: F) -> Informer<F> {
191 Informer {
192 underlying,
193 stats: InformerStats {
194 garbler_input_moduli: Vec::new(),
195 evaluator_input_moduli: Vec::new(),
196 constants: HashSet::new(),
197 outputs: Vec::new(),
198 nadds: 0,
199 nsubs: 0,
200 ncmuls: 0,
201 nmuls: 0,
202 nprojs: 0,
203 nciphertexts: 0,
204 moduli: HashMap::new(),
205 },
206 }
207 }
208
209 pub fn stats(&self) -> InformerStats {
211 self.stats.clone()
212 }
213
214 fn update_moduli(&mut self, q: u16) {
215 let entry = self.stats.moduli.entry(q).or_insert(0);
216 *entry += 1;
217 }
218}
219
220impl<F: Fancy + FancyInput<Item = <F as Fancy>::Item>> FancyInput for Informer<F> {
221 type Item = <F as Fancy>::Item;
222
223 fn receive_many(
224 &mut self,
225 moduli: &[u16],
226 channel: &mut Channel,
227 ) -> swanky_error::Result<Vec<Self::Item>> {
228 self.stats
229 .garbler_input_moduli
230 .extend(moduli.iter().cloned());
231 self.underlying.receive_many(moduli, channel)
232 }
233
234 fn encode_many(
235 &mut self,
236 values: &[u16],
237 moduli: &[u16],
238 channel: &mut Channel,
239 ) -> swanky_error::Result<Vec<Self::Item>> {
240 self.stats
241 .garbler_input_moduli
242 .extend(moduli.iter().cloned());
243 self.underlying.encode_many(values, moduli, channel)
244 }
245}
246
247impl<F: FancyBinary> FancyBinary for Informer<F> {
248 fn xor(&mut self, x: &Self::Item, y: &Self::Item) -> Self::Item {
249 let result = self.underlying.xor(x, y);
250 self.stats.nadds += 1;
251 self.update_moduli(x.modulus());
252 result
253 }
254
255 fn and(
256 &mut self,
257 x: &Self::Item,
258 y: &Self::Item,
259 channel: &mut Channel,
260 ) -> swanky_error::Result<Self::Item> {
261 let result = self.underlying.and(x, y, channel)?;
262 self.stats.nmuls += 1;
263 self.stats.nciphertexts += 2;
264 self.update_moduli(x.modulus());
265 Ok(result)
266 }
267
268 fn negate(&mut self, x: &Self::Item) -> Self::Item {
269 let result = self.underlying.negate(x);
270
271 self.stats.nadds += 1;
273 self.update_moduli(x.modulus());
274 result
275 }
276}
277
278impl<F: FancyArithmetic> FancyArithmetic for Informer<F> {
279 fn add(&mut self, x: &Self::Item, y: &Self::Item) -> Self::Item {
284 let result = self.underlying.add(x, y);
285 self.stats.nadds += 1;
286 self.update_moduli(x.modulus());
287 result
288 }
289
290 fn sub(&mut self, x: &Self::Item, y: &Self::Item) -> Self::Item {
291 let result = self.underlying.sub(x, y);
292 self.stats.nsubs += 1;
293 self.update_moduli(x.modulus());
294 result
295 }
296
297 fn cmul(&mut self, x: &Self::Item, y: u16) -> Self::Item {
298 let result = self.underlying.cmul(x, y);
299 self.stats.ncmuls += 1;
300 self.update_moduli(x.modulus());
301 result
302 }
303
304 fn mul(
305 &mut self,
306 x: &Self::Item,
307 y: &Self::Item,
308 channel: &mut Channel,
309 ) -> swanky_error::Result<Self::Item> {
310 if x.modulus() < y.modulus() {
311 return self.mul(y, x, channel);
312 }
313 let result = self.underlying.mul(x, y, channel)?;
314 self.stats.nmuls += 1;
315 self.stats.nciphertexts += x.modulus() as usize + y.modulus() as usize - 2;
316 if x.modulus() != y.modulus() {
317 self.stats.nciphertexts += 1;
319 }
320 self.update_moduli(x.modulus());
321 Ok(result)
322 }
323
324 fn proj(
325 &mut self,
326 x: &Self::Item,
327 q: u16,
328 tt: Option<Vec<u16>>,
329 channel: &mut Channel,
330 ) -> swanky_error::Result<Self::Item> {
331 let result = self.underlying.proj(x, q, tt, channel)?;
332 self.stats.nprojs += 1;
333 self.stats.nciphertexts += x.modulus() as usize - 1;
334 self.update_moduli(q);
335 Ok(result)
336 }
337}
338
339impl<F: Fancy> Fancy for Informer<F> {
340 type Item = F::Item;
341
342 fn constant(
343 &mut self,
344 val: u16,
345 q: u16,
346 channel: &mut Channel,
347 ) -> swanky_error::Result<Self::Item> {
348 self.stats.constants.insert((val, q));
349 self.update_moduli(q);
350 self.underlying.constant(val, q, channel)
351 }
352
353 fn output(
354 &mut self,
355 x: &Self::Item,
356 channel: &mut Channel,
357 ) -> swanky_error::Result<Option<u16>> {
358 let result = self.underlying.output(x, channel)?;
359 self.stats.outputs.push(x.modulus());
360 Ok(result)
361 }
362}
363
364impl<F: Fancy + FancyReveal> FancyReveal for Informer<F> {
365 fn reveal(&mut self, x: &Self::Item, channel: &mut Channel) -> swanky_error::Result<u16> {
366 self.underlying.reveal(x, channel)
367 }
368}