qfall_math/integer_mod_q/poly_over_zq/from.rs
1// Copyright 2023 Marcel Luca Schmidt, Marvin Beckmann and Sven Moog
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 [`PolyOverZq`] value from other types.
10//!
11//! The explicit functions contain the documentation.
12
13use crate::{
14 error::{MathError, StringConversionError},
15 integer::{PolyOverZ, Z},
16 integer_mod_q::{ModulusPolynomialRingZq, PolyOverZq, Zq, modulus::Modulus},
17 macros::for_others::implement_for_owned,
18};
19use flint3_sys::{fmpz_mod_poly_init, fmpz_mod_poly_set_coeff_fmpz, fmpz_mod_poly_set_fmpz_poly};
20use std::{mem::MaybeUninit, str::FromStr};
21
22impl<Mod: Into<Modulus>> From<Mod> for PolyOverZq {
23 /// Creates a zero polynomial with a given [`Modulus`].
24 ///
25 /// Parameters:
26 /// - `modulus`: of the new [`PolyOverZq`]
27 ///
28 /// Returns a new constant [`PolyOverZq`] with the specified [`Modulus`].
29 ///
30 /// # Examples
31 /// ```
32 /// use qfall_math::integer_mod_q::PolyOverZq;
33 /// use std::str::FromStr;
34 ///
35 /// let poly = PolyOverZq::from(100);
36 ///
37 /// let poly_cmp = PolyOverZq::from_str("0 mod 100").unwrap();
38 /// assert_eq!(poly, poly_cmp);
39 /// ```
40 ///
41 /// # Panics ...
42 /// - if `modulus` is smaller than `2`.
43 fn from(modulus: Mod) -> Self {
44 let modulus = modulus.into();
45 let mut poly = MaybeUninit::uninit();
46 unsafe {
47 fmpz_mod_poly_init(poly.as_mut_ptr(), modulus.get_fmpz_mod_ctx_struct());
48 let poly = poly.assume_init();
49 PolyOverZq { poly, modulus }
50 }
51 }
52}
53
54impl From<&Zq> for PolyOverZq {
55 /// Creates a constant [`PolyOverZq`], i.e. the polynomial `x mod q`,
56 /// where `x` is the value of the given [`Zq`] value and `q` its modulus.
57 ///
58 /// Parameters:
59 /// - `value`: the constant value the polynomial will have.
60 ///
61 /// Returns a new constant [`PolyOverZq`] with the specified `value` and `modulus` of the [`Zq`] value.
62 ///
63 /// # Examples
64 /// ```
65 /// use qfall_math::{integer_mod_q::*, traits::*};
66 ///
67 /// let poly = PolyOverZq::from(&Zq::from((1, 10)));
68 ///
69 /// let poly_cmp = PolyOverZq::from((1, 10));
70 /// assert_eq!(poly, poly_cmp);
71 /// assert_eq!(poly.get_degree(), 0);
72 /// ```
73 fn from(value: &Zq) -> Self {
74 let mut res = PolyOverZq::from(&value.modulus);
75 unsafe {
76 fmpz_mod_poly_set_coeff_fmpz(
77 &mut res.poly,
78 0,
79 &value.value.value,
80 value.modulus.get_fmpz_mod_ctx_struct(),
81 );
82 };
83 res
84 }
85}
86
87implement_for_owned!(Zq, PolyOverZq, From);
88
89impl<Mod: Into<Modulus>> From<(&PolyOverZ, Mod)> for PolyOverZq {
90 /// Creates a [`PolyOverZq`] from a [`PolyOverZ`] and a value that implements [`Into<Modulus>`].
91 ///
92 /// Parameters:
93 /// - `poly`: the coefficients of the polynomial.
94 /// - `modulus`: the modulus by which each entry is reduced.
95 ///
96 /// Returns a new [`PolyOverZq`] with the coefficients from the
97 /// [`PolyOverZ`] instance under the specified [`Modulus`] value.
98 ///
99 /// # Examples
100 /// ```
101 /// use qfall_math::integer_mod_q::{PolyOverZq, Modulus};
102 /// use qfall_math::integer::PolyOverZ;
103 /// use std::str::FromStr;
104 ///
105 /// let poly = PolyOverZ::from_str("4 0 1 102 3").unwrap();
106 /// let modulus = Modulus::from(100);
107 ///
108 /// let mod_poly = PolyOverZq::from((&poly, &modulus));
109 ///
110 /// # let poly_cmp = PolyOverZq::from_str("4 0 1 2 3 mod 100").unwrap();
111 /// # assert_eq!(poly_cmp, mod_poly);
112 /// ```
113 ///
114 /// # Panics ...
115 /// - if `modulus` is smaller than `2`.
116 fn from((poly, modulus): (&PolyOverZ, Mod)) -> Self {
117 let mut res = PolyOverZq::from(modulus);
118 unsafe {
119 fmpz_mod_poly_set_fmpz_poly(
120 &mut res.poly,
121 &poly.poly,
122 res.modulus.get_fmpz_mod_ctx_struct(),
123 );
124 }
125 res
126 }
127}
128
129impl<Mod: Into<Modulus>> From<(PolyOverZ, Mod)> for PolyOverZq {
130 /// Creates a [`PolyOverZq`] from a [`PolyOverZ`] and a value that implements [`Into<Modulus>`].
131 ///
132 /// Parameters:
133 /// - `poly`: the coefficients of the polynomial.
134 /// - `modulus`: the modulus by which each entry is reduced.
135 ///
136 /// Returns a new [`PolyOverZq`] with the coefficients from the
137 /// [`PolyOverZ`] instance under the specified [`Modulus`] value.
138 ///
139 /// # Examples
140 /// ```
141 /// use qfall_math::integer_mod_q::PolyOverZq;
142 /// use qfall_math::integer::PolyOverZ;
143 /// use std::str::FromStr;
144 ///
145 /// let poly = PolyOverZ::from_str("4 0 1 102 3").unwrap();
146 ///
147 /// let mod_poly = PolyOverZq::from((poly, 100));
148 ///
149 /// # let poly_cmp = PolyOverZq::from_str("4 0 1 2 3 mod 100").unwrap();
150 /// # assert_eq!(poly_cmp, mod_poly);
151 /// ```
152 ///
153 /// # Panics ...
154 /// - if `modulus` is smaller than `2`.
155 fn from((poly, modulus): (PolyOverZ, Mod)) -> Self {
156 let mut res = PolyOverZq::from(modulus);
157 unsafe {
158 fmpz_mod_poly_set_fmpz_poly(
159 &mut res.poly,
160 &poly.poly,
161 res.modulus.get_fmpz_mod_ctx_struct(),
162 );
163 }
164 res
165 }
166}
167
168impl<Integer: Into<Z>, Mod: Into<Modulus>> From<(Integer, Mod)> for PolyOverZq {
169 /// Creates a [`PolyOverZq`] from any values that implement [`Into<Z>`] and [`Into<Modulus>`],
170 /// where the second value must be larger than `1`.
171 ///
172 /// Parameters:
173 /// - `z`: the single, constant coefficient of the polynomial.
174 /// - `modulus`: the modulus by which each entry is reduced.
175 ///
176 /// Returns a new constant [`PolyOverZq`] with the specified `z` and `modulus` value.
177 ///
178 /// # Examples
179 /// ```
180 /// use qfall_math::integer_mod_q::PolyOverZq;
181 /// use std::str::FromStr;
182 ///
183 /// let mod_poly = PolyOverZq::from((5, 42));
184 ///
185 /// # let poly_cmp = PolyOverZq::from_str("1 5 mod 42").unwrap();
186 /// # assert_eq!(poly_cmp, mod_poly);
187 /// ```
188 ///
189 /// # Panics ...
190 /// - if `modulus` is smaller than `2`.
191 fn from((z, modulus): (Integer, Mod)) -> Self {
192 let z: Z = z.into();
193 let mut res = PolyOverZq::from(modulus);
194 unsafe {
195 fmpz_mod_poly_set_coeff_fmpz(
196 &mut res.poly,
197 0,
198 &z.value,
199 res.modulus.get_fmpz_mod_ctx_struct(),
200 );
201 }
202 res
203 }
204}
205
206impl From<&ModulusPolynomialRingZq> for PolyOverZq {
207 /// Creates a [`PolyOverZq`] from a [`ModulusPolynomialRingZq`].
208 ///
209 /// Parameters:
210 /// - `modulus`: the context polynomial from which the coefficients are copied.
211 ///
212 /// # Examples
213 ///
214 /// Returns a new [`PolyOverZq`] representing the modulus object.
215 ///
216 /// ```
217 /// use qfall_math::integer_mod_q::{ModulusPolynomialRingZq, PolyOverZq};
218 /// use std::str::FromStr;
219 ///
220 /// let modulus = ModulusPolynomialRingZq::from_str("4 1 0 0 1 mod 17").unwrap();
221 ///
222 /// let poly_zq = PolyOverZq::from(&modulus);
223 ///
224 /// let poly_cmp = PolyOverZq::from_str("4 1 0 0 1 mod 17").unwrap();
225 /// assert_eq!(poly_cmp, poly_zq);
226 /// ```
227 fn from(modulus: &ModulusPolynomialRingZq) -> Self {
228 (*modulus.modulus).clone()
229 }
230}
231
232implement_for_owned!(ModulusPolynomialRingZq, PolyOverZq, From);
233
234impl From<&PolyOverZq> for PolyOverZq {
235 /// Alias for [`PolyOverZq::clone`].
236 fn from(value: &PolyOverZq) -> Self {
237 value.clone()
238 }
239}
240
241impl FromStr for PolyOverZq {
242 type Err = MathError;
243
244 /// Creates a polynomial with arbitrarily many coefficients of type [`Zq`].
245 ///
246 /// **Warning**: If the input string starts with a correctly formatted [`PolyOverZ`] object,
247 /// the rest of the string until the `"mod"` is ignored. This means that the input string
248 /// `"4 0 1 2 3 mod 13"` is the same as `"4 0 1 2 3 4 5 6 7 mod 13"`.
249 ///
250 /// Parameters:
251 /// - `s`: the polynomial of form:
252 /// `"[#number of coefficients]⌴⌴[0th coefficient]⌴[1st coefficient]⌴...⌴mod⌴[modulus]"`.
253 ///
254 /// Note that the `[#number of coefficients]` and `[0th coefficient]`
255 /// are divided by two spaces and the string for the polynomial is trimmed,
256 /// i.e. all whitespaces before around the polynomial and the modulus are ignored.
257 ///
258 /// Returns a [`PolyOverZq`] or an error if the provided string was not
259 /// formatted correctly, the number of coefficients was smaller than the number provided
260 /// at the start of the provided string, or the modulus was smaller than `2`.
261 ///
262 /// # Examples
263 /// ```
264 /// use qfall_math::integer_mod_q::PolyOverZq;
265 /// use std::str::FromStr;
266 ///
267 /// let poly = PolyOverZq::from_str("4 0 1 -2 3 mod 42").unwrap();
268 /// ```
269 /// # Errors and Failures
270 /// - Returns a [`MathError`] of type
271 /// [`StringConversionError`](MathError::StringConversionError)
272 /// - if the provided first half of the string was not formatted correctly to
273 /// create a [`PolyOverZ`],
274 /// - if the provided second half of the
275 /// string was not formatted correctly to create a [`Modulus`],
276 /// - if the number of coefficients was smaller than the number provided
277 /// at the start of the provided string,
278 /// - if the provided value did not contain two whitespaces, or
279 /// - if the delimiter `mod` could not be found.
280 /// - Returns a [`MathError`] of type
281 /// [`InvalidModulus`](MathError::InvalidModulus)
282 /// if `modulus` is smaller than `2`.
283 fn from_str(s: &str) -> Result<Self, Self::Err> {
284 let (poly_s, modulus) = match s.split_once("mod") {
285 Some((poly_s, modulus)) => (poly_s, modulus.trim()),
286 None => {
287 return Err(StringConversionError::InvalidStringToPolyModulusInput(
288 s.to_owned(),
289 ))?;
290 }
291 };
292
293 let poly_over_z = PolyOverZ::from_str(poly_s)?;
294 let modulus = Modulus::from_str(modulus)?;
295
296 Ok(Self::from((&poly_over_z, &modulus)))
297 }
298}
299
300#[cfg(test)]
301mod test_availability {
302 use super::*;
303 use crate::{integer::Z, integer_mod_q::Zq};
304
305 /// Ensure that the from function can be called with several types.
306 #[test]
307 fn availability() {
308 let z = Z::from(3);
309 let modulus = Modulus::from(2);
310 let zq = Zq::from((1, 2));
311 let poly = PolyOverZ::from_str("2 1 1").unwrap();
312 let poly_mod = ModulusPolynomialRingZq::from_str("4 1 0 0 1 mod 17").unwrap();
313
314 let _ = PolyOverZq::from(3);
315 let _ = PolyOverZq::from(&z);
316 let _ = PolyOverZq::from(z.clone());
317 let _ = PolyOverZq::from(&modulus);
318 let _ = PolyOverZq::from(modulus.clone());
319
320 let _ = PolyOverZq::from(&zq);
321 let _ = PolyOverZq::from(zq.clone());
322
323 let _ = PolyOverZq::from((1, 2));
324 let _ = PolyOverZq::from((&z, 2));
325 let _ = PolyOverZq::from((z.clone(), 2));
326 let _ = PolyOverZq::from((&modulus, 2));
327 let _ = PolyOverZq::from((modulus.clone(), 2));
328 let _ = PolyOverZq::from((&poly, 2));
329 let _ = PolyOverZq::from((poly.clone(), 2));
330 let _ = PolyOverZq::from((1, &z));
331 let _ = PolyOverZq::from((1, z.clone()));
332 let _ = PolyOverZq::from((1, &modulus));
333 let _ = PolyOverZq::from((1, modulus));
334
335 let _ = PolyOverZq::from(&poly_mod);
336 let _ = PolyOverZq::from(poly_mod);
337 }
338}
339
340#[cfg(test)]
341mod test_from_zq {
342 use super::*;
343 use crate::{integer::Z, traits::GetCoefficient};
344
345 /// Ensure that the [`From`] trait works for small
346 /// borrowed and owned [`Zq`], and tuples of value and modulus instances
347 #[test]
348 fn small() {
349 let value: Zq = Zq::from((1, 2));
350
351 let poly = PolyOverZq::from(&value);
352 let poly_2 = PolyOverZq::from(value.clone());
353 let poly_3 = PolyOverZq::from((1, 2));
354 let poly_4 = PolyOverZq::from((&1, &2));
355
356 let value_set: Zq = poly.get_coeff(0).unwrap();
357 assert_eq!(value_set, value);
358 assert_eq!(poly.get_degree(), 0);
359 assert_eq!(poly, poly_2);
360 assert_eq!(poly, poly_3);
361 assert_eq!(poly, poly_4);
362 }
363
364 /// Ensure that the [`From`] trait works for large
365 /// borrowed and owned [`Zq`], and tuples of value and modulus instances.
366 #[test]
367 fn large() {
368 let value = Zq::from((u64::MAX - 1, u64::MAX));
369 let modulus = Modulus::from(u64::MAX);
370
371 let poly = PolyOverZq::from(&value);
372 let poly_2 = PolyOverZq::from(value.clone());
373 let poly_3 = PolyOverZq::from((u64::MAX - 1, &modulus));
374 let poly_4 = PolyOverZq::from((&(u64::MAX - 1), &modulus));
375 let poly_5 = PolyOverZq::from((Z::from(u64::MAX - 1), &u64::MAX));
376 let poly_6 = PolyOverZq::from((&Z::from(u64::MAX - 1), u64::MAX));
377
378 let value_set: Zq = poly.get_coeff(0).unwrap();
379 assert_eq!(value_set, value);
380 assert_eq!(poly.get_degree(), 0);
381 assert_eq!(poly, poly_2);
382 assert_eq!(poly, poly_3);
383 assert_eq!(poly, poly_4);
384 assert_eq!(poly, poly_5);
385 assert_eq!(poly, poly_6);
386 }
387
388 /// Ensure that the modulus is applied when creating a [`PolyOverZq`]
389 /// from a constant [`Zq`].
390 #[test]
391 fn modulus_reduction() {
392 let poly = PolyOverZq::from((42, 5));
393
394 let value_set: Zq = poly.get_coeff(0).unwrap();
395 assert_eq!(value_set, Zq::from((2, 5)));
396 }
397
398 /// Ensure that the polynomial can not be created with an invalid modulus.
399 #[test]
400 #[should_panic]
401 fn invalid_modulus() {
402 let _ = PolyOverZq::from((10, 1));
403 }
404}
405
406#[cfg(test)]
407mod test_from_poly_z_modulus {
408 use super::PolyOverZq;
409 use crate::{integer::PolyOverZ, integer_mod_q::Modulus};
410 use std::str::FromStr;
411
412 /// Test conversion of a [`PolyOverZ`] with small coefficients and small
413 /// [`Modulus`] into a [`PolyOverZq`].
414 #[test]
415 fn working_small() {
416 let poly = PolyOverZ::from_str("4 0 1 -2 3").unwrap();
417 let modulus = Modulus::from(100);
418
419 let mod_poly = PolyOverZq::from((&poly, &modulus));
420
421 let cmp_poly = PolyOverZq::from_str("4 0 1 -2 3 mod 100").unwrap();
422 assert_eq!(cmp_poly, mod_poly);
423 }
424
425 /// Test conversion of a [`PolyOverZ`] with large coefficients and large
426 /// [`Modulus`] into a [`PolyOverZq`].
427 #[test]
428 fn working_large() {
429 let poly = PolyOverZ::from_str(&format!("4 {} {} -2 3", u64::MAX - 1, u64::MAX)).unwrap();
430 let modulus = Modulus::from(u64::MAX);
431
432 let mod_poly = PolyOverZq::from((&poly, &modulus));
433
434 let cmp_poly = PolyOverZq::from_str(&format!("4 -1 0 -2 3 mod {}", u64::MAX)).unwrap();
435 assert_eq!(cmp_poly, mod_poly);
436 }
437
438 /// Test that the coefficients are reduced properly after the conversion.
439 #[test]
440 fn reduce() {
441 let poly = PolyOverZ::from_str("4 100 101 -102 103").unwrap();
442 let modulus = Modulus::from(100);
443
444 let mod_poly = PolyOverZq::from((&poly, &modulus));
445
446 let cmp_poly = PolyOverZq::from_str("4 0 1 -2 3 mod 100").unwrap();
447 assert_eq!(cmp_poly, mod_poly);
448 }
449}
450
451#[cfg(test)]
452mod test_from_z_modulus {
453 use super::PolyOverZq;
454 use crate::{integer::Z, integer_mod_q::Modulus};
455 use std::str::FromStr;
456
457 /// Test conversion of a [`Z`] with small coefficients and small
458 /// [`Modulus`] into a [`PolyOverZq`].
459 #[test]
460 fn working_small() {
461 let z = Z::from(42);
462 let modulus = Modulus::from(100);
463
464 let mod_poly = PolyOverZq::from((&z, &modulus));
465
466 let cmp_poly = PolyOverZq::from_str("1 42 mod 100").unwrap();
467 assert_eq!(cmp_poly, mod_poly);
468 }
469
470 /// Test conversion of a [`PolyOverZ`] with large coefficients and large
471 /// [`Modulus`] into a [`PolyOverZq`].
472 #[test]
473 fn working_large() {
474 let z = Z::from(u64::MAX - 1);
475 let modulus = Modulus::from(u64::MAX);
476
477 let mod_poly = PolyOverZq::from((&z, &modulus));
478
479 let cmp_poly =
480 PolyOverZq::from_str(&format!("1 {} mod {}", u64::MAX - 1, u64::MAX)).unwrap();
481 assert_eq!(cmp_poly, mod_poly);
482 }
483
484 /// Test that the coefficients are reduced properly after the conversion.
485 #[test]
486 fn reduce() {
487 let z = Z::from(101);
488 let modulus = Modulus::from(100);
489
490 let mod_poly = PolyOverZq::from((&z, &modulus));
491
492 let cmp_poly = PolyOverZq::from_str("1 1 mod 100").unwrap();
493 assert_eq!(cmp_poly, mod_poly);
494 }
495}
496
497#[cfg(test)]
498mod test_from_str {
499 use super::PolyOverZq;
500 use std::str::FromStr;
501
502 /// tests whether a falsely formatted string (modulus is 0) returns an
503 /// error
504 #[test]
505 fn modulus_zero_throws_error() {
506 assert!(PolyOverZq::from_str("4 0 1 -2 3 mod 0").is_err());
507 }
508
509 /// tests whether a falsely formatted string (several modulus) returns
510 /// an error
511 #[test]
512 fn several_mod() {
513 assert!(PolyOverZq::from_str("4 0 1 -2 3 mod 42 mod 13").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!(PolyOverZq::from_str("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_modulus() {
526 assert!(PolyOverZq::from_str("1 1 mod ba").is_err());
527 }
528
529 /// tests whether a falsely formatted string (wrong symbols) returns an error
530 #[test]
531 fn false_format_symbols_polynomial() {
532 assert!(PolyOverZq::from_str("1 ba mod 42").is_err());
533 }
534
535 /// tests whether a false string (negative modulus) returns an error
536 #[test]
537 fn false_sign() {
538 assert!(PolyOverZq::from_str("4 0 1 -2 3 mod -42").is_err());
539 }
540
541 /// tests whether a falsely formatted string (missing double-space) returns
542 /// an error
543 #[test]
544 fn false_format() {
545 assert!(PolyOverZq::from_str("4 0 1 -2 3 mod 42").is_err());
546 }
547
548 /// tests whether a falsely formatted string (wrong number of total
549 /// coefficients) returns an error
550 #[test]
551 fn false_number_of_coefficient() {
552 assert!(PolyOverZq::from_str("5 0 1 -2 3 mod 42").is_err());
553 }
554
555 /// tests whether a falsely formatted string (missing double-space) returns
556 /// an error
557 #[test]
558 fn missing_whitespace() {
559 assert!(PolyOverZq::from_str("3 12 2 -3 mod 42").is_err());
560 assert!(PolyOverZq::from_str("2 17 42 mod 42").is_err());
561 assert!(PolyOverZq::from_str("2 17 42 mod 42").is_err());
562 assert!(PolyOverZq::from_str("2 17 42 mod 42").is_err());
563 assert!(PolyOverZq::from_str(" 2 17 42 mod 42").is_err());
564 assert!(PolyOverZq::from_str("2 17 42 mod 42 ").is_err());
565 }
566
567 /// tests whether a falsely formatted string (too many whitespaces) returns
568 /// an error
569 #[test]
570 fn too_many_whitespaces() {
571 assert!(PolyOverZq::from_str("4 0 1 -2 3 mod 42").is_err());
572 }
573
574 /// Ensure that the input works with strings that have to be trimmed
575 #[test]
576 fn trim_input() {
577 let poly = PolyOverZq::from_str(
578 " 4 1 2 3 -4 mod 17 ",
579 );
580 assert!(poly.is_ok());
581 assert_eq!(
582 PolyOverZq::from_str("4 1 2 3 -4 mod 17").unwrap(),
583 poly.unwrap()
584 );
585 }
586}
587
588#[cfg(test)]
589mod test_from_modulus_polynomial_ring_zq {
590 use crate::integer_mod_q::{ModulusPolynomialRingZq, PolyOverZq};
591 use std::str::FromStr;
592
593 /// ensure that the conversion works with positive large entries
594 #[test]
595 fn large_positive() {
596 let modulus_ring =
597 ModulusPolynomialRingZq::from_str(&format!("4 -1 0 0 1 mod {}", u64::MAX - 58))
598 .unwrap();
599
600 let modulus = PolyOverZq::from(&modulus_ring);
601
602 let cmp_poly =
603 PolyOverZq::from_str(&format!("4 {} 0 0 1 mod {}", u64::MAX - 59, u64::MAX - 58))
604 .unwrap();
605 assert_eq!(cmp_poly, modulus);
606 }
607}