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