1use crate::ring::zq::Zq;
22use core::ops::{Add, Mul, Sub};
23use rand::distr::{Distribution, Uniform};
24use rand::{CryptoRng, Rng};
25use rustfft::num_complex::Complex;
26use rustfft::FftPlanner;
27
28#[derive(Debug, Clone, PartialEq, Eq)]
31pub struct Rq {
32 coeffs: [Zq; Self::DEGREE],
33}
34
35impl Rq {
36 pub const DEGREE: usize = 64;
37 pub const fn new(coeffs: [Zq; Self::DEGREE]) -> Self {
39 Rq { coeffs }
40 }
41
42 pub const fn zero() -> Self {
44 Self {
45 coeffs: [Zq::ZERO; Self::DEGREE],
46 }
47 }
48
49 pub fn into_coeffs(self) -> [Zq; Self::DEGREE] {
50 self.coeffs
51 }
52
53 pub fn get_coefficients(&self) -> &[Zq; Self::DEGREE] {
55 &self.coeffs
56 }
57
58 pub fn random<R: Rng + CryptoRng>(rng: &mut R) -> Self {
60 let uniform = Uniform::new_inclusive(Zq::ZERO, Zq::NEG_ONE).unwrap();
61 let mut coeffs = [Zq::ZERO; Self::DEGREE];
62 coeffs.iter_mut().for_each(|c| *c = uniform.sample(rng));
63 Self { coeffs }
64 }
65
66 pub fn random_with_bound<R: Rng + CryptoRng>(rng: &mut R, bound: u32) -> Self {
68 let uniform = Uniform::new_inclusive(Zq::ZERO, Zq::new(bound)).unwrap();
69 let mut coeffs = [Zq::ZERO; Self::DEGREE];
70 coeffs.iter_mut().for_each(|c| {
71 *c = if rng.random_bool(0.5) {
72 -uniform.sample(rng)
73 } else {
74 uniform.sample(rng)
75 }
76 });
77 Self { coeffs }
78 }
79
80 #[allow(clippy::as_conversions)]
81 pub fn l2_norm_squared(&self) -> Zq {
82 self.coeffs
83 .iter()
84 .map(|coeff| {
85 coeff.centered_mod(Zq::new(Zq::Q as u32))
86 * coeff.centered_mod(Zq::new(Zq::Q as u32))
87 })
88 .sum()
89 }
90
91 pub fn decompose(&self, base: Zq, num_parts: usize) -> Vec<Rq> {
95 debug_assert!(num_parts > 0, "num_parts must be positive");
96 let mut parts = Vec::with_capacity(num_parts);
97 let mut initial_coeffs = *self.get_coefficients();
98
99 for _ in 0..num_parts - 1 {
100 let mut low_coeffs = [Zq::ZERO; Self::DEGREE];
102
103 for (low_c, coeff) in low_coeffs.iter_mut().zip(initial_coeffs.iter_mut()) {
104 let centered = coeff.centered_mod(base);
105 *low_c = centered;
106 *coeff = (*coeff - centered).scale_by(base);
107 }
108 parts.push(Self::new(low_coeffs));
109 }
110 parts.push(Self::new(initial_coeffs));
111 parts
112 }
113
114 pub fn conjugate_automorphism(&self) -> Self {
116 let q_minus_1 = Zq::NEG_ONE;
117
118 let original_coefficients = self.get_coefficients();
119
120 let mut conjugated_coeffs = [Zq::ZERO; Rq::DEGREE];
121 conjugated_coeffs[0] = original_coefficients[0];
122
123 for (conj_coeff, original_coeff) in conjugated_coeffs
124 .iter_mut()
125 .skip(1)
126 .zip(original_coefficients.iter().rev())
127 {
128 *conj_coeff = original_coeff * q_minus_1;
129 }
130
131 Self::new(conjugated_coeffs)
132 }
133
134 #[allow(clippy::as_conversions)]
142 pub fn operator_norm(&self) -> f64 {
143 let coeffs = self.get_coefficients();
144 let n = coeffs.len();
145 let mut planner = FftPlanner::new();
146 let fft = planner.plan_fft_forward(n);
147
148 let mut buffer: Vec<Complex<f64>> = coeffs
150 .iter()
151 .map(|&x| {
152 let half = Zq::NEG_ONE.scale_by(Zq::TWO);
153 let converted_value = if x > half {
154 x.to_u128() as f64 - Zq::NEG_ONE.to_u128() as f64 - 1.0
155 } else {
156 x.to_u128() as f64
157 };
158 Complex {
159 re: converted_value,
160 im: 0.0,
161 }
162 })
163 .collect();
164
165 fft.process(&mut buffer);
167
168 buffer
170 .iter()
171 .map(|c| c.norm())
172 .fold(0.0, |max, x| max.max(x))
173 }
174}
175
176impl Add<&Rq> for &Rq {
177 type Output = Rq;
178 fn add(self, other: &Rq) -> Rq {
180 let mut coeffs = [Zq::ZERO; Rq::DEGREE];
181 for (r, (a, b)) in coeffs
182 .iter_mut()
183 .zip(self.coeffs.iter().zip(other.coeffs.iter()))
184 {
185 *r = *a + *b;
186 }
187 Rq::new(coeffs)
188 }
189}
190
191impl Sub<&Rq> for &Rq {
192 type Output = Rq;
193 fn sub(self, other: &Rq) -> Rq {
195 let mut coeffs = [Zq::ZERO; Rq::DEGREE];
196 for (r, (a, b)) in coeffs
197 .iter_mut()
198 .zip(self.coeffs.iter().zip(other.coeffs.iter()))
199 {
200 *r = *a - *b;
201 }
202 Rq::new(coeffs)
203 }
204}
205
206impl Mul<&Rq> for &Rq {
207 type Output = Rq;
208 fn mul(self, other: &Rq) -> Rq {
210 let mut result = [Zq::ZERO; Rq::DEGREE];
211 let mut out_of_field = [Zq::ZERO; Rq::DEGREE];
212 for (i, &self_coeff) in self.coeffs.iter().enumerate() {
213 for (j, &other_coeff) in other.coeffs.iter().enumerate() {
214 if i + j < Rq::DEGREE {
215 result[i + j] += self_coeff * other_coeff;
216 } else {
217 out_of_field[(i + j) % Rq::DEGREE] += self_coeff * other_coeff;
218 }
219 }
220 }
221 for i in (0..Rq::DEGREE).rev() {
223 result[i] -= out_of_field[i];
224 }
225 Rq::new(result)
226 }
227}
228
229impl Mul<&Zq> for &Rq {
230 type Output = Rq;
231 fn mul(self, other: &Zq) -> Rq {
233 let mut copied_coeffs = self.coeffs;
234 for elem in copied_coeffs.iter_mut() {
235 *elem *= *other;
236 }
237 Rq::new(copied_coeffs)
238 }
239}
240
241#[cfg(test)]
242pub mod tests {
243 use super::*;
244
245 pub fn generate_rq_from_zq_vector(vec: Vec<Zq>) -> Rq {
246 let mut temp = [Zq::ZERO; Rq::DEGREE];
247 for i in (0..vec.len()).rev() {
249 let m = i / Rq::DEGREE;
250 let r = i % Rq::DEGREE;
251 let sign = if m % 2 == 0 { 1 } else { -1 };
252 if sign == 1 {
253 temp[r] += vec[i];
254 } else {
255 temp[r] -= vec[i];
256 }
257 }
258 Rq::new(temp)
259 }
260
261 mod helper {
262 use super::*;
263 pub fn padded(prefix: &[Zq]) -> [Zq; Rq::DEGREE] {
264 assert!(
265 prefix.len() <= Rq::DEGREE,
266 "too many coefficients for degree {}",
267 Rq::DEGREE
268 );
269
270 let mut out = [Zq::ZERO; Rq::DEGREE];
271 out[..prefix.len()].copy_from_slice(prefix);
272 out
273 }
274
275 pub fn rq_from(prefix: &[Zq]) -> Rq {
276 Rq {
277 coeffs: padded(prefix),
278 }
279 }
280 }
281
282 #[test]
284 fn test_new_and_create_poly() {
285 let coeffs = [Zq::ONE, Zq::new(2), Zq::new(3), Zq::new(4)];
286 let poly = helper::rq_from(&coeffs);
287 assert_eq!(poly.coeffs, helper::padded(&coeffs));
288
289 let coeffs2 = [Zq::ONE, Zq::new(2), Zq::new(3), Zq::new(4)];
291 let poly_from_vec_direct: Rq = generate_rq_from_zq_vector(coeffs.to_vec());
292 assert_eq!(poly_from_vec_direct.coeffs, helper::padded(&coeffs2));
293 }
294
295 #[test]
296 fn test_into_coeffs_returns_correct() {
297 let mut coeffs = [Zq::ZERO; Rq::DEGREE];
298 coeffs[0] = Zq::ONE;
299 coeffs[0] = Zq::new(20);
300 coeffs[0] = Zq::new(3121);
301 coeffs[0] = Zq::new(40);
302 let poly: Rq = generate_rq_from_zq_vector(coeffs.to_vec());
303
304 let result = Rq::into_coeffs(poly); assert_eq!(result, coeffs);
306 }
307
308 #[test]
310 fn test_add() {
311 let poly1: Rq =
313 generate_rq_from_zq_vector(vec![Zq::ONE, Zq::new(2), Zq::new(3), Zq::new(4)]);
314 let poly2: Rq =
315 generate_rq_from_zq_vector(vec![Zq::new(4), Zq::new(3), Zq::new(2), Zq::ONE]);
316 let result = &poly1 + &poly2;
317 assert_eq!(
318 result.coeffs,
319 helper::padded(&[Zq::new(5), Zq::new(5), Zq::new(5), Zq::new(5)])
320 );
321
322 let poly3: Rq =
324 generate_rq_from_zq_vector(vec![Zq::ONE, Zq::new(2), Zq::new(3), Zq::new(4)]);
325 let poly4: Rq =
326 generate_rq_from_zq_vector(vec![Zq::NEG_ONE, Zq::new(3), Zq::NEG_ONE, Zq::ONE]);
327 let result2 = &poly3 + &poly4;
328 assert_eq!(
329 result2.coeffs,
330 helper::padded(&[Zq::ZERO, Zq::new(5), Zq::new(2), Zq::new(5)])
331 );
332 let poly5: Rq =
334 generate_rq_from_zq_vector(vec![Zq::ONE, Zq::new(2), Zq::new(3), Zq::new(4)]);
335 let poly6: Rq = generate_rq_from_zq_vector(vec![Zq::ZERO]);
336 let result3 = &poly5 + &poly6;
337 assert_eq!(
338 result3.coeffs,
339 helper::padded(&[Zq::ONE, Zq::new(2), Zq::new(3), Zq::new(4)])
340 );
341 let poly7: Rq =
343 generate_rq_from_zq_vector(vec![Zq::ONE, Zq::new(2), Zq::new(3), Zq::NEG_ONE]);
344 let poly8: Rq =
345 generate_rq_from_zq_vector(vec![Zq::NEG_ONE, Zq::NEG_ONE, Zq::NEG_ONE, Zq::NEG_ONE]);
346 let result3 = &poly7 + &poly8;
347 assert_eq!(
348 result3.coeffs,
349 helper::padded(&[Zq::ZERO, Zq::ONE, Zq::new(2), -Zq::new(2)])
350 );
351 }
352
353 #[test]
355 fn test_mul() {
356 let poly1: Rq = generate_rq_from_zq_vector(vec![Zq::ONE, Zq::ONE, Zq::new(2)]);
358 let poly2: Rq = generate_rq_from_zq_vector(vec![Zq::ONE, Zq::ONE]);
359 let result = &poly1 * &poly2;
360 assert_eq!(
361 result.coeffs,
362 helper::padded(&[Zq::new(1), Zq::new(2), Zq::new(3), Zq::new(2)])
363 );
364
365 let poly3: Rq = generate_rq_from_zq_vector(vec![Zq::ONE, Zq::ONE, Zq::new(2)]);
367 let poly4: Rq = generate_rq_from_zq_vector(vec![Zq::ZERO]);
368 let result2 = &poly3 * &poly4;
369 assert_eq!(
370 result2.coeffs,
371 helper::padded(&[Zq::ZERO, Zq::ZERO, Zq::ZERO])
372 );
373
374 }
384
385 #[test]
387 fn test_sub() {
388 let poly1: Rq =
390 generate_rq_from_zq_vector(vec![Zq::new(5), Zq::new(10), Zq::new(15), Zq::new(20)]);
391 let poly2: Rq =
392 generate_rq_from_zq_vector(vec![Zq::new(2), Zq::new(4), Zq::new(6), Zq::new(8)]);
393 let result = &poly1 - &poly2;
394 assert_eq!(
395 result.coeffs,
396 helper::padded(&[Zq::new(3), Zq::new(6), Zq::new(9), Zq::new(12)])
397 );
398
399 let poly3: Rq = generate_rq_from_zq_vector(vec![Zq::ONE, Zq::ONE, Zq::new(3), Zq::new(2)]);
401 let poly4: Rq =
402 generate_rq_from_zq_vector(vec![Zq::new(2), Zq::new(4), Zq::new(6), Zq::new(8)]);
403 let result2 = &poly3 - &poly4;
404 assert_eq!(
405 result2.coeffs,
406 helper::padded(&[
407 Zq::ZERO - Zq::new(1),
408 Zq::ZERO - Zq::new(3),
409 Zq::ZERO - Zq::new(3),
410 Zq::ZERO - Zq::new(6),
411 ])
412 );
413 let poly5: Rq =
415 generate_rq_from_zq_vector(vec![Zq::ONE, Zq::new(2), Zq::new(3), Zq::new(4)]);
416 let poly6: Rq = generate_rq_from_zq_vector(vec![Zq::ZERO]);
417 let result3 = &poly6 - &poly5;
418 let result4 = &poly5 - &poly6;
419 assert_eq!(
420 result3.coeffs,
421 helper::padded(&[
422 Zq::ZERO - Zq::new(1),
423 Zq::ZERO - Zq::new(2),
424 Zq::ZERO - Zq::new(3),
425 Zq::ZERO - Zq::new(4),
426 ])
427 );
428 assert_eq!(
429 result4.coeffs,
430 helper::padded(&[Zq::ONE, Zq::new(2), Zq::new(3), Zq::new(4)])
431 );
432 }
433
434 #[test]
436 fn test_scalar_mul() {
437 let poly: Rq =
438 generate_rq_from_zq_vector(vec![Zq::ONE, Zq::new(2), Zq::new(3), Zq::new(4)]);
439 let result = &poly * &Zq::new(2);
440 assert_eq!(
441 result.coeffs,
442 helper::padded(&[Zq::new(2), Zq::new(4), Zq::new(6), Zq::new(8)])
443 );
444 }
445
446 #[test]
448 fn test_get_coefficient() {
449 let poly: Rq = generate_rq_from_zq_vector(vec![Zq::ONE, Zq::ZERO, Zq::new(5), Zq::NEG_ONE]);
450 let vec = helper::padded(&[Zq::ONE, Zq::ZERO, Zq::new(5), Zq::NEG_ONE]).to_vec();
451 assert!(poly.get_coefficients().to_vec() == vec);
452
453 let poly_zero: Rq =
454 generate_rq_from_zq_vector(vec![Zq::ZERO, Zq::ZERO, Zq::ZERO, Zq::ZERO]);
455 let vec_zero = helper::padded(&[Zq::ZERO, Zq::ZERO, Zq::ZERO, Zq::ZERO]).to_vec();
456 assert!(poly_zero.get_coefficients().to_vec() == vec_zero);
457 }
458
459 #[test]
460 fn test_base2_decomposition() {
461 let poly: Rq =
463 generate_rq_from_zq_vector(vec![Zq::new(5), Zq::new(3), Zq::new(7), Zq::new(1)]);
464 let parts = poly.decompose(Zq::TWO, 2);
465
466 assert_eq!(
468 parts[0].coeffs,
469 helper::padded(&[
470 Zq::ONE, Zq::ONE, Zq::ONE, Zq::ONE, ])
475 );
476
477 assert_eq!(
479 parts[1].coeffs,
480 helper::padded(&[
481 Zq::new(2), Zq::ONE, Zq::new(3), Zq::ZERO, ])
486 );
487
488 for i in 0..4 {
490 let expected = poly.coeffs[i];
491 let actual = parts[0].coeffs[i] + parts[1].coeffs[i] * Zq::TWO;
492 assert_eq!(actual, expected, "Base 2: Coefficient {} mismatch", i);
493 }
494 }
495
496 #[test]
497 fn test_base3_decomposition() {
498 let specific_poly: Rq =
500 generate_rq_from_zq_vector(vec![Zq::new(8), Zq::new(11), Zq::new(4), Zq::new(15)]);
501 let parts = specific_poly.decompose(Zq::new(3), 2);
502
503 assert_eq!(
505 parts[0].coeffs,
506 helper::padded(&[
507 Zq::NEG_ONE, Zq::NEG_ONE, Zq::ONE, Zq::ZERO, ])
512 );
513
514 assert_eq!(
516 parts[1].coeffs,
517 helper::padded(&[
518 Zq::new(3), Zq::new(4), Zq::ONE, Zq::new(5), ])
523 );
524
525 for i in 0..4 {
527 let expected = specific_poly.coeffs[i];
528 let p0 = parts[0].coeffs[i];
529 let p1 = parts[1].coeffs[i];
530 let actual = p0 + p1 * Zq::new(3);
531 assert_eq!(actual, expected, "Base 3: Coefficient {} mismatch", i);
532 }
533 }
534
535 #[test]
536 fn test_decomposition_edge_cases() {
537 let zero_poly: Rq = generate_rq_from_zq_vector(vec![Zq::ZERO; 4]);
539 let parts = zero_poly.decompose(Zq::TWO, 2);
540 assert!(
541 parts
543 .iter()
544 .all(|p| p.get_coefficients().iter().all(|&coeff| coeff == Zq::ZERO)),
545 "Zero polynomial decomposition failed"
546 );
547
548 let simple_poly: Rq =
550 generate_rq_from_zq_vector(vec![Zq::ONE, Zq::new(2), Zq::new(3), Zq::new(4)]);
551 let parts = simple_poly.decompose(Zq::TWO, 1);
552 assert_eq!(parts.len(), 1, "Single part decomposition length incorrect");
553 assert_eq!(
554 parts[0], simple_poly,
555 "Single part decomposition value incorrect"
556 );
557 }
558
559 #[test]
560 fn test_large_base_decomposition() {
561 let poly: Rq =
563 generate_rq_from_zq_vector(vec![Zq::new(120), Zq::new(33), Zq::new(255), Zq::new(19)]);
564
565 let parts_base8 = poly.decompose(Zq::new(8), 2);
567
568 assert_eq!(
570 parts_base8[0].coeffs,
571 helper::padded(&[
572 Zq::ZERO, Zq::ONE, Zq::NEG_ONE, Zq::new(3), ])
577 );
578
579 assert_eq!(
581 parts_base8[1].coeffs,
582 helper::padded(&[
583 Zq::new(15), Zq::new(4), Zq::new(32), Zq::new(2), ])
588 );
589
590 for i in 0..4 {
592 let expected = poly.coeffs[i];
593 let p0 = parts_base8[0].coeffs[i];
594 let p1 = parts_base8[1].coeffs[i];
595 let actual = p0 + p1 * Zq::new(8);
596 assert_eq!(actual, expected, "Base 8: Coefficient {} mismatch", i);
597 }
598
599 let parts_base16 = poly.decompose(Zq::new(16), 2);
601
602 for i in 0..4 {
604 let expected = poly.coeffs[i];
605 let p0 = parts_base16[0].coeffs[i];
606 let p1 = parts_base16[1].coeffs[i];
607 let actual = p0 + p1 * Zq::new(16);
608 assert_eq!(actual, expected, "Base 16: Coefficient {} mismatch", i);
609 }
610 }
611
612 #[test]
613 fn test_multi_part_decomposition() {
614 let poly: Rq = generate_rq_from_zq_vector(vec![
616 Zq::new(123),
617 Zq::new(456),
618 Zq::new(789),
619 Zq::new(101112),
620 ]);
621
622 let parts = poly.decompose(Zq::new(4), 3);
624 assert_eq!(parts.len(), 3, "Should have 3 parts");
625
626 let reconstructed =
628 &(&parts[0] + &(&(&parts[1] * &Zq::new(4)) + &(&parts[2] * &Zq::new(16)))); for i in 0..4 {
632 assert_eq!(
633 reconstructed.coeffs[i], poly.coeffs[i],
634 "3-part base 4: Coefficient {} mismatch",
635 i
636 );
637 }
638 }
639
640 #[test]
641 fn test_centering_properties() {
642 let values = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
645 let poly: Rq =
646 generate_rq_from_zq_vector(values.iter().map(|&v| Zq::new(v)).collect::<Vec<Zq>>());
647
648 let parts = poly.decompose(Zq::new(5), 2);
649
650 let expected_centered = [
659 Zq::ZERO, Zq::ONE, Zq::new(2), -Zq::new(2), -Zq::ONE, Zq::ZERO, Zq::ONE, Zq::new(2), -Zq::new(2), -Zq::ONE, Zq::ZERO, ];
671
672 for (i, &expected) in expected_centered.iter().enumerate() {
673 assert_eq!(
674 parts[0].coeffs[i], expected,
675 "Base 5 centering: Coefficient {} incorrectly centered",
676 i
677 );
678 }
679 }
680
681 #[test]
682 fn test_extreme_values() {
683 let poly: Rq = generate_rq_from_zq_vector(vec![Zq::ZERO, Zq::NEG_ONE, -Zq::ONE]);
685
686 let parts = poly.decompose(Zq::new(3), 2);
688
689 let reconstructed = &parts[0] + &(&parts[1] * &Zq::new(3));
691
692 for i in 0..3 {
693 assert_eq!(
694 reconstructed.coeffs[i], poly.coeffs[i],
695 "Extreme values: Coefficient {} mismatch",
696 i
697 );
698 }
699
700 assert_eq!(parts[0].coeffs[1], -Zq::new(1)); assert_eq!(parts[1].coeffs[1], Zq::ZERO); assert_eq!(parts[0].coeffs[2], Zq::NEG_ONE); assert_eq!(parts[1].coeffs[2], Zq::ZERO); }
711
712 #[test]
713 fn test_decomposition_properties() {
714 let poly: Rq = generate_rq_from_zq_vector(vec![
716 Zq::new(100),
717 Zq::new(200),
718 Zq::new(300),
719 Zq::new(400),
720 Zq::new(500),
721 Zq::new(600),
722 Zq::new(700),
723 Zq::new(800),
724 ]);
725
726 for base in [2, 3, 4, 5, 8, 10, 16].iter() {
727 let parts = poly.decompose(Zq::new(*base), 2);
728 let half_base = Zq::new(*base).scale_by(Zq::TWO);
729
730 for coeff in parts[0].coeffs.iter() {
732 let abs_coeff = if *coeff > Zq::new(u32::MAX / 2) {
734 Zq::ZERO - *coeff } else {
736 *coeff
737 };
738
739 assert!(
740 abs_coeff <= half_base,
741 "Base {}: First part coefficient {} exceeds half-base {}",
742 base,
743 coeff,
744 half_base
745 );
746 }
747
748 let reconstructed = &parts[0] + &(&parts[1] * &Zq::new(*base));
750 assert_eq!(reconstructed, poly, "Base {}: Reconstruction failed", base);
751 }
752 }
753
754 #[test]
755 fn test_conjugate_automorphism() {
756 use crate::core::inner_product::compute_linear_combination;
757
758 let poly1 = helper::rq_from(&[Zq::ONE, Zq::TWO, Zq::new(3)]);
759 let poly2 = helper::rq_from(&[Zq::new(4), Zq::new(5), Zq::new(6)]);
760 let inner_12 =
761 compute_linear_combination(poly1.get_coefficients(), poly2.get_coefficients());
762 let conjugated_1 = poly1.conjugate_automorphism();
763 let inner_conjugated_12 = &conjugated_1 * &poly2;
764
765 assert_eq!(inner_conjugated_12.coeffs.len(), Rq::DEGREE);
766 assert_eq!(inner_conjugated_12.get_coefficients()[0], Zq::new(32));
767 assert_eq!(inner_conjugated_12.get_coefficients()[1], Zq::new(17));
768 assert_eq!(inner_conjugated_12.get_coefficients()[2], Zq::new(6));
769
770 let ct_inner_conjugated_12 = inner_conjugated_12.get_coefficients()[0];
772 assert_eq!(ct_inner_conjugated_12, inner_12);
773 }
774
775 #[test]
777 fn test_norm() {
778 let poly1 = generate_rq_from_zq_vector(vec![Zq::ONE, Zq::ZERO, Zq::new(5), Zq::NEG_ONE]);
779 let poly2 = generate_rq_from_zq_vector(vec![Zq::ZERO, Zq::ZERO, Zq::new(5), Zq::ONE]);
780 let poly3 = generate_rq_from_zq_vector(vec![Zq::new(5), Zq::ONE, -Zq::new(6), Zq::ZERO]);
781 let poly4 = Rq::zero();
782
783 assert_eq!(poly1.l2_norm_squared(), Zq::new(27));
784 assert_eq!(poly2.l2_norm_squared(), Zq::new(26));
785 assert_eq!(poly3.l2_norm_squared(), Zq::new(62));
786 assert_eq!(poly4.l2_norm_squared(), Zq::ZERO);
787 }
788}