1use super::super::MatPolynomialRingZq;
12use crate::{
13 error::MathError,
14 integer::MatPolyOverZ,
15 macros::arithmetics::{
16 arithmetic_assign_trait_borrowed_to_owned, arithmetic_trait_borrowed_to_owned,
17 arithmetic_trait_mixed_borrowed_owned, arithmetic_trait_reverse,
18 },
19 traits::{CompareBase, MatrixDimensions},
20};
21use std::ops::{Add, AddAssign};
22
23impl AddAssign<&MatPolynomialRingZq> for MatPolynomialRingZq {
24 fn add_assign(&mut self, other: &Self) {
54 if !self.compare_base(other) {
55 panic!("{}", self.call_compare_base_error(other).unwrap());
56 }
57
58 self.matrix += &other.matrix;
59
60 self.reduce();
61 }
62}
63impl AddAssign<&MatPolyOverZ> for MatPolynomialRingZq {
64 fn add_assign(&mut self, other: &MatPolyOverZ) {
66 self.matrix += other;
67
68 self.reduce();
69 }
70}
71
72arithmetic_assign_trait_borrowed_to_owned!(
73 AddAssign,
74 add_assign,
75 MatPolynomialRingZq,
76 MatPolynomialRingZq
77);
78arithmetic_assign_trait_borrowed_to_owned!(
79 AddAssign,
80 add_assign,
81 MatPolynomialRingZq,
82 MatPolyOverZ
83);
84
85impl Add for &MatPolynomialRingZq {
86 type Output = MatPolynomialRingZq;
87 fn add(self, other: Self) -> Self::Output {
118 self.add_safe(other).unwrap()
119 }
120}
121
122arithmetic_trait_borrowed_to_owned!(
123 Add,
124 add,
125 MatPolynomialRingZq,
126 MatPolynomialRingZq,
127 MatPolynomialRingZq
128);
129arithmetic_trait_mixed_borrowed_owned!(
130 Add,
131 add,
132 MatPolynomialRingZq,
133 MatPolynomialRingZq,
134 MatPolynomialRingZq
135);
136
137impl Add<&MatPolyOverZ> for &MatPolynomialRingZq {
138 type Output = MatPolynomialRingZq;
139 fn add(self, other: &MatPolyOverZ) -> Self::Output {
162 self.add_mat_poly_over_z_safe(other).unwrap()
163 }
164}
165
166arithmetic_trait_reverse!(
167 Add,
168 add,
169 MatPolyOverZ,
170 MatPolynomialRingZq,
171 MatPolynomialRingZq
172);
173
174arithmetic_trait_borrowed_to_owned!(
175 Add,
176 add,
177 MatPolynomialRingZq,
178 MatPolyOverZ,
179 MatPolynomialRingZq
180);
181arithmetic_trait_borrowed_to_owned!(
182 Add,
183 add,
184 MatPolyOverZ,
185 MatPolynomialRingZq,
186 MatPolynomialRingZq
187);
188arithmetic_trait_mixed_borrowed_owned!(
189 Add,
190 add,
191 MatPolynomialRingZq,
192 MatPolyOverZ,
193 MatPolynomialRingZq
194);
195arithmetic_trait_mixed_borrowed_owned!(
196 Add,
197 add,
198 MatPolyOverZ,
199 MatPolynomialRingZq,
200 MatPolynomialRingZq
201);
202
203impl MatPolynomialRingZq {
204 pub fn add_safe(&self, other: &Self) -> Result<MatPolynomialRingZq, MathError> {
234 if !self.compare_base(other) {
235 return Err(self.call_compare_base_error(other).unwrap());
236 }
237 let matrix = self.matrix.add_safe(&other.matrix)?;
238
239 Ok(MatPolynomialRingZq::from((&matrix, &self.modulus)))
240 }
241
242 pub fn add_mat_poly_over_z_safe(&self, other: &MatPolyOverZ) -> Result<Self, MathError> {
266 let mut out =
267 MatPolynomialRingZq::new(self.get_num_rows(), self.get_num_columns(), self.get_mod());
268
269 out.matrix = self.matrix.add_safe(other)?;
270 out.reduce();
271
272 Ok(out)
273 }
274}
275
276#[cfg(test)]
277mod test_add_assign {
278 use crate::{
279 integer::MatPolyOverZ,
280 integer_mod_q::{MatPolynomialRingZq, ModulusPolynomialRingZq},
281 };
282 use std::str::FromStr;
283
284 #[test]
286 fn correct_small() {
287 let mut a = MatPolynomialRingZq::from_str("[[1 1, 0],[0, 1 1]] / 2 0 1 mod 7").unwrap();
288 let b =
289 MatPolynomialRingZq::from_str("[[1 4, 1 5],[1 -6, 2 6 1]] / 2 0 1 mod 7").unwrap();
290 let cmp = MatPolynomialRingZq::from_str("[[1 5, 1 5],[1 1, 0]] / 2 0 1 mod 7").unwrap();
291
292 a += b;
293
294 assert_eq!(cmp, a);
295 }
296
297 #[test]
299 fn correct_large() {
300 let mut a = MatPolynomialRingZq::from_str(&format!(
301 "[[1 {}, 1 5],[1 {}, 1 -1]] / 2 0 1 mod {}",
302 i64::MAX,
303 i64::MIN,
304 u64::MAX
305 ))
306 .unwrap();
307 let b = MatPolynomialRingZq::from_str(&format!(
308 "[[1 {}, 1 -6],[1 6, 1 -1]] / 2 0 1 mod {}",
309 i64::MAX,
310 u64::MAX
311 ))
312 .unwrap();
313 let cmp = MatPolynomialRingZq::from_str(&format!(
314 "[[1 {}, 1 -1],[1 {}, 1 -2]] / 2 0 1 mod {}",
315 2 * (i64::MAX as u64),
316 i64::MIN + 6,
317 u64::MAX
318 ))
319 .unwrap();
320
321 a += b;
322
323 assert_eq!(cmp, a);
324 }
325
326 #[test]
328 fn matrix_dimensions() {
329 let modulus = ModulusPolynomialRingZq::from_str("3 1 0 1 mod 7").unwrap();
330 let dimensions = [(3, 3), (5, 1), (1, 4)];
331
332 for (nr_rows, nr_cols) in dimensions {
333 let mut a = MatPolynomialRingZq::new(nr_rows, nr_cols, &modulus);
334 let b = MatPolynomialRingZq::identity(nr_rows, nr_cols, &modulus);
335
336 a += b;
337
338 assert_eq!(MatPolynomialRingZq::identity(nr_rows, nr_cols, &modulus), a);
339 }
340 }
341
342 #[test]
344 #[should_panic]
345 fn mismatching_dimensions() {
346 let modulus = ModulusPolynomialRingZq::from_str("3 1 0 1 mod 7").unwrap();
347 let mut a = MatPolynomialRingZq::new(2, 1, &modulus);
348 let b = MatPolynomialRingZq::new(1, 1, &modulus);
349
350 a += b;
351 }
352
353 #[test]
355 #[should_panic]
356 fn mismatching_moduli() {
357 let modulus_0 = ModulusPolynomialRingZq::from_str("3 1 0 1 mod 7").unwrap();
358 let modulus_1 = ModulusPolynomialRingZq::from_str("4 1 0 0 1 mod 7").unwrap();
359 let mut a = MatPolynomialRingZq::new(1, 1, &modulus_0);
360 let b = MatPolynomialRingZq::new(1, 1, &modulus_1);
361
362 a += b;
363 }
364
365 #[test]
367 fn availability() {
368 let modulus = ModulusPolynomialRingZq::from_str("3 1 0 1 mod 7").unwrap();
369 let mut a = MatPolynomialRingZq::new(2, 2, &modulus);
370 let b = MatPolynomialRingZq::new(2, 2, &modulus);
371 let c = MatPolyOverZ::new(2, 2);
372
373 a += &b;
374 a += b;
375 a += &c;
376 a += c;
377 }
378}
379
380#[cfg(test)]
381mod test_add {
382 use crate::integer::MatPolyOverZ;
383 use crate::integer_mod_q::MatPolynomialRingZq;
384 use crate::integer_mod_q::ModulusPolynomialRingZq;
385 use std::str::FromStr;
386
387 const LARGE_PRIME: u64 = 18446744073709551557;
388
389 #[test]
391 fn add() {
392 let modulus = ModulusPolynomialRingZq::from_str("4 1 0 0 1 mod 17").unwrap();
393 let poly_mat_1 = MatPolyOverZ::from_str("[[4 -1 0 1 1, 1 42],[0, 2 1 2]]").unwrap();
394 let poly_ring_mat_1 = MatPolynomialRingZq::from((&poly_mat_1, &modulus));
395 let poly_mat_2 = MatPolyOverZ::from_str("[[3 3 0 1, 1 42],[0, 1 17]]").unwrap();
396 let poly_ring_mat_2 = MatPolynomialRingZq::from((&poly_mat_2, &modulus));
397 let poly_mat_cmp = MatPolyOverZ::from_str("[[3 1 0 2, 1 16],[0, 2 1 2]]").unwrap();
398 let poly_ring_mat_cmp = MatPolynomialRingZq::from((&poly_mat_cmp, &modulus));
399
400 let poly_ring_mat_3 = poly_ring_mat_1 + poly_ring_mat_2;
401
402 assert_eq!(poly_ring_mat_3, poly_ring_mat_cmp);
403 }
404
405 #[test]
407 fn add_borrow() {
408 let modulus = ModulusPolynomialRingZq::from_str("4 1 0 0 1 mod 17").unwrap();
409 let poly_mat_1 = MatPolyOverZ::from_str("[[4 -1 0 1 1, 1 42],[0, 2 1 2]]").unwrap();
410 let poly_ring_mat_1 = MatPolynomialRingZq::from((&poly_mat_1, &modulus));
411 let poly_mat_2 = MatPolyOverZ::from_str("[[3 3 0 1, 1 42],[0, 1 17]]").unwrap();
412 let poly_ring_mat_2 = MatPolynomialRingZq::from((&poly_mat_2, &modulus));
413 let poly_mat_cmp = MatPolyOverZ::from_str("[[3 1 0 2, 1 16],[0, 2 1 2]]").unwrap();
414 let poly_ring_mat_cmp = MatPolynomialRingZq::from((&poly_mat_cmp, &modulus));
415
416 let poly_ring_mat_3 = &poly_ring_mat_1 + &poly_ring_mat_2;
417
418 assert_eq!(poly_ring_mat_3, poly_ring_mat_cmp);
419 }
420
421 #[test]
423 fn add_first_borrowed() {
424 let modulus = ModulusPolynomialRingZq::from_str("4 1 0 0 1 mod 17").unwrap();
425 let poly_mat_1 = MatPolyOverZ::from_str("[[4 -1 0 1 1, 1 42],[0, 2 1 2]]").unwrap();
426 let poly_ring_mat_1 = MatPolynomialRingZq::from((&poly_mat_1, &modulus));
427 let poly_mat_2 = MatPolyOverZ::from_str("[[3 3 0 1, 1 42],[0, 1 17]]").unwrap();
428 let poly_ring_mat_2 = MatPolynomialRingZq::from((&poly_mat_2, &modulus));
429 let poly_mat_cmp = MatPolyOverZ::from_str("[[3 1 0 2, 1 16],[0, 2 1 2]]").unwrap();
430 let poly_ring_mat_cmp = MatPolynomialRingZq::from((&poly_mat_cmp, &modulus));
431
432 let poly_ring_mat_3 = &poly_ring_mat_1 + poly_ring_mat_2;
433
434 assert_eq!(poly_ring_mat_3, poly_ring_mat_cmp);
435 }
436
437 #[test]
439 fn add_second_borrowed() {
440 let modulus = ModulusPolynomialRingZq::from_str("4 1 0 0 1 mod 17").unwrap();
441 let poly_mat_1 = MatPolyOverZ::from_str("[[4 -1 0 1 1, 1 42],[0, 2 1 2]]").unwrap();
442 let poly_ring_mat_1 = MatPolynomialRingZq::from((&poly_mat_1, &modulus));
443 let poly_mat_2 = MatPolyOverZ::from_str("[[3 3 0 1, 1 42],[0, 1 17]]").unwrap();
444 let poly_ring_mat_2 = MatPolynomialRingZq::from((&poly_mat_2, &modulus));
445 let poly_mat_cmp = MatPolyOverZ::from_str("[[3 1 0 2, 1 16],[0, 2 1 2]]").unwrap();
446 let poly_ring_mat_cmp = MatPolynomialRingZq::from((&poly_mat_cmp, &modulus));
447
448 let poly_ring_mat_3 = poly_ring_mat_1 + &poly_ring_mat_2;
449
450 assert_eq!(poly_ring_mat_3, poly_ring_mat_cmp);
451 }
452
453 #[test]
455 fn add_reduce() {
456 let modulus = ModulusPolynomialRingZq::from_str("4 1 0 0 1 mod 17").unwrap();
457 let poly_mat_1 = MatPolyOverZ::from_str("[[4 -1 0 1 1]]").unwrap();
458 let a = MatPolynomialRingZq::from((&poly_mat_1, &modulus));
459 let poly_mat_2 = MatPolyOverZ::from_str("[[4 2 0 3 -1]]").unwrap();
460 let b = MatPolynomialRingZq::from((&poly_mat_2, &modulus));
461 let c = a + &b;
462 assert_eq!(
463 c,
464 MatPolynomialRingZq::from((&MatPolyOverZ::from_str("[[3 1 0 4]]").unwrap(), &modulus))
465 );
466 }
467
468 #[test]
470 fn add_large_numbers() {
471 let modulus = ModulusPolynomialRingZq::from_str(&format!(
472 "5 1 1 0 0 {} mod {LARGE_PRIME}",
473 i64::MAX
474 ))
475 .unwrap();
476 let poly_mat_1 = MatPolyOverZ::from_str(&format!(
477 "[[4 1 {} 1 1, 1 42],[0, 2 {} 2]]",
478 i64::MAX,
479 i64::MIN
480 ))
481 .unwrap();
482 let poly_ring_mat_1 = MatPolynomialRingZq::from((&poly_mat_1, &modulus));
483 let poly_mat_2 = MatPolyOverZ::from_str("[[3 3 0 1, 1 42],[0, 1 17]]").unwrap();
484 let poly_ring_mat_2 = MatPolynomialRingZq::from((&poly_mat_2, &modulus));
485 let poly_mat_cmp = MatPolyOverZ::from_str(&format!(
486 "[[4 4 {} 2 1, 1 84],[0, 2 {} 2]]",
487 i64::MAX,
488 i64::MIN + 17
489 ))
490 .unwrap();
491 let poly_ring_mat_cmp = MatPolynomialRingZq::from((&poly_mat_cmp, &modulus));
492
493 let poly_ring_mat_3 = poly_ring_mat_1 + poly_ring_mat_2;
494
495 assert_eq!(poly_ring_mat_3, poly_ring_mat_cmp);
496 }
497
498 #[test]
500 #[should_panic]
501 fn add_mismatching_modulus_modulus() {
502 let modulus_1 = ModulusPolynomialRingZq::from_str("4 1 0 0 1 mod 11").unwrap();
503 let poly_mat_1 = MatPolyOverZ::from_str("[[4 -1 0 1 1, 1 42],[0, 2 1 2]]").unwrap();
504 let poly_ring_mat_1 = MatPolynomialRingZq::from((&poly_mat_1, &modulus_1));
505 let modulus_2 = ModulusPolynomialRingZq::from_str("4 1 0 0 1 mod 17").unwrap();
506 let poly_mat_2 = MatPolyOverZ::from_str("[[3 3 0 1, 1 42],[0, 1 17]]").unwrap();
507 let poly_ring_mat_2 = MatPolynomialRingZq::from((&poly_mat_2, &modulus_2));
508
509 let _ = poly_ring_mat_1 + poly_ring_mat_2;
510 }
511
512 #[test]
514 #[should_panic]
515 fn add_mismatching_modulus_polynomial() {
516 let modulus_1 = ModulusPolynomialRingZq::from_str("4 1 0 0 2 mod 17").unwrap();
517 let poly_mat_1 = MatPolyOverZ::from_str("[[4 -1 0 1 1, 1 42],[0, 2 1 2]]").unwrap();
518 let poly_ring_mat_1 = MatPolynomialRingZq::from((&poly_mat_1, &modulus_1));
519 let modulus_2 = ModulusPolynomialRingZq::from_str("4 1 0 0 1 mod 17").unwrap();
520 let poly_mat_2 = MatPolyOverZ::from_str("[[3 3 0 1, 1 42],[0, 1 17]]").unwrap();
521 let poly_ring_mat_2 = MatPolynomialRingZq::from((&poly_mat_2, &modulus_2));
522
523 let _ = poly_ring_mat_1 + poly_ring_mat_2;
524 }
525
526 #[test]
528 #[should_panic]
529 fn add_mismatching_dim() {
530 let modulus_1 = ModulusPolynomialRingZq::from_str("4 1 0 0 2 mod 17").unwrap();
531 let poly_mat_1 = MatPolyOverZ::from_str("[[1 42],[2 1 2]]").unwrap();
532 let poly_ring_mat_1 = MatPolynomialRingZq::from((&poly_mat_1, &modulus_1));
533 let modulus_2 = ModulusPolynomialRingZq::from_str("4 1 0 0 1 mod 17").unwrap();
534 let poly_mat_2 = MatPolyOverZ::from_str("[[3 3 0 1, 1 42]]").unwrap();
535 let poly_ring_mat_2 = MatPolynomialRingZq::from((&poly_mat_2, &modulus_2));
536
537 let _ = poly_ring_mat_1 + poly_ring_mat_2;
538 }
539
540 #[test]
542 fn add_safe_is_err_moduli() {
543 let modulus_1 = ModulusPolynomialRingZq::from_str("4 1 0 0 2 mod 17").unwrap();
544 let poly_mat_1 = MatPolyOverZ::from_str("[[4 -1 0 1 1, 1 42],[0, 2 1 2]]").unwrap();
545 let poly_ring_mat_1 = MatPolynomialRingZq::from((&poly_mat_1, &modulus_1));
546 let modulus_2 = ModulusPolynomialRingZq::from_str("4 1 0 0 1 mod 17").unwrap();
547 let poly_mat_2 = MatPolyOverZ::from_str("[[3 3 0 1, 1 42],[0, 1 17]]").unwrap();
548 let poly_ring_mat_2 = MatPolynomialRingZq::from((&poly_mat_2, &modulus_2));
549
550 assert!(&poly_ring_mat_1.add_safe(&poly_ring_mat_2).is_err());
551 }
552
553 #[test]
555 fn add_safe_is_err_dim() {
556 let modulus_1 = ModulusPolynomialRingZq::from_str("4 1 0 0 2 mod 17").unwrap();
557 let poly_mat_1 = MatPolyOverZ::from_str("[[4 -1 0 1 1],[2 1 2]]").unwrap();
558 let poly_ring_mat_1 = MatPolynomialRingZq::from((&poly_mat_1, &modulus_1));
559 let modulus_2 = ModulusPolynomialRingZq::from_str("4 1 0 0 1 mod 17").unwrap();
560 let poly_mat_2 = MatPolyOverZ::from_str("[[3 3 0 1, 1 42],[0, 1 17]]").unwrap();
561 let poly_ring_mat_2 = MatPolynomialRingZq::from((&poly_mat_2, &modulus_2));
562
563 assert!(&poly_ring_mat_1.add_safe(&poly_ring_mat_2).is_err());
564 }
565}
566
567#[cfg(test)]
568mod test_mul_mat_poly_over_z {
569 use super::MatPolynomialRingZq;
570 use crate::{integer::MatPolyOverZ, integer_mod_q::ModulusPolynomialRingZq};
571 use std::str::FromStr;
572
573 const LARGE_PRIME: u64 = u64::MAX - 58;
574
575 #[test]
577 fn availability() {
578 let modulus = ModulusPolynomialRingZq::from_str("4 1 0 0 1 mod 17").unwrap();
579 let poly_mat = MatPolyOverZ::from_str("[[3 0 1 1, 1 3],[0, 2 1 2]]").unwrap();
580 let poly_ring_mat = MatPolynomialRingZq::from((&poly_mat, &modulus));
581
582 let _ = &poly_mat + &poly_ring_mat;
583 let _ = &poly_mat + poly_ring_mat.clone();
584 let _ = poly_mat.clone() + &poly_ring_mat;
585 let _ = poly_mat.clone() + poly_ring_mat.clone();
586
587 let _ = &poly_ring_mat + &poly_mat;
588 let _ = &poly_ring_mat + poly_mat.clone();
589 let _ = poly_ring_mat.clone() + &poly_mat;
590 let _ = poly_ring_mat + poly_mat;
591 }
592
593 #[test]
595 fn square_correctness() {
596 let modulus = ModulusPolynomialRingZq::from_str("4 1 0 0 1 mod 17").unwrap();
597 let poly_mat_1 = MatPolyOverZ::from_str("[[2 1 1, 1 42],[0, 2 1 2]]").unwrap();
598 let poly_ring_mat_1 = MatPolynomialRingZq::from((&poly_mat_1, &modulus));
599 let poly_mat_2 = MatPolyOverZ::from_str("[[3 3 0 1, 1 42],[0, 1 17]]").unwrap();
600
601 let poly_ring_mat_3 = &poly_ring_mat_1 + &poly_mat_2;
602
603 let poly_mat_cmp = MatPolyOverZ::from_str("[[3 4 1 1, 1 84],[0, 2 18 2]]").unwrap();
604 let poly_ring_mat_cmp = MatPolynomialRingZq::from((&poly_mat_cmp, &modulus));
605
606 assert_eq!(poly_ring_mat_cmp, poly_ring_mat_3);
607 }
608
609 #[test]
611 fn large_entries() {
612 let modulus =
613 ModulusPolynomialRingZq::from_str(&format!("4 1 0 0 1 mod {LARGE_PRIME}")).unwrap();
614 let poly_mat_1 = MatPolyOverZ::from_str(&format!("[[2 3 {}],[1 1]]", u64::MAX)).unwrap();
615 let poly_ring_mat_1 = MatPolynomialRingZq::from((&poly_mat_1, &modulus));
616 let poly_mat_2 = MatPolyOverZ::from_str(&format!("[[2 1 {}],[0]]", u64::MAX)).unwrap();
617
618 let poly_ring_mat_3 = &poly_ring_mat_1 + &poly_mat_2;
619
620 let poly_mat_cmp =
621 MatPolyOverZ::from_str(&format!("[[2 4 {}],[1 1]]", u128::from(u64::MAX) * 2))
622 .unwrap();
623 let poly_ring_mat_cmp = MatPolynomialRingZq::from((&poly_mat_cmp, &modulus));
624
625 assert_eq!(poly_ring_mat_cmp, poly_ring_mat_3);
626 }
627
628 #[test]
631 fn errors() {
632 let modulus_1 = ModulusPolynomialRingZq::from_str("4 1 0 0 1 mod 17").unwrap();
633 let poly_mat_1 = MatPolyOverZ::from_str("[[4 -1 0 1 1],[2 1 2]]").unwrap();
634 let poly_ring_mat_1 = MatPolynomialRingZq::from((&poly_mat_1, &modulus_1));
635 let poly_mat_2 = MatPolyOverZ::from_str("[[4 -1 0 1 1, 1 1],[2 1 2, 1 1]]").unwrap();
636
637 assert!((poly_ring_mat_1.add_mat_poly_over_z_safe(&poly_mat_2)).is_err());
638 }
639
640 #[test]
642 #[should_panic]
643 fn mul_panic() {
644 let modulus_1 = ModulusPolynomialRingZq::from_str("4 1 0 0 1 mod 17").unwrap();
645 let poly_mat_1 = MatPolyOverZ::from_str("[[1 3],[2 1 2]]").unwrap();
646 let poly_ring_mat_1 = MatPolynomialRingZq::from((&poly_mat_1, &modulus_1));
647 let poly_mat_2 = MatPolyOverZ::from_str("[[4 -1 0 1 1, 1 1],[2 1 2, 1 1]]").unwrap();
648
649 let _ = &poly_ring_mat_1 + &poly_mat_2;
650 }
651}