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 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}