1#[cfg(feature = "seq_analyze")]
2use colored::Colorize;
3
4use crate::ciphertexts::{ParmCiphertext, ParmCiphertextImpl};
5use crate::ParmesanCloudovo;
6use crate::cloudovo::*;
7
8
9pub trait ParmArithmetics {
16 fn zero() -> Self;
18
19 fn opp(x: &Self) -> Self;
28
29 fn shift(
31 pc: &ParmesanCloudovo,
32 x: &Self,
33 k: usize,
34 ) -> Self;
35
36 fn add(
38 pc: &ParmesanCloudovo,
39 x: &Self,
40 y: &Self,
41 ) -> Self;
42
43 fn sub(
45 pc: &ParmesanCloudovo,
46 x: &Self,
47 y: &Self,
48 ) -> Self;
49
50 fn add_noisy(
53 pc: &ParmesanCloudovo,
54 x: &Self,
55 y: &Self,
56 ) -> Self;
57
58 fn sub_noisy(
61 pc: &ParmesanCloudovo,
62 x: &Self,
63 y: &Self,
64 ) -> Self;
65
66 fn add_const(
68 pc: &ParmesanCloudovo,
69 x: &Self,
70 k: i64,
71 ) -> Self;
72
73 fn scalar_mul(
75 pc: &ParmesanCloudovo,
76 k: i32,
77 x: &Self,
78 ) -> Self;
79
80 fn sgn(
82 pc: &ParmesanCloudovo,
83 x: &Self,
84 ) -> Self;
85
86 fn max(
88 pc: &ParmesanCloudovo,
89 x: &Self,
90 y: &Self,
91 ) -> Self;
92
93 fn relu(
95 pc: &ParmesanCloudovo,
96 x: &Self,
97 ) -> Self;
98
99 fn mul(
101 pc: &ParmesanCloudovo,
102 x: &Self,
103 y: &Self,
104 ) -> Self;
105
106 fn squ(
108 pc: &ParmesanCloudovo,
109 x: &Self,
110 ) -> Self;
111
112 fn round_at(
114 pc: &ParmesanCloudovo,
115 x: &Self,
116 pos: usize,
117 ) -> Self;
118
119 }
121
122impl ParmArithmetics for i64 {
123 fn zero() -> i64 {0i64}
124
125 fn opp(x: &i64) -> i64 {-x}
126
127 fn shift(
128 _pc: &ParmesanCloudovo,
129 x: &i64,
130 k: usize,
131 ) -> i64 {x << k}
132
133 fn add(
134 _pc: &ParmesanCloudovo,
135 x: &i64,
136 y: &i64,
137 ) -> i64 {x + y}
138
139 fn sub(
140 _pc: &ParmesanCloudovo,
141 x: &i64,
142 y: &i64,
143 ) -> i64 {x - y}
144
145 fn add_noisy(
146 _pc: &ParmesanCloudovo,
147 x: &i64,
148 y: &i64,
149 ) -> i64 {x + y}
150
151 fn sub_noisy(
152 _pc: &ParmesanCloudovo,
153 x: &i64,
154 y: &i64,
155 ) -> i64 {x - y}
156
157 fn add_const(
158 _pc: &ParmesanCloudovo,
159 x: &i64,
160 k: i64,
161 ) -> i64 {x + k}
162
163 fn scalar_mul(
164 _pc: &ParmesanCloudovo,
165 k: i32,
166 x: &i64,
167 ) -> i64 {(k as i64) * x}
168
169 fn sgn(
170 _pc: &ParmesanCloudovo,
171 x: &i64,
172 ) -> i64 {x.signum()}
173
174 fn max(
175 _pc: &ParmesanCloudovo,
176 x: &i64,
177 y: &i64,
178 ) -> i64 {std::cmp::max(*x, *y)}
179
180 fn relu(
181 _pc: &ParmesanCloudovo,
182 x: &i64,
183 ) -> i64 {std::cmp::max(0, *x)}
184
185 fn mul(
186 _pc: &ParmesanCloudovo,
187 x: &i64,
188 y: &i64,
189 ) -> i64 {x * y}
190
191 fn squ(
192 _pc: &ParmesanCloudovo,
193 x: &i64,
194 ) -> i64 {x * x}
195
196 fn round_at(
197 _pc: &ParmesanCloudovo,
198 x: &i64,
199 pos: usize,
200 ) -> i64 {
201 match pos {
202 0 => { *x },
203 p if p >= 63 => { panic!("Rounding position ≥ 63 (for i64).") },
204 _ => {
205 x
207 - (x & ((1 << pos) - 1))
208 + ((x & (1 << (pos-1))) << 1)
209 },
210 }
211 }
212}
213
214impl ParmArithmetics for ParmCiphertext {
215 fn zero() -> ParmCiphertext {
216 ParmCiphertext::empty()
217 }
218
219 fn opp(x: &ParmCiphertext) -> ParmCiphertext {
220 addition::opposite_impl(x)
221 }
222
223 fn shift(
224 pc: &ParmesanCloudovo,
225 x: &ParmCiphertext,
226 k: usize,
227 ) -> ParmCiphertext {
228 if k == 0 {return x.clone();}
229 let mut x_shifted = ParmCiphertext::triv(k, pc);
230 x_shifted.append(&mut x.clone());
231 x_shifted
232 }
233
234 fn add(
235 pc: &ParmesanCloudovo,
236 x: &ParmCiphertext,
237 y: &ParmCiphertext,
238 ) -> ParmCiphertext {
239 #[cfg(feature = "seq_analyze")]
240 start_pbs_analysis!();
241
242 let res = addition::add_sub_impl(
243 true,
244 pc,
245 x,
246 y,
247 true,
248 ).expect("ParmArithmetics::add failed.");
249
250 #[cfg(feature = "seq_analyze")]
251 finish_pbs_analysis!();
252
253 res
254 }
255
256 fn sub(
257 pc: &ParmesanCloudovo,
258 x: &ParmCiphertext,
259 y: &ParmCiphertext,
260 ) -> ParmCiphertext {
261 #[cfg(feature = "seq_analyze")]
262 start_pbs_analysis!();
263
264 let res = addition::add_sub_impl(
265 false,
266 pc,
267 x,
268 y,
269 true,
270 ).expect("ParmArithmetics::sub failed.");
271
272 #[cfg(feature = "seq_analyze")]
273 finish_pbs_analysis!();
274
275 res
276 }
277
278 fn add_noisy(
279 pc: &ParmesanCloudovo,
280 x: &ParmCiphertext,
281 y: &ParmCiphertext,
282 ) -> ParmCiphertext {
283 #[cfg(feature = "seq_analyze")]
284 start_pbs_analysis!();
285
286 let res = addition::add_sub_impl(
287 true,
288 pc,
289 x,
290 y,
291 false,
292 ).expect("ParmArithmetics::add failed.");
293
294 #[cfg(feature = "seq_analyze")]
295 finish_pbs_analysis!();
296
297 res
298 }
299
300 fn sub_noisy(
301 pc: &ParmesanCloudovo,
302 x: &ParmCiphertext,
303 y: &ParmCiphertext,
304 ) -> ParmCiphertext {
305 #[cfg(feature = "seq_analyze")]
306 start_pbs_analysis!();
307
308 let res = addition::add_sub_impl(
309 false,
310 pc,
311 x,
312 y,
313 false,
314 ).expect("ParmArithmetics::sub failed.");
315
316 #[cfg(feature = "seq_analyze")]
317 finish_pbs_analysis!();
318
319 res
320 }
321
322 fn add_const(
323 pc: &ParmesanCloudovo,
324 x: &ParmCiphertext,
325 k: i64,
326 ) -> ParmCiphertext {
327 #[cfg(feature = "seq_analyze")]
328 start_pbs_analysis!();
329
330 let res = addition::add_const_impl(
331 pc,
332 x,
333 k,
334 ).expect("ParmArithmetics::add_const failed.");
335
336 #[cfg(feature = "seq_analyze")]
337 finish_pbs_analysis!();
338
339 res
340 }
341
342 fn scalar_mul(
343 pc: &ParmesanCloudovo,
344 k: i32,
345 x: &ParmCiphertext,
346 ) -> ParmCiphertext {
347 #[cfg(feature = "seq_analyze")]
348 start_pbs_analysis!();
349
350 let res = scalar_multiplication::scalar_mul_impl(
351 pc,
352 k,
353 x,
354 ).expect("ParmArithmetics::scalar_mul failed.");
355
356 #[cfg(feature = "seq_analyze")]
357 finish_pbs_analysis!();
358
359 res
360 }
361
362 fn sgn(
363 pc: &ParmesanCloudovo,
364 x: &ParmCiphertext,
365 ) -> ParmCiphertext {
366 #[cfg(feature = "seq_analyze")]
367 start_pbs_analysis!();
368
369 let res = signum::sgn_impl(
370 pc,
371 x,
372 ).expect("ParmArithmetics::sgn failed.");
373
374 #[cfg(feature = "seq_analyze")]
375 finish_pbs_analysis!();
376
377 res
378 }
379
380 fn max(
381 pc: &ParmesanCloudovo,
382 x: &ParmCiphertext,
383 y: &ParmCiphertext,
384 ) -> ParmCiphertext {
385 #[cfg(feature = "seq_analyze")]
386 start_pbs_analysis!();
387
388 let res = maximum::max_impl(
389 pc,
390 x,
391 y,
392 ).expect("ParmArithmetics::max failed.");
393
394 #[cfg(feature = "seq_analyze")]
395 finish_pbs_analysis!();
396
397 res
398 }
399
400 fn relu(
401 pc: &ParmesanCloudovo,
402 x: &ParmCiphertext,
403 ) -> ParmCiphertext {
404 #[cfg(feature = "seq_analyze")]
405 start_pbs_analysis!();
406
407 let res = maximum::max_impl(
408 pc,
409 &ParmArithmetics::zero(),
410 x,
411 ).expect("ParmArithmetics::relu failed.");
412
413 #[cfg(feature = "seq_analyze")]
414 finish_pbs_analysis!();
415
416 res
417 }
418
419 fn mul(
420 pc: &ParmesanCloudovo,
421 x: &ParmCiphertext,
422 y: &ParmCiphertext,
423 ) -> ParmCiphertext {
424 #[cfg(feature = "seq_analyze")]
425 start_pbs_analysis!();
426
427 let res = multiplication::mul_impl(
428 pc,
429 x,
430 y,
431 ).expect("ParmArithmetics::mul failed.");
432
433 #[cfg(feature = "seq_analyze")]
434 finish_pbs_analysis!();
435
436 res
437 }
438
439 fn squ(
440 pc: &ParmesanCloudovo,
441 x: &ParmCiphertext,
442 ) -> ParmCiphertext {
443 #[cfg(feature = "seq_analyze")]
444 start_pbs_analysis!();
445
446 let res = squaring::squ_impl(
447 pc,
448 x,
449 ).expect("ParmArithmetics::squ failed.");
450
451 #[cfg(feature = "seq_analyze")]
452 finish_pbs_analysis!();
453
454 res
455 }
456
457 fn round_at(
458 pc: &ParmesanCloudovo,
459 x: &ParmCiphertext,
460 pos: usize,
461 ) -> ParmCiphertext {
462 #[cfg(feature = "seq_analyze")]
463 start_pbs_analysis!();
464
465 let res = rounding::round_at_impl(
466 pc,
467 x,
468 pos,
469 ).expect("ParmArithmetics::round_at failed.");
470
471 #[cfg(feature = "seq_analyze")]
472 finish_pbs_analysis!();
473
474 res
475 }
476}