1use crate::{
4 FancyArithmetic, FancyBinary, FancyProj,
5 fancy::{Fancy, 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 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_inputs(&self) -> usize {
36 self.input_moduli.len()
37 }
38
39 pub fn input_moduli(&self) -> Vec<u16> {
41 self.input_moduli.clone()
42 }
43
44 pub fn num_consts(&self) -> usize {
46 self.constants.len()
47 }
48
49 pub fn num_outputs(&self) -> usize {
51 self.outputs.len()
52 }
53
54 pub fn num_output_ciphertexts(&self) -> usize {
56 self.outputs.iter().map(|&m| m as usize).sum()
57 }
58
59 pub fn num_adds(&self) -> usize {
61 self.nadds
62 }
63
64 pub fn num_subs(&self) -> usize {
66 self.nsubs
67 }
68
69 pub fn num_cmuls(&self) -> usize {
71 self.ncmuls
72 }
73
74 pub fn num_muls(&self) -> usize {
76 self.nmuls
77 }
78
79 pub fn num_projs(&self) -> usize {
81 self.nprojs
82 }
83
84 pub fn num_ciphertexts(&self) -> usize {
86 self.nciphertexts
87 }
88}
89
90impl std::fmt::Display for InformerStats {
91 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
109 let mut total = 0.0;
110 writeln!(f, "computation info:")?;
111 let comm = self.num_inputs() as f64 * 128.0 / 1000.0;
112
113 writeln!(
114 f,
115 " inputs: {:16} // communication: {:.2} Kb",
116 self.num_inputs(),
117 comm
118 )?;
119 total += comm;
120
121 let comm = self.num_output_ciphertexts() as f64 * 128.0 / 1000.0;
122
123 writeln!(f, " outputs: {:16}", self.num_outputs())?;
124 writeln!(
125 f,
126 " output ciphertexts: {:16} // communication: {:.2} Kb",
127 self.num_output_ciphertexts(),
128 comm
129 )?;
130 total += comm;
131 let comm = self.num_consts() as f64 * 128.0 / 1000.0;
132
133 writeln!(
134 f,
135 " constants: {:16} // communication: {:.2} Kb",
136 self.num_consts(),
137 comm
138 )?;
139 total += comm;
140
141 writeln!(f, " additions: {:16}", self.num_adds())?;
142 writeln!(f, " subtractions: {:16}", self.num_subs())?;
143 writeln!(f, " cmuls: {:16}", self.num_cmuls())?;
144 writeln!(f, " projections: {:16}", self.num_projs())?;
145 writeln!(f, " multiplications: {:16}", self.num_muls())?;
146 let cs = self.num_ciphertexts();
147 let kb = cs as f64 * 128.0 / 1000.0;
148 let mb = kb / 1000.0;
149 writeln!(
150 f,
151 " ciphertexts: {:16} // communication: {:.2} Mb ({:.2} Kb)",
152 cs, mb, kb
153 )?;
154 total += kb;
155
156 let mb = total / 1000.0;
157 writeln!(f, " total communication: {:11.2} Mb", mb)?;
158 writeln!(f, " wire moduli: {:#?}", self.moduli)?;
159 Ok(())
160 }
161}
162
163impl<F: Fancy> Informer<F> {
164 pub fn new(underlying: F) -> Informer<F> {
166 Informer {
167 underlying,
168 stats: InformerStats {
169 input_moduli: Vec::new(),
170 constants: HashSet::new(),
171 outputs: Vec::new(),
172 nadds: 0,
173 nsubs: 0,
174 ncmuls: 0,
175 nmuls: 0,
176 nprojs: 0,
177 nciphertexts: 0,
178 moduli: HashMap::new(),
179 },
180 }
181 }
182
183 pub fn stats(&self) -> InformerStats {
185 self.stats.clone()
186 }
187
188 fn update_moduli(&mut self, q: u16) {
189 let entry = self.stats.moduli.entry(q).or_insert(0);
190 *entry += 1;
191 }
192}
193
194impl<F: FancyBinary> FancyBinary for Informer<F> {
195 fn xor(&mut self, x: &Self::Item, y: &Self::Item) -> Self::Item {
196 let result = self.underlying.xor(x, y);
197 self.stats.nadds += 1;
198 self.update_moduli(x.modulus());
199 result
200 }
201
202 fn and(
203 &mut self,
204 x: &Self::Item,
205 y: &Self::Item,
206 channel: &mut Channel,
207 ) -> swanky_error::Result<Self::Item> {
208 let result = self.underlying.and(x, y, channel)?;
209 self.stats.nmuls += 1;
210 self.stats.nciphertexts += 2;
211 self.update_moduli(x.modulus());
212 Ok(result)
213 }
214
215 fn negate(&mut self, x: &Self::Item) -> Self::Item {
216 let result = self.underlying.negate(x);
217
218 self.stats.nadds += 1;
220 self.update_moduli(x.modulus());
221 result
222 }
223}
224
225impl<F: FancyArithmetic> FancyArithmetic for Informer<F> {
226 fn add(&mut self, x: &Self::Item, y: &Self::Item) -> Self::Item {
231 let result = self.underlying.add(x, y);
232 self.stats.nadds += 1;
233 self.update_moduli(x.modulus());
234 result
235 }
236
237 fn sub(&mut self, x: &Self::Item, y: &Self::Item) -> Self::Item {
238 let result = self.underlying.sub(x, y);
239 self.stats.nsubs += 1;
240 self.update_moduli(x.modulus());
241 result
242 }
243
244 fn cmul(&mut self, x: &Self::Item, y: u16) -> Self::Item {
245 let result = self.underlying.cmul(x, y);
246 self.stats.ncmuls += 1;
247 self.update_moduli(x.modulus());
248 result
249 }
250
251 fn mul(
252 &mut self,
253 x: &Self::Item,
254 y: &Self::Item,
255 channel: &mut Channel,
256 ) -> swanky_error::Result<Self::Item> {
257 if x.modulus() < y.modulus() {
258 return self.mul(y, x, channel);
259 }
260 let result = self.underlying.mul(x, y, channel)?;
261 self.stats.nmuls += 1;
262 self.stats.nciphertexts += x.modulus() as usize + y.modulus() as usize - 2;
263 if x.modulus() != y.modulus() {
264 self.stats.nciphertexts += 1;
266 }
267 self.update_moduli(x.modulus());
268 Ok(result)
269 }
270}
271
272impl<F: FancyProj> FancyProj for Informer<F> {
273 fn proj(
274 &mut self,
275 x: &Self::Item,
276 q: u16,
277 tt: Option<Vec<u16>>,
278 channel: &mut Channel,
279 ) -> swanky_error::Result<Self::Item> {
280 let result = self.underlying.proj(x, q, tt, channel)?;
281 self.stats.nprojs += 1;
282 self.stats.nciphertexts += x.modulus() as usize - 1;
283 self.update_moduli(q);
284 Ok(result)
285 }
286}
287
288impl<F: Fancy> Fancy for Informer<F> {
289 type Item = F::Item;
290
291 fn receive_many(
292 &mut self,
293 moduli: &[u16],
294 channel: &mut Channel,
295 ) -> swanky_error::Result<Vec<Self::Item>> {
296 self.stats.input_moduli.extend(moduli.iter().cloned());
297 self.underlying.receive_many(moduli, channel)
298 }
299
300 fn encode_many(
301 &mut self,
302 values: &[u16],
303 moduli: &[u16],
304 channel: &mut Channel,
305 ) -> swanky_error::Result<Vec<Self::Item>> {
306 self.stats.input_moduli.extend(moduli.iter().cloned());
307 self.underlying.encode_many(values, moduli, channel)
308 }
309
310 fn constant(
311 &mut self,
312 val: u16,
313 q: u16,
314 channel: &mut Channel,
315 ) -> swanky_error::Result<Self::Item> {
316 self.stats.constants.insert((val, q));
317 self.update_moduli(q);
318 self.underlying.constant(val, q, channel)
319 }
320
321 fn output(
322 &mut self,
323 x: &Self::Item,
324 channel: &mut Channel,
325 ) -> swanky_error::Result<Option<u16>> {
326 let result = self.underlying.output(x, channel)?;
327 self.stats.outputs.push(x.modulus());
328 Ok(result)
329 }
330}