qfall_math/integer_mod_q/polynomial_ring_zq/arithmetic/
add.rs1use super::super::PolynomialRingZq;
12use crate::{
13 error::MathError,
14 integer::PolyOverZ,
15 integer_mod_q::PolyOverZq,
16 macros::arithmetics::{
17 arithmetic_assign_trait_borrowed_to_owned, arithmetic_trait_borrowed_to_owned,
18 arithmetic_trait_mixed_borrowed_owned, arithmetic_trait_reverse,
19 },
20 traits::CompareBase,
21};
22use std::ops::{Add, AddAssign};
23
24impl AddAssign<&PolynomialRingZq> for PolynomialRingZq {
25 fn add_assign(&mut self, other: &Self) {
59 if !self.compare_base(other) {
60 panic!("{}", self.call_compare_base_error(other).unwrap());
61 }
62
63 self.poly += &other.poly;
64 self.reduce();
65 }
66}
67impl AddAssign<&PolyOverZ> for PolynomialRingZq {
68 fn add_assign(&mut self, other: &PolyOverZ) {
70 self.poly += other;
71 self.reduce();
72 }
73}
74impl AddAssign<&PolyOverZq> for PolynomialRingZq {
75 fn add_assign(&mut self, other: &PolyOverZq) {
80 if !self.compare_base(other) {
81 panic!("{}", self.call_compare_base_error(other).unwrap())
82 }
83
84 self.poly += &other.get_representative_least_nonnegative_residue();
85 self.reduce();
86 }
87}
88
89arithmetic_assign_trait_borrowed_to_owned!(
90 AddAssign,
91 add_assign,
92 PolynomialRingZq,
93 PolynomialRingZq
94);
95arithmetic_assign_trait_borrowed_to_owned!(AddAssign, add_assign, PolynomialRingZq, PolyOverZ);
96arithmetic_assign_trait_borrowed_to_owned!(AddAssign, add_assign, PolynomialRingZq, PolyOverZq);
97
98impl Add for &PolynomialRingZq {
99 type Output = PolynomialRingZq;
100 fn add(self, other: Self) -> Self::Output {
130 self.add_safe(other).unwrap()
131 }
132}
133
134impl Add<&PolyOverZ> for &PolynomialRingZq {
135 type Output = PolynomialRingZq;
136 fn add(self, other: &PolyOverZ) -> Self::Output {
159 let mut out = self.clone();
160 out += other;
161 out
162 }
163}
164
165arithmetic_trait_reverse!(Add, add, PolyOverZ, PolynomialRingZq, PolynomialRingZq);
166
167arithmetic_trait_borrowed_to_owned!(Add, add, PolynomialRingZq, PolyOverZ, PolynomialRingZq);
168arithmetic_trait_borrowed_to_owned!(Add, add, PolyOverZ, PolynomialRingZq, PolynomialRingZq);
169arithmetic_trait_mixed_borrowed_owned!(Add, add, PolynomialRingZq, PolyOverZ, PolynomialRingZq);
170arithmetic_trait_mixed_borrowed_owned!(Add, add, PolyOverZ, PolynomialRingZq, PolynomialRingZq);
171
172impl Add<&PolyOverZq> for &PolynomialRingZq {
173 type Output = PolynomialRingZq;
174 fn add(self, other: &PolyOverZq) -> Self::Output {
200 if !self.compare_base(other) {
201 panic!("{}", self.call_compare_base_error(other).unwrap())
202 }
203
204 let mut out = self.clone();
205 out.poly += &other.get_representative_least_nonnegative_residue();
206 out
207 }
208}
209
210arithmetic_trait_reverse!(Add, add, PolyOverZq, PolynomialRingZq, PolynomialRingZq);
211
212arithmetic_trait_borrowed_to_owned!(Add, add, PolynomialRingZq, PolyOverZq, PolynomialRingZq);
213arithmetic_trait_borrowed_to_owned!(Add, add, PolyOverZq, PolynomialRingZq, PolynomialRingZq);
214arithmetic_trait_mixed_borrowed_owned!(Add, add, PolynomialRingZq, PolyOverZq, PolynomialRingZq);
215arithmetic_trait_mixed_borrowed_owned!(Add, add, PolyOverZq, PolynomialRingZq, PolynomialRingZq);
216
217impl PolynomialRingZq {
218 pub fn add_safe(&self, other: &Self) -> Result<PolynomialRingZq, MathError> {
245 if !self.compare_base(other) {
246 return Err(self.call_compare_base_error(other).unwrap());
247 }
248 let mut out = self.clone();
249 out += other;
250 Ok(out)
251 }
252}
253
254arithmetic_trait_borrowed_to_owned!(
255 Add,
256 add,
257 PolynomialRingZq,
258 PolynomialRingZq,
259 PolynomialRingZq
260);
261arithmetic_trait_mixed_borrowed_owned!(
262 Add,
263 add,
264 PolynomialRingZq,
265 PolynomialRingZq,
266 PolynomialRingZq
267);
268
269#[cfg(test)]
270mod test_add_assign {
271 use super::PolyOverZ;
272 use crate::integer_mod_q::{ModulusPolynomialRingZq, PolyOverZq, PolynomialRingZq};
273 use std::str::FromStr;
274
275 #[test]
277 fn correct_small() {
278 let modulus = ModulusPolynomialRingZq::from_str("4 1 0 0 1 mod 17").unwrap();
279 let poly_1 = PolyOverZ::from_str("4 -1 0 1 1").unwrap();
280 let mut a = PolynomialRingZq::from((&poly_1, &modulus));
281 let poly_2 = PolyOverZ::from_str("4 2 0 3 -1").unwrap();
282 let b = PolynomialRingZq::from((&poly_2, &modulus));
283 let cmp = PolynomialRingZq::from((&PolyOverZ::from_str("3 1 0 4").unwrap(), &modulus));
284
285 a += b;
286
287 assert_eq!(cmp, a);
288 }
289
290 #[test]
292 fn correct_large() {
293 let modulus = ModulusPolynomialRingZq::from_str(&format!(
294 "4 {} 0 0 1 mod {}",
295 u64::MAX,
296 u64::MAX - 58
297 ))
298 .unwrap();
299 let poly_1 = PolyOverZ::from_str(&format!("4 {} 0 1 {}", u64::MAX, i64::MIN)).unwrap();
300 let mut a = PolynomialRingZq::from((&poly_1, &modulus));
301 let poly_2 = PolyOverZ::from_str(&format!("4 {} 0 -1 {}", i64::MAX, i64::MAX)).unwrap();
302 let b = PolynomialRingZq::from((&poly_2, &modulus));
303 let cmp = PolynomialRingZq::from((
304 &PolyOverZ::from_str(&format!("4 {} 0 0 {}", (u64::MAX - 1) / 2 + 58, -1)).unwrap(),
305 &modulus,
306 ));
307
308 a += b;
309
310 assert_eq!(cmp, a);
311 }
312
313 #[test]
315 fn availability() {
316 let modulus = ModulusPolynomialRingZq::from_str("4 1 0 0 1 mod 17").unwrap();
317 let poly_1 = PolyOverZ::from_str("4 -1 0 1 1").unwrap();
318 let mut a = PolynomialRingZq::from((&poly_1, &modulus));
319 let poly_2 = PolyOverZ::from_str("4 2 0 3 1").unwrap();
320 let b = PolynomialRingZq::from((&poly_2, &modulus));
321 let c = PolyOverZq::from((poly_2, 17));
322
323 a += &b;
324 a += b;
325 a += &poly_1;
326 a += poly_1;
327 a += &c;
328 a += c;
329 }
330
331 #[test]
333 #[should_panic]
334 fn mismatching_moduli() {
335 let modulus = ModulusPolynomialRingZq::from_str("4 1 0 0 1 mod 17").unwrap();
336 let poly_1 = PolyOverZ::from_str("4 -1 0 1 1").unwrap();
337 let mut a = PolynomialRingZq::from((&poly_1, &modulus));
338 let modulus = ModulusPolynomialRingZq::from_str("4 2 0 0 1 mod 17").unwrap();
339 let poly_2 = PolyOverZ::from_str("4 2 0 3 1").unwrap();
340 let b = PolynomialRingZq::from((&poly_2, &modulus));
341
342 a += b;
343 }
344}
345
346#[cfg(test)]
347mod test_add {
348 use crate::integer::PolyOverZ;
349 use crate::integer_mod_q::ModulusPolynomialRingZq;
350 use crate::integer_mod_q::PolynomialRingZq;
351 use std::str::FromStr;
352
353 #[test]
355 fn add() {
356 let modulus = ModulusPolynomialRingZq::from_str("4 1 0 0 1 mod 17").unwrap();
357 let poly_1 = PolyOverZ::from_str("4 -1 0 1 1").unwrap();
358 let a = PolynomialRingZq::from((&poly_1, &modulus));
359 let poly_2 = PolyOverZ::from_str("4 2 0 3 1").unwrap();
360 let b = PolynomialRingZq::from((&poly_2, &modulus));
361 let c = a + b;
362 assert_eq!(
363 c,
364 PolynomialRingZq::from((&PolyOverZ::from_str("4 1 0 4 2").unwrap(), &modulus))
365 );
366 }
367
368 #[test]
370 fn add_borrow() {
371 let modulus = ModulusPolynomialRingZq::from_str("4 1 0 0 1 mod 17").unwrap();
372 let poly_1 = PolyOverZ::from_str("4 -1 0 1 1").unwrap();
373 let a = PolynomialRingZq::from((&poly_1, &modulus));
374 let poly_2 = PolyOverZ::from_str("4 2 0 3 1").unwrap();
375 let b = PolynomialRingZq::from((&poly_2, &modulus));
376 let c = &a + &b;
377 assert_eq!(
378 c,
379 PolynomialRingZq::from((&PolyOverZ::from_str("4 1 0 4 2").unwrap(), &modulus))
380 );
381 }
382
383 #[test]
385 fn add_first_borrowed() {
386 let modulus = ModulusPolynomialRingZq::from_str("4 1 0 0 1 mod 17").unwrap();
387 let poly_1 = PolyOverZ::from_str("4 -1 0 1 1").unwrap();
388 let a = PolynomialRingZq::from((&poly_1, &modulus));
389 let poly_2 = PolyOverZ::from_str("4 2 0 3 1").unwrap();
390 let b = PolynomialRingZq::from((&poly_2, &modulus));
391 let c = &a + b;
392 assert_eq!(
393 c,
394 PolynomialRingZq::from((&PolyOverZ::from_str("4 1 0 4 2").unwrap(), &modulus))
395 );
396 }
397
398 #[test]
400 fn add_second_borrowed() {
401 let modulus = ModulusPolynomialRingZq::from_str("4 1 0 0 1 mod 17").unwrap();
402 let poly_1 = PolyOverZ::from_str("4 -1 0 1 1").unwrap();
403 let a = PolynomialRingZq::from((&poly_1, &modulus));
404 let poly_2 = PolyOverZ::from_str("4 2 0 3 1").unwrap();
405 let b = PolynomialRingZq::from((&poly_2, &modulus));
406 let c = a + &b;
407 assert_eq!(
408 c,
409 PolynomialRingZq::from((&PolyOverZ::from_str("4 1 0 4 2").unwrap(), &modulus))
410 );
411 }
412
413 #[test]
415 fn add_reduce() {
416 let modulus = ModulusPolynomialRingZq::from_str("4 1 0 0 1 mod 17").unwrap();
417 let poly_1 = PolyOverZ::from_str("4 -1 0 1 1").unwrap();
418 let a = PolynomialRingZq::from((&poly_1, &modulus));
419 let poly_2 = PolyOverZ::from_str("4 2 0 3 -1").unwrap();
420 let b = PolynomialRingZq::from((&poly_2, &modulus));
421 let c = a + &b;
422 assert_eq!(
423 c,
424 PolynomialRingZq::from((&PolyOverZ::from_str("3 1 0 4").unwrap(), &modulus))
425 );
426 }
427
428 #[test]
430 fn add_large_numbers() {
431 let modulus = ModulusPolynomialRingZq::from_str(&format!(
432 "4 {} 0 0 1 mod {}",
433 u64::MAX,
434 u64::MAX - 58
435 ))
436 .unwrap();
437
438 let poly_1 = PolyOverZ::from_str(&format!("4 {} 0 1 {}", u64::MAX, i64::MIN)).unwrap();
439 let a = PolynomialRingZq::from((&poly_1, &modulus));
440
441 let poly_2 = PolyOverZ::from_str(&format!("4 {} 0 -1 {}", i64::MAX, i64::MAX)).unwrap();
442 let b = PolynomialRingZq::from((&poly_2, &modulus));
443
444 let c = a + b;
445 assert_eq!(
446 c,
447 PolynomialRingZq::from((
448 &PolyOverZ::from_str(&format!("4 {} 0 0 {}", (u64::MAX - 1) / 2 + 58, -1))
449 .unwrap(),
450 &modulus
451 ))
452 );
453 }
454
455 #[test]
457 #[should_panic]
458 fn add_mismatching_modulus() {
459 let modulus = ModulusPolynomialRingZq::from_str("4 1 0 0 1 mod 17").unwrap();
460 let poly_1 = PolyOverZ::from_str("4 -1 0 1 1").unwrap();
461 let a = PolynomialRingZq::from((&poly_1, &modulus));
462 let modulus = ModulusPolynomialRingZq::from_str("4 2 0 0 1 mod 17").unwrap();
463 let poly_2 = PolyOverZ::from_str("4 2 0 3 1").unwrap();
464 let b = PolynomialRingZq::from((&poly_2, &modulus));
465 let _ = a + b;
466 }
467
468 #[test]
470 fn add_safe_is_err() {
471 let modulus = ModulusPolynomialRingZq::from_str("4 1 0 0 1 mod 17").unwrap();
472 let poly_1 = PolyOverZ::from_str("4 -1 0 1 1").unwrap();
473 let a = PolynomialRingZq::from((&poly_1, &modulus));
474 let modulus = ModulusPolynomialRingZq::from_str("4 2 0 0 1 mod 17").unwrap();
475 let poly_2 = PolyOverZ::from_str("4 2 0 3 1").unwrap();
476 let b = PolynomialRingZq::from((&poly_2, &modulus));
477
478 assert!(&a.add_safe(&b).is_err());
479 }
480}
481
482#[cfg(test)]
483mod test_add_poly_over_z {
484 use super::PolynomialRingZq;
485 use crate::integer::PolyOverZ;
486 use std::str::FromStr;
487
488 #[test]
490 fn borrowed_correctness() {
491 let poly_1 =
492 PolynomialRingZq::from_str(&format!("2 2 {} / 4 1 2 3 1 mod {}", i64::MAX, u64::MAX))
493 .unwrap();
494 let poly_2 = PolynomialRingZq::from_str(&format!(
495 "2 3 {} / 4 1 2 3 1 mod {}",
496 i64::MAX as u64 + 2,
497 u64::MAX
498 ))
499 .unwrap();
500 let poly = PolyOverZ::from_str("2 1 2").unwrap();
501
502 let poly_1 = &poly_1 + &poly;
503
504 assert_eq!(poly_2, poly_1);
505 }
506
507 #[test]
509 fn availability() {
510 let poly = PolynomialRingZq::from_str("3 1 2 3 / 4 1 2 3 1 mod 17").unwrap();
511 let z = PolyOverZ::from(2);
512
513 _ = poly.clone() + z.clone();
514 _ = z.clone() + poly.clone();
515 _ = &poly + &z;
516 _ = &z + &poly;
517 _ = &poly + z.clone();
518 _ = z.clone() + &poly;
519 _ = &z + poly.clone();
520 _ = poly.clone() + &z;
521 }
522}
523
524#[cfg(test)]
525mod test_add_poly_over_zq {
526 use super::PolynomialRingZq;
527 use crate::integer_mod_q::PolyOverZq;
528 use std::str::FromStr;
529
530 #[test]
532 fn borrowed_correctness() {
533 let poly_1 =
534 PolynomialRingZq::from_str(&format!("2 2 {} / 4 1 2 3 1 mod {}", i64::MAX, u64::MAX))
535 .unwrap();
536 let poly_2 = PolynomialRingZq::from_str(&format!(
537 "2 3 {} / 4 1 2 3 1 mod {}",
538 i64::MAX as u64 + 1,
539 u64::MAX
540 ))
541 .unwrap();
542 let poly = PolyOverZq::from_str(&format!("2 1 1 mod {}", u64::MAX)).unwrap();
543
544 let poly_1 = &poly_1 + &poly;
545
546 assert_eq!(poly_2, poly_1);
547 }
548
549 #[test]
551 fn availability() {
552 let poly = PolynomialRingZq::from_str("3 1 2 3 / 4 1 2 3 1 mod 17").unwrap();
553 let zq = PolyOverZq::from((2, 17));
554
555 _ = poly.clone() + zq.clone();
556 _ = zq.clone() + poly.clone();
557 _ = &poly + &zq;
558 _ = &zq + &poly;
559 _ = &poly + zq.clone();
560 _ = zq.clone() + &poly;
561 _ = &zq + poly.clone();
562 _ = poly.clone() + &zq;
563 }
564
565 #[test]
567 #[should_panic]
568 fn different_moduli_panic() {
569 let poly = PolynomialRingZq::from_str("3 1 2 3 / 4 1 2 3 1 mod 17").unwrap();
570 let zq = PolyOverZq::from((2, 16));
571
572 _ = &poly + &zq;
573 }
574}