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 =
472 ModulusPolynomialRingZq::from_str(&format!("5 1 1 0 0 1 mod {LARGE_PRIME}")).unwrap();
473 let poly_mat_1 = MatPolyOverZ::from_str(&format!(
474 "[[4 1 {} 1 1, 1 42],[0, 2 {} 2]]",
475 i64::MAX,
476 i64::MIN
477 ))
478 .unwrap();
479 let poly_ring_mat_1 = MatPolynomialRingZq::from((&poly_mat_1, &modulus));
480 let poly_mat_2 = MatPolyOverZ::from_str("[[3 3 0 1, 1 42],[0, 1 17]]").unwrap();
481 let poly_ring_mat_2 = MatPolynomialRingZq::from((&poly_mat_2, &modulus));
482 let poly_mat_cmp = MatPolyOverZ::from_str(&format!(
483 "[[4 4 {} 2 1, 1 84],[0, 2 {} 2]]",
484 i64::MAX,
485 i64::MIN + 17
486 ))
487 .unwrap();
488 let poly_ring_mat_cmp = MatPolynomialRingZq::from((&poly_mat_cmp, &modulus));
489
490 let poly_ring_mat_3 = poly_ring_mat_1 + poly_ring_mat_2;
491
492 assert_eq!(poly_ring_mat_3, poly_ring_mat_cmp);
493 }
494
495 #[test]
497 #[should_panic]
498 fn add_mismatching_modulus_modulus() {
499 let modulus_1 = ModulusPolynomialRingZq::from_str("4 1 0 0 1 mod 11").unwrap();
500 let poly_mat_1 = MatPolyOverZ::from_str("[[4 -1 0 1 1, 1 42],[0, 2 1 2]]").unwrap();
501 let poly_ring_mat_1 = MatPolynomialRingZq::from((&poly_mat_1, &modulus_1));
502 let modulus_2 = ModulusPolynomialRingZq::from_str("4 1 0 0 1 mod 17").unwrap();
503 let poly_mat_2 = MatPolyOverZ::from_str("[[3 3 0 1, 1 42],[0, 1 17]]").unwrap();
504 let poly_ring_mat_2 = MatPolynomialRingZq::from((&poly_mat_2, &modulus_2));
505
506 let _ = poly_ring_mat_1 + poly_ring_mat_2;
507 }
508
509 #[test]
511 #[should_panic]
512 fn add_mismatching_modulus_polynomial() {
513 let modulus_1 = ModulusPolynomialRingZq::from_str("4 2 0 0 1 mod 17").unwrap();
514 let poly_mat_1 = MatPolyOverZ::from_str("[[4 -1 0 1 1, 1 42],[0, 2 1 2]]").unwrap();
515 let poly_ring_mat_1 = MatPolynomialRingZq::from((&poly_mat_1, &modulus_1));
516 let modulus_2 = ModulusPolynomialRingZq::from_str("4 1 0 0 1 mod 17").unwrap();
517 let poly_mat_2 = MatPolyOverZ::from_str("[[3 3 0 1, 1 42],[0, 1 17]]").unwrap();
518 let poly_ring_mat_2 = MatPolynomialRingZq::from((&poly_mat_2, &modulus_2));
519
520 let _ = poly_ring_mat_1 + poly_ring_mat_2;
521 }
522
523 #[test]
525 #[should_panic]
526 fn add_mismatching_dim() {
527 let modulus_1 = ModulusPolynomialRingZq::from_str("4 1 0 0 1 mod 17").unwrap();
528 let poly_mat_1 = MatPolyOverZ::from_str("[[1 42],[2 1 2]]").unwrap();
529 let poly_ring_mat_1 = MatPolynomialRingZq::from((&poly_mat_1, &modulus_1));
530 let modulus_2 = ModulusPolynomialRingZq::from_str("4 1 0 0 1 mod 17").unwrap();
531 let poly_mat_2 = MatPolyOverZ::from_str("[[3 3 0 1, 1 42]]").unwrap();
532 let poly_ring_mat_2 = MatPolynomialRingZq::from((&poly_mat_2, &modulus_2));
533
534 let _ = poly_ring_mat_1 + poly_ring_mat_2;
535 }
536
537 #[test]
539 fn add_safe_is_err_moduli() {
540 let modulus_1 = ModulusPolynomialRingZq::from_str("4 1 0 0 1 mod 17").unwrap();
541 let poly_mat_1 = MatPolyOverZ::from_str("[[4 -1 0 1 1, 1 42],[0, 2 1 2]]").unwrap();
542 let poly_ring_mat_1 = MatPolynomialRingZq::from((&poly_mat_1, &modulus_1));
543 let modulus_2 = ModulusPolynomialRingZq::from_str("4 2 0 0 1 mod 17").unwrap();
544 let poly_mat_2 = MatPolyOverZ::from_str("[[3 3 0 1, 1 42],[0, 1 17]]").unwrap();
545 let poly_ring_mat_2 = MatPolynomialRingZq::from((&poly_mat_2, &modulus_2));
546
547 assert!(&poly_ring_mat_1.add_safe(&poly_ring_mat_2).is_err());
548 }
549
550 #[test]
552 fn add_safe_is_err_dim() {
553 let modulus_1 = ModulusPolynomialRingZq::from_str("4 1 0 0 1 mod 17").unwrap();
554 let poly_mat_1 = MatPolyOverZ::from_str("[[4 -1 0 1 1],[2 1 2]]").unwrap();
555 let poly_ring_mat_1 = MatPolynomialRingZq::from((&poly_mat_1, &modulus_1));
556 let modulus_2 = ModulusPolynomialRingZq::from_str("4 1 0 0 1 mod 17").unwrap();
557 let poly_mat_2 = MatPolyOverZ::from_str("[[3 3 0 1, 1 42],[0, 1 17]]").unwrap();
558 let poly_ring_mat_2 = MatPolynomialRingZq::from((&poly_mat_2, &modulus_2));
559
560 assert!(&poly_ring_mat_1.add_safe(&poly_ring_mat_2).is_err());
561 }
562}
563
564#[cfg(test)]
565mod test_mul_mat_poly_over_z {
566 use super::MatPolynomialRingZq;
567 use crate::{integer::MatPolyOverZ, integer_mod_q::ModulusPolynomialRingZq};
568 use std::str::FromStr;
569
570 const LARGE_PRIME: u64 = u64::MAX - 58;
571
572 #[test]
574 fn availability() {
575 let modulus = ModulusPolynomialRingZq::from_str("4 1 0 0 1 mod 17").unwrap();
576 let poly_mat = MatPolyOverZ::from_str("[[3 0 1 1, 1 3],[0, 2 1 2]]").unwrap();
577 let poly_ring_mat = MatPolynomialRingZq::from((&poly_mat, &modulus));
578
579 let _ = &poly_mat + &poly_ring_mat;
580 let _ = &poly_mat + poly_ring_mat.clone();
581 let _ = poly_mat.clone() + &poly_ring_mat;
582 let _ = poly_mat.clone() + poly_ring_mat.clone();
583
584 let _ = &poly_ring_mat + &poly_mat;
585 let _ = &poly_ring_mat + poly_mat.clone();
586 let _ = poly_ring_mat.clone() + &poly_mat;
587 let _ = poly_ring_mat + poly_mat;
588 }
589
590 #[test]
592 fn square_correctness() {
593 let modulus = ModulusPolynomialRingZq::from_str("4 1 0 0 1 mod 17").unwrap();
594 let poly_mat_1 = MatPolyOverZ::from_str("[[2 1 1, 1 42],[0, 2 1 2]]").unwrap();
595 let poly_ring_mat_1 = MatPolynomialRingZq::from((&poly_mat_1, &modulus));
596 let poly_mat_2 = MatPolyOverZ::from_str("[[3 3 0 1, 1 42],[0, 1 17]]").unwrap();
597
598 let poly_ring_mat_3 = &poly_ring_mat_1 + &poly_mat_2;
599
600 let poly_mat_cmp = MatPolyOverZ::from_str("[[3 4 1 1, 1 84],[0, 2 18 2]]").unwrap();
601 let poly_ring_mat_cmp = MatPolynomialRingZq::from((&poly_mat_cmp, &modulus));
602
603 assert_eq!(poly_ring_mat_cmp, poly_ring_mat_3);
604 }
605
606 #[test]
608 fn large_entries() {
609 let modulus =
610 ModulusPolynomialRingZq::from_str(&format!("4 1 0 0 1 mod {LARGE_PRIME}")).unwrap();
611 let poly_mat_1 = MatPolyOverZ::from_str(&format!("[[2 3 {}],[1 1]]", u64::MAX)).unwrap();
612 let poly_ring_mat_1 = MatPolynomialRingZq::from((&poly_mat_1, &modulus));
613 let poly_mat_2 = MatPolyOverZ::from_str(&format!("[[2 1 {}],[0]]", u64::MAX)).unwrap();
614
615 let poly_ring_mat_3 = &poly_ring_mat_1 + &poly_mat_2;
616
617 let poly_mat_cmp =
618 MatPolyOverZ::from_str(&format!("[[2 4 {}],[1 1]]", u128::from(u64::MAX) * 2))
619 .unwrap();
620 let poly_ring_mat_cmp = MatPolynomialRingZq::from((&poly_mat_cmp, &modulus));
621
622 assert_eq!(poly_ring_mat_cmp, poly_ring_mat_3);
623 }
624
625 #[test]
628 fn errors() {
629 let modulus_1 = ModulusPolynomialRingZq::from_str("4 1 0 0 1 mod 17").unwrap();
630 let poly_mat_1 = MatPolyOverZ::from_str("[[4 -1 0 1 1],[2 1 2]]").unwrap();
631 let poly_ring_mat_1 = MatPolynomialRingZq::from((&poly_mat_1, &modulus_1));
632 let poly_mat_2 = MatPolyOverZ::from_str("[[4 -1 0 1 1, 1 1],[2 1 2, 1 1]]").unwrap();
633
634 assert!((poly_ring_mat_1.add_mat_poly_over_z_safe(&poly_mat_2)).is_err());
635 }
636
637 #[test]
639 #[should_panic]
640 fn mul_panic() {
641 let modulus_1 = ModulusPolynomialRingZq::from_str("4 1 0 0 1 mod 17").unwrap();
642 let poly_mat_1 = MatPolyOverZ::from_str("[[1 3],[2 1 2]]").unwrap();
643 let poly_ring_mat_1 = MatPolynomialRingZq::from((&poly_mat_1, &modulus_1));
644 let poly_mat_2 = MatPolyOverZ::from_str("[[4 -1 0 1 1, 1 1],[2 1 2, 1 1]]").unwrap();
645
646 let _ = &poly_ring_mat_1 + &poly_mat_2;
647 }
648}