1use crate::ring::zq::Zq;
4use crate::ring::Norms;
5use core::ops::{Add, Mul, Sub};
6use rand::distr::{Distribution, Uniform};
7use rand::{CryptoRng, Rng};
8use rustfft::num_complex::Complex;
9use rustfft::FftPlanner;
10
11#[derive(Debug, Clone, PartialEq, Eq)]
14pub struct Rq {
15 coeffs: [Zq; Self::DEGREE],
16}
17
18impl Rq {
19 pub const DEGREE: usize = 64;
20 pub const fn new(coeffs: [Zq; Self::DEGREE]) -> Self {
22 Self { coeffs }
23 }
24
25 pub const fn zero() -> Self {
27 Self {
28 coeffs: [Zq::ZERO; Self::DEGREE],
29 }
30 }
31
32 pub fn into_coeffs(self) -> [Zq; Self::DEGREE] {
33 self.coeffs
34 }
35
36 pub fn coeffs(&self) -> &[Zq; Self::DEGREE] {
38 &self.coeffs
39 }
40
41 pub fn random<R: Rng + CryptoRng>(rng: &mut R) -> Self {
43 let uniform = Uniform::new_inclusive(Zq::ZERO, Zq::NEG_ONE).unwrap();
44 let mut coeffs = [Zq::ZERO; Self::DEGREE];
45 coeffs.iter_mut().for_each(|c| *c = uniform.sample(rng));
46 Self { coeffs }
47 }
48
49 pub fn random_with_bound<R: Rng + CryptoRng>(rng: &mut R, bound: u32) -> Self {
51 let uniform = Uniform::new_inclusive(Zq::ZERO, Zq::new(bound)).unwrap();
52 let mut coeffs = [Zq::ZERO; Self::DEGREE];
53 coeffs.iter_mut().for_each(|c| {
54 *c = if rng.random_bool(0.5) {
55 -uniform.sample(rng)
56 } else {
57 uniform.sample(rng)
58 }
59 });
60 Self { coeffs }
61 }
62
63 pub fn decompose(&self, base: Zq, num_parts: usize) -> Vec<Rq> {
67 let mut result = vec![Rq::zero(); num_parts];
68 self.coeffs.iter().enumerate().for_each(|(index, coeff)| {
69 coeff
70 .decompose(base, num_parts)
71 .into_iter()
72 .zip(result.iter_mut())
73 .for_each(|(decomposed_coeff, decomposed_vec)| {
74 decomposed_vec.coeffs[index] = decomposed_coeff;
75 });
76 });
77 result
78 }
79
80 pub fn conjugate_automorphism(&self) -> Self {
83 let original_coefficients = self.coeffs();
84
85 let mut conjugated_coeffs = [Zq::ZERO; Rq::DEGREE];
86 conjugated_coeffs[0] = original_coefficients[0];
87
88 for (conj_coeff, original_coeff) in conjugated_coeffs
89 .iter_mut()
90 .skip(1)
91 .zip(original_coefficients.iter().rev())
92 {
93 *conj_coeff = original_coeff * Zq::NEG_ONE;
94 }
95
96 Self::new(conjugated_coeffs)
97 }
98
99 #[allow(clippy::as_conversions)]
107 pub fn operator_norm(&self) -> f64 {
108 let coeffs = self.coeffs();
109 let n = coeffs.len();
110 let mut planner = FftPlanner::new();
111 let fft = planner.plan_fft_forward(n);
112
113 let mut buffer: Vec<Complex<f64>> = coeffs
115 .iter()
116 .map(|&x| {
117 let half = Zq::NEG_ONE.div_floor_by(2);
118 let converted_value = if x > half {
119 x.to_u128() as f64 - Zq::NEG_ONE.to_u128() as f64 - 1.0
120 } else {
121 x.to_u128() as f64
122 };
123 Complex {
124 re: converted_value,
125 im: 0.0,
126 }
127 })
128 .collect();
129
130 fft.process(&mut buffer);
132
133 buffer
135 .iter()
136 .map(|c| c.norm())
137 .fold(0.0, |max, x| max.max(x))
138 }
139}
140
141impl Add<&Rq> for &Rq {
142 type Output = Rq;
143 fn add(self, other: &Rq) -> Rq {
145 let mut coeffs = [Zq::ZERO; Rq::DEGREE];
146 for (r, (a, b)) in coeffs
147 .iter_mut()
148 .zip(self.coeffs.iter().zip(other.coeffs.iter()))
149 {
150 *r = *a + *b;
151 }
152 Rq::new(coeffs)
153 }
154}
155
156impl Sub<&Rq> for &Rq {
157 type Output = Rq;
158 fn sub(self, other: &Rq) -> Rq {
160 let mut coeffs = [Zq::ZERO; Rq::DEGREE];
161 for (r, (a, b)) in coeffs
162 .iter_mut()
163 .zip(self.coeffs.iter().zip(other.coeffs.iter()))
164 {
165 *r = *a - *b;
166 }
167 Rq::new(coeffs)
168 }
169}
170
171impl Mul<&Rq> for &Rq {
172 type Output = Rq;
173 fn mul(self, other: &Rq) -> Rq {
175 let mut result = [Zq::ZERO; Rq::DEGREE];
176 let mut out_of_field = [Zq::ZERO; Rq::DEGREE];
177 for (i, &self_coeff) in self.coeffs.iter().enumerate() {
178 for (j, &other_coeff) in other.coeffs.iter().enumerate() {
179 if i + j < Rq::DEGREE {
180 result[i + j] += self_coeff * other_coeff;
181 } else {
182 out_of_field[(i + j) % Rq::DEGREE] += self_coeff * other_coeff;
183 }
184 }
185 }
186 for i in (0..Rq::DEGREE).rev() {
188 result[i] -= out_of_field[i];
189 }
190 Rq::new(result)
191 }
192}
193
194impl Mul<&Zq> for &Rq {
195 type Output = Rq;
196 fn mul(self, other: &Zq) -> Rq {
198 let mut copied_coeffs = self.coeffs;
199 for elem in copied_coeffs.iter_mut() {
200 *elem *= *other;
201 }
202 Rq::new(copied_coeffs)
203 }
204}
205
206impl Norms for Rq {
207 type NormType = u128;
208
209 #[allow(clippy::as_conversions)]
210 fn l2_norm_squared(&self) -> Self::NormType {
211 self.coeffs.l2_norm_squared()
212 }
213
214 fn linf_norm(&self) -> Self::NormType {
215 self.coeffs.linf_norm()
216 }
217}
218
219#[cfg(test)]
220pub mod tests {
221 use super::*;
222
223 pub fn generate_rq_from_zq_vector(vec: Vec<Zq>) -> Rq {
224 let mut temp = [Zq::ZERO; Rq::DEGREE];
225 for i in (0..vec.len()).rev() {
227 let m = i / Rq::DEGREE;
228 let r = i % Rq::DEGREE;
229 let sign = if m % 2 == 0 { 1 } else { -1 };
230 if sign == 1 {
231 temp[r] += vec[i];
232 } else {
233 temp[r] -= vec[i];
234 }
235 }
236 Rq::new(temp)
237 }
238
239 pub mod helper {
240 use super::*;
241 pub fn padded(prefix: &[Zq]) -> [Zq; Rq::DEGREE] {
242 assert!(
243 prefix.len() <= Rq::DEGREE,
244 "too many coefficients for degree {}",
245 Rq::DEGREE
246 );
247
248 let mut out = [Zq::ZERO; Rq::DEGREE];
249 out[..prefix.len()].copy_from_slice(prefix);
250 out
251 }
252
253 pub fn rq_from(prefix: &[Zq]) -> Rq {
254 Rq {
255 coeffs: padded(prefix),
256 }
257 }
258 }
259
260 #[test]
262 fn test_new_and_create_poly() {
263 let coeffs = [Zq::ONE, Zq::new(2), Zq::new(3), Zq::new(4)];
264 let poly = helper::rq_from(&coeffs);
265 assert_eq!(poly.coeffs, helper::padded(&coeffs));
266
267 let coeffs2 = [Zq::ONE, Zq::new(2), Zq::new(3), Zq::new(4)];
269 let poly_from_vec_direct: Rq = generate_rq_from_zq_vector(coeffs.to_vec());
270 assert_eq!(poly_from_vec_direct.coeffs, helper::padded(&coeffs2));
271 }
272
273 #[test]
274 fn test_into_coeffs_returns_correct() {
275 let mut coeffs = [Zq::ZERO; Rq::DEGREE];
276 coeffs[0] = Zq::ONE;
277 coeffs[0] = Zq::new(20);
278 coeffs[0] = Zq::new(3121);
279 coeffs[0] = Zq::new(40);
280 let poly: Rq = generate_rq_from_zq_vector(coeffs.to_vec());
281
282 let result = Rq::into_coeffs(poly); assert_eq!(result, coeffs);
284 }
285
286 #[test]
288 fn test_add() {
289 let poly1: Rq =
291 generate_rq_from_zq_vector(vec![Zq::ONE, Zq::new(2), Zq::new(3), Zq::new(4)]);
292 let poly2: Rq =
293 generate_rq_from_zq_vector(vec![Zq::new(4), Zq::new(3), Zq::new(2), Zq::ONE]);
294 let result = &poly1 + &poly2;
295 assert_eq!(
296 result.coeffs,
297 helper::padded(&[Zq::new(5), Zq::new(5), Zq::new(5), Zq::new(5)])
298 );
299
300 let poly3: Rq =
302 generate_rq_from_zq_vector(vec![Zq::ONE, Zq::new(2), Zq::new(3), Zq::new(4)]);
303 let poly4: Rq =
304 generate_rq_from_zq_vector(vec![Zq::NEG_ONE, Zq::new(3), Zq::NEG_ONE, Zq::ONE]);
305 let result2 = &poly3 + &poly4;
306 assert_eq!(
307 result2.coeffs,
308 helper::padded(&[Zq::ZERO, Zq::new(5), Zq::new(2), Zq::new(5)])
309 );
310 let poly5: Rq =
312 generate_rq_from_zq_vector(vec![Zq::ONE, Zq::new(2), Zq::new(3), Zq::new(4)]);
313 let poly6: Rq = generate_rq_from_zq_vector(vec![Zq::ZERO]);
314 let result3 = &poly5 + &poly6;
315 assert_eq!(
316 result3.coeffs,
317 helper::padded(&[Zq::ONE, Zq::new(2), Zq::new(3), Zq::new(4)])
318 );
319 let poly7: Rq =
321 generate_rq_from_zq_vector(vec![Zq::ONE, Zq::new(2), Zq::new(3), Zq::NEG_ONE]);
322 let poly8: Rq =
323 generate_rq_from_zq_vector(vec![Zq::NEG_ONE, Zq::NEG_ONE, Zq::NEG_ONE, Zq::NEG_ONE]);
324 let result3 = &poly7 + &poly8;
325 assert_eq!(
326 result3.coeffs,
327 helper::padded(&[Zq::ZERO, Zq::ONE, Zq::new(2), -Zq::new(2)])
328 );
329 }
330
331 #[test]
333 fn test_mul() {
334 let poly1: Rq = generate_rq_from_zq_vector(vec![Zq::ONE, Zq::ONE, Zq::new(2)]);
336 let poly2: Rq = generate_rq_from_zq_vector(vec![Zq::ONE, Zq::ONE]);
337 let result = &poly1 * &poly2;
338 assert_eq!(
339 result.coeffs,
340 helper::padded(&[Zq::new(1), Zq::new(2), Zq::new(3), Zq::new(2)])
341 );
342
343 let poly3: Rq = generate_rq_from_zq_vector(vec![Zq::ONE, Zq::ONE, Zq::new(2)]);
345 let poly4: Rq = generate_rq_from_zq_vector(vec![Zq::ZERO]);
346 let result2 = &poly3 * &poly4;
347 assert_eq!(
348 result2.coeffs,
349 helper::padded(&[Zq::ZERO, Zq::ZERO, Zq::ZERO])
350 );
351
352 }
362
363 #[test]
365 fn test_sub() {
366 let poly1: Rq =
368 generate_rq_from_zq_vector(vec![Zq::new(5), Zq::new(10), Zq::new(15), Zq::new(20)]);
369 let poly2: Rq =
370 generate_rq_from_zq_vector(vec![Zq::new(2), Zq::new(4), Zq::new(6), Zq::new(8)]);
371 let result = &poly1 - &poly2;
372 assert_eq!(
373 result.coeffs,
374 helper::padded(&[Zq::new(3), Zq::new(6), Zq::new(9), Zq::new(12)])
375 );
376
377 let poly3: Rq = generate_rq_from_zq_vector(vec![Zq::ONE, Zq::ONE, Zq::new(3), Zq::new(2)]);
379 let poly4: Rq =
380 generate_rq_from_zq_vector(vec![Zq::new(2), Zq::new(4), Zq::new(6), Zq::new(8)]);
381 let result2 = &poly3 - &poly4;
382 assert_eq!(
383 result2.coeffs,
384 helper::padded(&[
385 Zq::ZERO - Zq::new(1),
386 Zq::ZERO - Zq::new(3),
387 Zq::ZERO - Zq::new(3),
388 Zq::ZERO - Zq::new(6),
389 ])
390 );
391 let poly5: Rq =
393 generate_rq_from_zq_vector(vec![Zq::ONE, Zq::new(2), Zq::new(3), Zq::new(4)]);
394 let poly6: Rq = generate_rq_from_zq_vector(vec![Zq::ZERO]);
395 let result3 = &poly6 - &poly5;
396 let result4 = &poly5 - &poly6;
397 assert_eq!(
398 result3.coeffs,
399 helper::padded(&[
400 Zq::ZERO - Zq::new(1),
401 Zq::ZERO - Zq::new(2),
402 Zq::ZERO - Zq::new(3),
403 Zq::ZERO - Zq::new(4),
404 ])
405 );
406 assert_eq!(
407 result4.coeffs,
408 helper::padded(&[Zq::ONE, Zq::new(2), Zq::new(3), Zq::new(4)])
409 );
410 }
411
412 #[test]
414 fn test_scalar_mul() {
415 let poly: Rq =
416 generate_rq_from_zq_vector(vec![Zq::ONE, Zq::new(2), Zq::new(3), Zq::new(4)]);
417 let result = &poly * &Zq::new(2);
418 assert_eq!(
419 result.coeffs,
420 helper::padded(&[Zq::new(2), Zq::new(4), Zq::new(6), Zq::new(8)])
421 );
422 }
423
424 #[test]
426 fn test_get_coefficient() {
427 let poly: Rq = generate_rq_from_zq_vector(vec![Zq::ONE, Zq::ZERO, Zq::new(5), Zq::NEG_ONE]);
428 let vec = helper::padded(&[Zq::ONE, Zq::ZERO, Zq::new(5), Zq::NEG_ONE]).to_vec();
429 assert!(poly.coeffs().to_vec() == vec);
430
431 let poly_zero: Rq =
432 generate_rq_from_zq_vector(vec![Zq::ZERO, Zq::ZERO, Zq::ZERO, Zq::ZERO]);
433 let vec_zero = helper::padded(&[Zq::ZERO, Zq::ZERO, Zq::ZERO, Zq::ZERO]).to_vec();
434 assert!(poly_zero.coeffs().to_vec() == vec_zero);
435 }
436
437 #[test]
438 fn test_conjugate_automorphism() {
439 use crate::core::inner_product::compute_linear_combination;
440
441 let poly1 = helper::rq_from(&[Zq::ONE, Zq::TWO, Zq::new(3)]);
442 let poly2 = helper::rq_from(&[Zq::new(4), Zq::new(5), Zq::new(6)]);
443 let inner_12 = compute_linear_combination(poly1.coeffs(), poly2.coeffs());
444 let conjugated_1 = poly1.conjugate_automorphism();
445 let inner_conjugated_12 = &conjugated_1 * &poly2;
446
447 assert_eq!(inner_conjugated_12.coeffs.len(), Rq::DEGREE);
448 assert_eq!(inner_conjugated_12.coeffs()[0], Zq::new(32));
449 assert_eq!(inner_conjugated_12.coeffs()[1], Zq::new(17));
450 assert_eq!(inner_conjugated_12.coeffs()[2], Zq::new(6));
451
452 let ct_inner_conjugated_12 = inner_conjugated_12.coeffs()[0];
454 assert_eq!(ct_inner_conjugated_12, inner_12);
455 }
456}
457
458#[cfg(test)]
459mod norm_tests {
460 use super::tests::generate_rq_from_zq_vector;
461 use crate::ring::{rq::Rq, zq::Zq, Norms};
462
463 #[test]
465 fn test_l2_norm() {
466 let poly1 = generate_rq_from_zq_vector(vec![Zq::ONE, Zq::ZERO, Zq::new(5), Zq::NEG_ONE]);
467 let poly2 = generate_rq_from_zq_vector(vec![Zq::ZERO, Zq::ZERO, Zq::new(5), Zq::ONE]);
468 let poly3 = generate_rq_from_zq_vector(vec![Zq::new(5), Zq::ONE, -Zq::new(6), Zq::ZERO]);
469 let poly4 = Rq::zero();
470
471 assert_eq!(poly1.l2_norm_squared(), 27);
472 assert_eq!(poly2.l2_norm_squared(), 26);
473 assert_eq!(poly3.l2_norm_squared(), 62);
474 assert_eq!(poly4.l2_norm_squared(), 0);
475 }
476
477 #[test]
478 fn test_linf_norm() {
479 let poly1 = generate_rq_from_zq_vector(vec![Zq::ONE, Zq::ZERO, Zq::new(5), Zq::NEG_ONE]);
480 let poly2 = generate_rq_from_zq_vector(vec![Zq::ZERO, Zq::ZERO, -Zq::new(5), Zq::ONE]);
481 let poly3 = generate_rq_from_zq_vector(vec![Zq::new(5), Zq::ONE, -Zq::new(6), Zq::ZERO]);
482 let poly4 = Rq::zero();
483
484 assert_eq!(poly1.linf_norm(), 5);
485 assert_eq!(poly2.linf_norm(), 5);
486 assert_eq!(poly3.linf_norm(), 6);
487 assert_eq!(poly4.linf_norm(), 0);
488 }
489}
490
491#[cfg(test)]
492mod decomposition_tests {
493 use crate::ring::rq::tests::{generate_rq_from_zq_vector, helper};
494
495 use super::*;
496
497 #[test]
498 fn failure_test() {
499 let poly1 =
500 generate_rq_from_zq_vector(vec![-Zq::new(192), -Zq::new(0), -Zq::new(0), -Zq::new(0)]);
501 let decomposed = poly1.decompose(Zq::new(1802), 10);
502
503 let mut result = Rq::zero();
504 let mut exponential_base = Zq::new(1);
505 for elem in decomposed {
506 result = &result + &(&elem * &exponential_base);
507 exponential_base *= Zq::new(24);
508 }
509 assert_eq!(result, poly1);
510 }
511
512 #[test]
513 fn test_base2_decomposition() {
514 let poly: Rq =
516 generate_rq_from_zq_vector(vec![Zq::new(5), Zq::new(3), Zq::new(7), Zq::new(1)]);
517 let parts = poly.decompose(Zq::TWO, 4);
518
519 assert_eq!(
521 parts[0].coeffs,
522 helper::padded(&[
523 Zq::ONE, Zq::ONE, Zq::ONE, Zq::ONE, ])
528 );
529
530 assert_eq!(
532 parts[1].coeffs,
533 helper::padded(&[Zq::ZERO, Zq::ONE, Zq::ONE, Zq::ZERO,])
534 );
535
536 assert_eq!(
538 parts[2].coeffs,
539 helper::padded(&[
540 Zq::ONE, Zq::ZERO, Zq::ONE, Zq::ZERO, ])
545 );
546
547 let mut result = Rq::zero();
549 let mut expo_base = Zq::ONE;
550 for part in parts {
551 result = &result + &(&part * &expo_base);
552 expo_base *= Zq::TWO;
553 }
554 assert_eq!(poly, result);
555 }
556
557 #[test]
558 fn test_decomposition_edge_cases() {
559 let zero_poly: Rq = generate_rq_from_zq_vector(vec![Zq::ZERO; 4]);
561 let parts = zero_poly.decompose(Zq::TWO, 2);
562 assert!(
563 parts
565 .iter()
566 .all(|p| p.coeffs().iter().all(|&coeff| coeff == Zq::ZERO)),
567 "Zero polynomial decomposition failed"
568 );
569
570 let simple_poly: Rq =
572 generate_rq_from_zq_vector(vec![Zq::ONE, Zq::new(2), Zq::new(3), Zq::new(4)]);
573 let parts = simple_poly.decompose(Zq::TWO, 1);
574 assert_eq!(parts.len(), 1, "Single part decomposition length incorrect");
575 }
576
577 #[test]
578 fn test_decomposition_real_values() {
579 let poly1 = Rq {
580 coeffs: [
581 Zq::new(23071),
582 Zq::new(4294941461),
583 Zq::new(4084),
584 Zq::new(23413),
585 Zq::new(26902),
586 Zq::new(4294960817),
587 Zq::new(4294957829),
588 Zq::new(18248),
589 Zq::new(15293),
590 Zq::new(45978),
591 Zq::new(27197),
592 Zq::new(11233),
593 Zq::new(4294962536),
594 Zq::new(1196),
595 Zq::new(17083),
596 Zq::new(4294960822),
597 Zq::new(4294967103),
598 Zq::new(4294949429),
599 Zq::new(2926),
600 Zq::new(2742),
601 Zq::new(27552),
602 Zq::new(4294955871),
603 Zq::new(2917),
604 Zq::new(4294938904),
605 Zq::new(2288),
606 Zq::new(4294948781),
607 Zq::new(4294966588),
608 Zq::new(4294951307),
609 Zq::new(4294961210),
610 Zq::new(19355),
611 Zq::new(4294956913),
612 Zq::new(14940),
613 Zq::new(4294934068),
614 Zq::new(4294961161),
615 Zq::new(4294959017),
616 Zq::new(3339),
617 Zq::new(4294932967),
618 Zq::new(4294938251),
619 Zq::new(4294943006),
620 Zq::new(4294965167),
621 Zq::new(4294960800),
622 Zq::new(4161),
623 Zq::new(9213),
624 Zq::new(4294962556),
625 Zq::new(14299),
626 Zq::new(44418),
627 Zq::new(2438),
628 Zq::new(6583),
629 Zq::new(4294957783),
630 Zq::new(16),
631 Zq::new(4294941724),
632 Zq::new(4294966309),
633 Zq::new(4294966984),
634 Zq::new(4294956138),
635 Zq::new(1779),
636 Zq::new(29598),
637 Zq::new(16393),
638 Zq::new(728),
639 Zq::new(4294944371),
640 Zq::new(4294951792),
641 Zq::new(4294943824),
642 Zq::new(4294937618),
643 Zq::new(4294955208),
644 Zq::new(11235),
645 ],
646 };
647 let base = Zq::new(1802);
648 let decomposed = poly1.decompose(base, 2);
649
650 let reconstructed = &decomposed[0] + &(&decomposed[1] * &base);
652
653 assert_eq!(decomposed.len(), 2);
654 assert_eq!(reconstructed, poly1, "Base {base}: Reconstruction failed");
655 }
656
657 #[test]
658 fn test_linf_norm() {
659 let poly1 = Rq {
660 coeffs: [
661 Zq::new(23071),
662 Zq::new(4294941461),
663 Zq::new(4084),
664 Zq::new(23413),
665 Zq::new(26902),
666 Zq::new(4294960817),
667 Zq::new(4294957829),
668 Zq::new(18248),
669 Zq::new(15293),
670 Zq::new(45978),
671 Zq::new(27197),
672 Zq::new(11233),
673 Zq::new(4294962536),
674 Zq::new(1196),
675 Zq::new(17083),
676 Zq::new(4294960822),
677 Zq::new(4294967103),
678 Zq::new(4294949429),
679 Zq::new(2926),
680 Zq::new(2742),
681 Zq::new(27552),
682 Zq::new(4294955871),
683 Zq::new(2917),
684 Zq::new(4294938904),
685 Zq::new(2288),
686 Zq::new(4294948781),
687 Zq::new(4294966588),
688 Zq::new(4294951307),
689 Zq::new(4294961210),
690 Zq::new(19355),
691 Zq::new(4294956913),
692 Zq::new(14940),
693 Zq::new(4294934068),
694 Zq::new(4294961161),
695 Zq::new(4294959017),
696 Zq::new(3339),
697 Zq::new(4294932967),
698 Zq::new(4294938251),
699 Zq::new(4294943006),
700 Zq::new(4294965167),
701 Zq::new(4294960800),
702 Zq::new(4161),
703 Zq::new(9213),
704 Zq::new(4294962556),
705 Zq::new(14299),
706 Zq::new(44418),
707 Zq::new(2438),
708 Zq::new(6583),
709 Zq::new(4294957783),
710 Zq::new(16),
711 Zq::new(4294941724),
712 Zq::new(4294966309),
713 Zq::new(4294966984),
714 Zq::new(4294956138),
715 Zq::new(1779),
716 Zq::new(29598),
717 Zq::new(16393),
718 Zq::new(728),
719 Zq::new(4294944371),
720 Zq::new(4294951792),
721 Zq::new(4294943824),
722 Zq::new(4294937618),
723 Zq::new(4294955208),
724 Zq::new(11235),
725 ],
726 };
727 let base = Zq::new(1802);
728 let decomposed = poly1.decompose(base, 2);
729
730 for decomposed_poly in decomposed {
732 assert!(decomposed_poly.linf_norm() <= 901)
733 }
734 }
735}