Skip to main content

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