qfall_math/integer_mod_q/polynomial_ring_zq/from.rs
1// Copyright © 2023 Marcel Luca Schmidt, Marvin Beckmann
2//
3// This file is part of qFALL-math.
4//
5// qFALL-math is free software: you can redistribute it and/or modify it under
6// the terms of the Mozilla Public License Version 2.0 as published by the
7// Mozilla Foundation. See <https://mozilla.org/en-US/MPL/2.0/>.
8
9//! Implementations to create a [`PolynomialRingZq`] value from other types.
10//!
11//! The explicit functions contain the documentation.
12
13use super::PolynomialRingZq;
14use crate::{
15 error::{MathError, StringConversionError},
16 integer::PolyOverZ,
17 integer_mod_q::{ModulusPolynomialRingZq, NTTPolynomialRingZq, PolyOverZq},
18 macros::for_others::implement_for_owned,
19};
20use std::str::FromStr;
21
22impl From<NTTPolynomialRingZq> for PolynomialRingZq {
23 /// Creates a polynomial from [`NTTPolynomialRingZq`] generated with respect to the
24 /// [`NTTBasisPolynomialRingZq`](crate::integer_mod_q::NTTBasisPolynomialRingZq) as part of
25 /// [`ModulusPolynomialRingZq`].
26 ///
27 /// Parameters:
28 /// - `ntt`: the NTT representation of the polynomial.
29 /// - `modulus`: the modulus that is applied to the polynomial ring element.
30 ///
31 /// Returns a new [`PolynomialRingZq`] with the specified [`ModulusPolynomialRingZq`] and
32 /// values as defined in `ntt`.
33 ///
34 /// # Examples
35 /// ```
36 /// use qfall_math::integer_mod_q::{PolynomialRingZq, PolyOverZq, ModulusPolynomialRingZq, NTTPolynomialRingZq};
37 /// use qfall_math::traits::SetCoefficient;
38 ///
39 /// let n = 4;
40 /// let modulus = 7681;
41 ///
42 /// let mut mod_poly = PolyOverZq::from(modulus);
43 /// mod_poly.set_coeff(0, 1).unwrap();
44 /// mod_poly.set_coeff(n, 1).unwrap();
45 ///
46 /// let mut polynomial_modulus = ModulusPolynomialRingZq::from(&mod_poly);
47 /// polynomial_modulus.set_ntt_unchecked(1925);
48 ///
49 /// let ntt = NTTPolynomialRingZq::sample_uniform(&polynomial_modulus);
50 ///
51 /// let res = PolynomialRingZq::from(ntt);
52 /// ```
53 ///
54 /// # Panics ...
55 /// - if the [`NTTBasisPolynomialRingZq`](crate::integer_mod_q::NTTBasisPolynomialRingZq) in `modulus`
56 /// is not set.
57 fn from(ntt: NTTPolynomialRingZq) -> Self {
58 ntt.inv_ntt()
59 }
60}
61
62impl From<&ModulusPolynomialRingZq> for PolynomialRingZq {
63 /// Creates a zero polynomial with a given [`ModulusPolynomialRingZq`].
64 ///
65 /// Parameters:
66 /// - `modulus`: the modulus that is applied to the polynomial ring element.
67 ///
68 /// Returns a new constant [`PolynomialRingZq`] with the specified [`ModulusPolynomialRingZq`].
69 ///
70 /// # Examples
71 /// ```
72 /// use qfall_math::integer_mod_q::PolynomialRingZq;
73 /// use qfall_math::integer_mod_q::ModulusPolynomialRingZq;
74 /// use qfall_math::integer_mod_q::PolyOverZq;
75 /// use std::str::FromStr;
76 ///
77 /// let modulus = ModulusPolynomialRingZq::from_str("4 1 0 0 1 mod 17").unwrap();
78 /// let poly = PolyOverZq::from_str("4 -1 0 1 1 mod 17").unwrap();
79 /// let poly_ring = PolynomialRingZq::from((poly, &modulus));
80 /// ```
81 ///
82 /// # Panics ...
83 /// - if the moduli mismatch.
84 fn from(modulus: &ModulusPolynomialRingZq) -> Self {
85 let modulus = modulus.into();
86
87 Self {
88 poly: PolyOverZ::default(),
89 modulus,
90 }
91 }
92}
93
94implement_for_owned!(ModulusPolynomialRingZq, PolynomialRingZq, From);
95
96impl<Poly: Into<PolyOverZ>, Mod: Into<ModulusPolynomialRingZq>> From<(Poly, Mod)>
97 for PolynomialRingZq
98{
99 /// Creates a new polynomial ring element of type [`PolynomialRingZq`].
100 ///
101 /// Parameters:
102 /// - `poly`: the coefficients of the polynomial.
103 /// - `modulus`: the modulus that is applied to the polynomial ring element.
104 ///
105 /// Returns a new element inside the polynomial ring.
106 ///
107 /// # Examples
108 /// ```
109 /// use qfall_math::integer_mod_q::PolynomialRingZq;
110 /// use qfall_math::integer_mod_q::ModulusPolynomialRingZq;
111 /// use qfall_math::integer::PolyOverZ;
112 /// use std::str::FromStr;
113 ///
114 /// let modulus = ModulusPolynomialRingZq::from_str("4 1 0 0 1 mod 17").unwrap();
115 /// let poly = PolyOverZ::from_str("4 -1 0 1 1").unwrap();
116 /// let poly_ring = PolynomialRingZq::from((&poly, &modulus));
117 /// ```
118 fn from((poly, modulus): (Poly, Mod)) -> Self {
119 let mut out = Self {
120 poly: poly.into(),
121 modulus: modulus.into(),
122 };
123 out.reduce();
124 out
125 }
126}
127
128impl<Mod: Into<ModulusPolynomialRingZq>> From<(&PolyOverZq, Mod)> for PolynomialRingZq {
129 /// Creates a new polynomial ring element of type [`PolynomialRingZq`].
130 ///
131 /// Parameters:
132 /// - `poly`: the coefficients of the polynomial.
133 /// - `modulus`: the modulus that is applied to the polynomial ring element.
134 ///
135 /// Returns a new element inside the polynomial ring, if the moduli of the
136 /// polynomial and the modulus match.
137 ///
138 /// # Examples
139 /// ```
140 /// use qfall_math::integer_mod_q::PolynomialRingZq;
141 /// use qfall_math::integer_mod_q::ModulusPolynomialRingZq;
142 /// use qfall_math::integer_mod_q::PolyOverZq;
143 /// use std::str::FromStr;
144 ///
145 /// let modulus = ModulusPolynomialRingZq::from_str("4 1 0 0 1 mod 17").unwrap();
146 /// let poly = PolyOverZq::from_str("4 -1 0 1 1 mod 17").unwrap();
147 /// let poly_ring = PolynomialRingZq::from((&poly, &modulus));
148 /// ```
149 ///
150 /// # Panics ...
151 /// - if the moduli mismatch.
152 fn from((poly, modulus): (&PolyOverZq, Mod)) -> Self {
153 let modulus = modulus.into();
154
155 assert_eq!(
156 poly.modulus,
157 modulus.get_q(),
158 "The moduli of the polynomial and the modulus mismatch."
159 );
160
161 let mut out = Self {
162 poly: poly.get_representative_least_nonnegative_residue(),
163 modulus,
164 };
165 out.reduce();
166 out
167 }
168}
169
170impl<Mod: Into<ModulusPolynomialRingZq>> From<(PolyOverZq, Mod)> for PolynomialRingZq {
171 /// Creates a new polynomial ring element of type [`PolynomialRingZq`].
172 ///
173 /// Parameters:
174 /// - `poly`: the coefficients of the polynomial.
175 /// - `modulus`: the modulus that is applied to the polynomial ring element.
176 ///
177 /// Returns a new element inside the polynomial ring, if the moduli of the
178 /// polynomial and the modulus match.
179 ///
180 /// # Examples
181 /// ```
182 /// use qfall_math::integer_mod_q::PolynomialRingZq;
183 /// use qfall_math::integer_mod_q::ModulusPolynomialRingZq;
184 /// use qfall_math::integer_mod_q::PolyOverZq;
185 /// use std::str::FromStr;
186 ///
187 /// let modulus = ModulusPolynomialRingZq::from_str("4 1 0 0 1 mod 17").unwrap();
188 /// let poly = PolyOverZq::from_str("4 -1 0 1 1 mod 17").unwrap();
189 /// let poly_ring = PolynomialRingZq::from((poly, &modulus));
190 /// ```
191 ///
192 /// # Panics ...
193 /// - if the moduli mismatch.
194 fn from((poly, modulus): (PolyOverZq, Mod)) -> Self {
195 let modulus = modulus.into();
196
197 assert_eq!(
198 poly.modulus,
199 modulus.get_q(),
200 "The moduli of the polynomial and the modulus mismatch."
201 );
202
203 let mut out = Self {
204 poly: poly.get_representative_least_nonnegative_residue(),
205 modulus,
206 };
207 out.reduce();
208 out
209 }
210}
211
212impl FromStr for PolynomialRingZq {
213 type Err = MathError;
214
215 /// Creates a polynomial ring element of type [`PolynomialRingZq`].
216 ///
217 /// **Warning**: If the polynomials start with a correctly formatted
218 /// [`PolyOverZ`] object, the rest of the string
219 /// until the `"/"` (for the first polynomial) or `"mod"` (for the second polynomial)
220 /// is ignored. This means that the input string `"4 0 1 2 3 / 2 1 1 mod 13"`
221 /// is the same as `"4 0 1 2 3 4 5 6 7 / 2 1 1 mod 13"`.
222 ///
223 /// Parameters:
224 /// - `s`: the polynomial ring element of form:
225 /// `"[#number of coefficients of element]⌴⌴[0th coefficient]⌴
226 /// [1st coefficient]⌴...⌴/⌴[#number of coefficients of polynomial modulus]⌴⌴
227 /// [0th coefficient]⌴[1st coefficient]⌴...⌴mod⌴[q]"`.
228 ///
229 /// Note that the `[#number of coefficients]` and `[0th coefficient]`
230 /// are divided by two spaces and the strings for the polynomials are trimmed,
231 /// i.e. all whitespaces around the polynomials and the modulus are ignored.
232 ///
233 /// Returns a [`PolynomialRingZq`] or an error if the provided string was not
234 /// formatted correctly, the numbers of coefficients were smaller than the numbers
235 /// provided at the start of the provided string, or the modulus was smaller than `2`.
236 ///
237 /// # Examples
238 /// ```
239 /// use qfall_math::integer_mod_q::PolynomialRingZq;
240 /// use std::str::FromStr;
241 ///
242 /// let poly = PolynomialRingZq::from_str("4 -1 0 1 1 / 4 0 1 -2 3 mod 42").unwrap();
243 /// ```
244 /// # Errors and Failures
245 /// - Returns a [`MathError`] of type
246 /// [`StringConversionError`](MathError::StringConversionError)
247 /// - if the provided first half of the string was not formatted correctly to
248 /// create a [`PolyOverZ`],
249 /// - if the provided second half of the
250 /// string was not formatted correctly to create a [`ModulusPolynomialRingZq`],
251 /// - if the numbers of coefficients were smaller than the numbers provided
252 /// at the start of the provided string,
253 /// - if the provided values did not contain two whitespaces, or
254 /// - if the delimiter `/` and `mod` could not be found.
255 /// - Returns a [`MathError`] of type
256 /// [`InvalidModulus`](MathError::InvalidModulus)
257 /// if the integer modulus `q` is smaller than `2`.
258 fn from_str(s: &str) -> Result<Self, Self::Err> {
259 let (poly_s, modulus) = match s.split_once("/") {
260 Some((poly_s, modulus)) => (poly_s, modulus),
261 None => {
262 return Err(StringConversionError::InvalidStringToPolyRingZqInput(
263 s.to_owned(),
264 ))?;
265 }
266 };
267
268 let poly_over_z = PolyOverZ::from_str(poly_s)?;
269 let modulus = ModulusPolynomialRingZq::from_str(modulus)?;
270
271 Ok(Self::from((&poly_over_z, &modulus)))
272 }
273}
274
275#[cfg(test)]
276mod test_from_ntt_modulus_polynomial_ring_zq {
277 use crate::{
278 integer::{PolyOverZ, Z},
279 integer_mod_q::{ModulusPolynomialRingZq, NTTPolynomialRingZq, PolynomialRingZq},
280 };
281 use std::str::FromStr;
282
283 /// Ensures that `inv_ntt` works properly and that we can make a round trip and get to the same ntt representation.
284 #[test]
285 fn round_trip() {
286 let mut mod_poly = ModulusPolynomialRingZq::from_str("5 1 0 0 0 1 mod 257").unwrap();
287 mod_poly.set_ntt_unchecked(64);
288
289 let poly = PolyOverZ::from_str("4 103 182 146 116").unwrap();
290 let poly_ring_zq = PolynomialRingZq::from((poly, &mod_poly));
291 let cmp_ntt = NTTPolynomialRingZq {
292 poly: vec![Z::from(113), Z::from(54), Z::from(47), Z::from(198)],
293 modulus: mod_poly.clone(),
294 };
295
296 let ntt = NTTPolynomialRingZq::from(&poly_ring_zq);
297
298 assert_eq!(ntt, cmp_ntt);
299
300 let res_poly_ring_zq = PolynomialRingZq::from(ntt);
301
302 assert_eq!(res_poly_ring_zq, poly_ring_zq);
303 }
304}
305
306#[cfg(test)]
307mod test_from_modulus_polynomial_ring_zq {
308 use crate::{
309 integer::PolyOverZ,
310 integer_mod_q::{ModulusPolynomialRingZq, PolynomialRingZq},
311 };
312 use std::str::FromStr;
313
314 /// Ensure that the default value is set correctly and that the modulus is correct
315 #[test]
316 fn is_reduced_large() {
317 let modulus = ModulusPolynomialRingZq::from_str("4 1 0 0 1 mod 17").unwrap();
318
319 let poly_ring = PolynomialRingZq::from(&modulus);
320
321 assert_eq!(PolyOverZ::default(), poly_ring.poly);
322 assert_eq!(modulus, poly_ring.modulus);
323 }
324
325 /// Ensures that the function is still available for all values implementing
326 /// `Into<ModulusPolynomialRingZq>`.
327 #[test]
328 fn availability() {
329 let modulus = ModulusPolynomialRingZq::from_str("4 1 0 0 1 mod 17").unwrap();
330
331 let _ = PolynomialRingZq::from(&modulus);
332 let _ = PolynomialRingZq::from(modulus);
333 }
334}
335
336#[cfg(test)]
337mod test_from_poly_over_z_modulus_polynomial_ring_zq {
338 use crate::{
339 integer::{PolyOverZ, Z},
340 integer_mod_q::{Modulus, ModulusPolynomialRingZq, PolyOverZq, PolynomialRingZq},
341 };
342 use std::str::FromStr;
343
344 const LARGE_PRIME: u64 = u64::MAX - 58;
345
346 /// Ensure that the modulus is applied with a large prime and large coefficients
347 #[test]
348 fn is_reduced_large() {
349 let modulus =
350 ModulusPolynomialRingZq::from_str(&format!("4 1 0 0 1 mod {LARGE_PRIME}")).unwrap();
351
352 let poly =
353 PolyOverZ::from_str(&format!("4 {} {} 1 1", LARGE_PRIME + 2, u64::MAX)).unwrap();
354 let poly_ring = PolynomialRingZq::from((&poly, &modulus));
355
356 let cmp_poly = PolyOverZ::from_str("3 1 58 1").unwrap();
357 let cmp_poly_ring = PolynomialRingZq::from((&cmp_poly, &modulus));
358
359 assert_eq!(poly_ring, cmp_poly_ring);
360 }
361
362 /// Ensure that two ring elements that are instantiated the same way are equal
363 #[test]
364 fn same_instantiation() {
365 let modulus =
366 ModulusPolynomialRingZq::from_str(&format!("4 1 0 0 1 mod {LARGE_PRIME}")).unwrap();
367 let poly =
368 PolyOverZ::from_str(&format!("4 {} {} 1 1", LARGE_PRIME + 2, u64::MAX)).unwrap();
369
370 let poly_ring_1 = PolynomialRingZq::from((&poly, &modulus));
371 let poly_ring_2 = PolynomialRingZq::from((&poly, &modulus));
372
373 assert_eq!(poly_ring_1, poly_ring_2);
374 }
375
376 /// Ensures that the function is still available for all values implementing
377 /// `Into<ModulusPolynomialRingZq>`.
378 #[test]
379 fn availability() {
380 let z = Z::from(2);
381 let q = Modulus::from(17);
382 let poly = PolyOverZ::from(2);
383 let poly_mod = PolyOverZq::from_str("2 1 1 mod 17").unwrap();
384 let modulus = ModulusPolynomialRingZq::from(&poly_mod);
385
386 let _ = PolynomialRingZq::from((&poly, &poly_mod));
387 let _ = PolynomialRingZq::from((&poly, poly_mod.clone()));
388 let _ = PolynomialRingZq::from((poly.clone(), &poly_mod));
389 let _ = PolynomialRingZq::from((poly.clone(), poly_mod));
390
391 let _ = PolynomialRingZq::from((0_i8, &modulus));
392 let _ = PolynomialRingZq::from((0_i16, &modulus));
393 let _ = PolynomialRingZq::from((0_i32, &modulus));
394 let _ = PolynomialRingZq::from((0_i64, &modulus));
395 let _ = PolynomialRingZq::from((0_u8, &modulus));
396 let _ = PolynomialRingZq::from((0_u16, &modulus));
397 let _ = PolynomialRingZq::from((0_u32, &modulus));
398 let _ = PolynomialRingZq::from((0_u64, &modulus));
399 let _ = PolynomialRingZq::from((&z, &modulus));
400 let _ = PolynomialRingZq::from((z, &modulus));
401 let _ = PolynomialRingZq::from((&q, &modulus));
402 let _ = PolynomialRingZq::from((q, &modulus));
403
404 let _ = PolynomialRingZq::from((poly.clone(), &modulus));
405 let _ = PolynomialRingZq::from((poly, modulus));
406 }
407}
408
409#[cfg(test)]
410mod test_from_poly_over_zq_modulus_polynomial_ring_zq {
411 use crate::{
412 integer::PolyOverZ,
413 integer_mod_q::{ModulusPolynomialRingZq, PolyOverZq, PolynomialRingZq},
414 };
415 use std::str::FromStr;
416
417 const LARGE_PRIME: u64 = u64::MAX - 58;
418
419 /// Ensure that the modulus is applied with a large prime and large coefficients
420 #[test]
421 fn is_reduced_large() {
422 let modulus =
423 ModulusPolynomialRingZq::from_str(&format!("4 1 0 0 1 mod {LARGE_PRIME}")).unwrap();
424
425 let poly = PolyOverZq::from_str(&format!(
426 "4 {} {} 1 1 mod {}",
427 LARGE_PRIME + 2,
428 u64::MAX,
429 LARGE_PRIME
430 ))
431 .unwrap();
432 let poly_ring = PolynomialRingZq::from((&poly, &modulus));
433
434 let cmp_poly = PolyOverZ::from_str("3 1 58 1").unwrap();
435 let cmp_poly_ring = PolynomialRingZq::from((&cmp_poly, &modulus));
436
437 assert_eq!(poly_ring, cmp_poly_ring);
438 }
439
440 /// Ensure that two ring elements that are instantiated the same way are equal
441 #[test]
442 fn same_instantiation() {
443 let modulus =
444 ModulusPolynomialRingZq::from_str(&format!("4 1 0 0 1 mod {LARGE_PRIME}")).unwrap();
445 let poly = PolyOverZq::from_str(&format!(
446 "4 {} {} 1 1 mod {}",
447 LARGE_PRIME + 2,
448 u64::MAX,
449 LARGE_PRIME
450 ))
451 .unwrap();
452
453 let poly_ring_1 = PolynomialRingZq::from((&poly, &modulus));
454 let poly_ring_2 = PolynomialRingZq::from((&poly, &modulus));
455
456 assert_eq!(poly_ring_1, poly_ring_2);
457 }
458
459 /// Ensures that the function is still available for all values implementing
460 /// `Into<ModulusPolynomialRingZq>`.
461 #[test]
462 fn availability() {
463 let poly_mod = PolyOverZq::from_str("2 1 1 mod 17").unwrap();
464 let modulus = ModulusPolynomialRingZq::from(&poly_mod);
465
466 let _ = PolynomialRingZq::from((&poly_mod, &poly_mod));
467 let _ = PolynomialRingZq::from((&poly_mod, poly_mod.clone()));
468 let _ = PolynomialRingZq::from((poly_mod.clone(), &poly_mod));
469 let _ = PolynomialRingZq::from((poly_mod.clone(), poly_mod.clone()));
470
471 let _ = PolynomialRingZq::from((&poly_mod, &modulus));
472 let _ = PolynomialRingZq::from((&poly_mod, modulus.clone()));
473 let _ = PolynomialRingZq::from((poly_mod.clone(), &modulus));
474 let _ = PolynomialRingZq::from((poly_mod, modulus));
475 }
476
477 /// Ensure that the function panics if the moduli mismatch.
478 #[test]
479 #[should_panic]
480 fn mismatiching_modulus_error_borrowed() {
481 let modulus = ModulusPolynomialRingZq::from_str("4 1 0 0 1 mod 17").unwrap();
482 let poly = PolyOverZq::from_str("4 -1 0 1 1 mod 13").unwrap();
483
484 let _ = PolynomialRingZq::from((&poly, &modulus));
485 }
486
487 /// Ensure that the function panics if the moduli mismatch.
488 #[test]
489 #[should_panic]
490 fn mismatiching_modulus_error_owned() {
491 let modulus = ModulusPolynomialRingZq::from_str("4 1 0 0 1 mod 17").unwrap();
492 let poly = PolyOverZq::from_str("4 -1 0 1 1 mod 13").unwrap();
493
494 let _ = PolynomialRingZq::from((poly, &modulus));
495 }
496}
497
498#[cfg(test)]
499mod test_from_str {
500 use super::PolynomialRingZq;
501 use std::str::FromStr;
502
503 /// tests whether a falsely formatted string (integer modulus is 0) returns an
504 /// error
505 #[test]
506 fn modulus_zero_throws_error() {
507 assert!(PolynomialRingZq::from_str("4 -1 0 1 1 / 4 0 1 -2 3 mod 0").is_err());
508 }
509
510 /// tests whether a false string (negative modulus) returns an error
511 #[test]
512 fn false_sign() {
513 assert!(PolynomialRingZq::from_str("4 0 1 -2 3 mod -42").is_err());
514 }
515
516 /// tests whether a falsely formatted string (wrong whitespaces) returns an
517 /// error
518 #[test]
519 fn whitespaces_in_modulus() {
520 assert!(PolynomialRingZq::from_str("4 -1 0 1 1 / 4 0 1 -2 3 mod 4 2").is_err());
521 }
522
523 /// tests whether a falsely formatted string (wrong symbols) returns an error
524 #[test]
525 fn false_format_symbols() {
526 assert!(PolynomialRingZq::from_str("4 -1 0 1 1 / 1 1 mod ba").is_err());
527 assert!(PolynomialRingZq::from_str("4 -1 0 1a 1 / 1 1 mod 42").is_err());
528 assert!(PolynomialRingZq::from_str("4 -1 0 1 1 / b 1 mod 42").is_err());
529 }
530
531 /// tests whether a falsely formatted string (missing double-space) returns
532 /// an error
533 #[test]
534 fn false_format() {
535 assert!(PolynomialRingZq::from_str("4 -1 0 1 1 / 4 0 1 -2 3 mod 42").is_err());
536 assert!(PolynomialRingZq::from_str("4 -1 0 1 1 / 4 0 1 -2 3 mod 42").is_err());
537 }
538
539 /// tests whether a falsely formatted string (wrong number of total
540 /// coefficients) returns an error
541 #[test]
542 fn false_number_of_coefficient() {
543 assert!(PolynomialRingZq::from_str("4 -1 0 1 1 / 5 0 1 -2 3 mod 42").is_err());
544 assert!(PolynomialRingZq::from_str("5 -1 0 1 1 / 4 0 1 -2 3 mod 42").is_err());
545 }
546
547 /// tests whether a falsely formatted string (too many whitespaces) returns
548 /// an error
549 #[test]
550 fn too_many_whitespaces() {
551 assert!(PolynomialRingZq::from_str("4 -1 0 1 1 / 4 0 1 -2 3 mod 42").is_err());
552 }
553
554 /// Ensure that the input works with strings that have to be trimmed
555 #[test]
556 fn trim_input() {
557 let poly = PolynomialRingZq::from_str(
558 " 4 -1 0 1 1 / 4 1 2 3 -4 mod 17 ",
559 );
560 assert!(poly.is_ok());
561 assert_eq!(
562 PolynomialRingZq::from_str("4 -1 0 1 1 / 4 1 2 3 -4 mod 17").unwrap(),
563 poly.unwrap()
564 );
565 }
566
567 /// Ensure that a string resulting from to_string, can be used in from_str
568 #[test]
569 fn roundtrip() {
570 let poly = PolynomialRingZq::from_str("2 1 1 / 4 1 1 -2 3 mod 42").unwrap();
571 let poly2 = PolynomialRingZq::from_str(&poly.to_string()).unwrap();
572 assert_eq!(poly, poly2);
573 }
574}