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}