qfall_math/integer_mod_q/poly_over_zq/
evaluate.rs

1// Copyright © 2023 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 evaluate a [`PolyOverZq`].
10//! For each reasonable type, an implementation
11//! of the [`Evaluate`] trait should be implemented.
12
13use super::PolyOverZq;
14use crate::{
15    error::MathError,
16    integer::Z,
17    integer_mod_q::Zq,
18    macros::for_others::implement_for_owned,
19    traits::{CompareBase, Evaluate},
20};
21use flint_sys::fmpz_mod_poly::fmpz_mod_poly_evaluate_fmpz;
22
23impl<Integer: Into<Z>> Evaluate<Integer, Zq> for PolyOverZq {
24    /// Evaluates a [`PolyOverZq`] on a given input that implements [`Into<Z>`].
25    ///
26    /// Parameters:
27    /// - `value`: the value with which to evaluate the polynomial.
28    ///
29    /// Returns the evaluation of the polynomial as a [`Zq`].
30    ///
31    /// # Examples
32    /// ```
33    /// use qfall_math::traits::*;
34    /// use qfall_math::integer::Z;
35    /// use qfall_math::integer_mod_q::PolyOverZq;
36    /// use std::str::FromStr;
37    ///
38    /// let poly = PolyOverZq::from_str("5  0 1 2 -3 1 mod 17").unwrap();
39    /// let value = Z::from(3);
40    ///
41    /// let res = poly.evaluate(&value);
42    /// let res_2 = poly.evaluate(3);
43    /// ```
44    fn evaluate(&self, value: Integer) -> Zq {
45        let value: Z = value.into();
46        let mut res = Zq::from((0, &self.modulus));
47
48        unsafe {
49            fmpz_mod_poly_evaluate_fmpz(
50                &mut res.value.value,
51                &self.poly,
52                &value.value,
53                self.modulus.get_fmpz_mod_ctx_struct(),
54            )
55        };
56
57        res
58    }
59}
60
61impl PolyOverZq {
62    /// Evaluates a [`PolyOverZq`] on a given input of [`Zq`]. Note that the
63    /// [`Zq`] in this case is only a reference.
64    ///
65    /// Parameters:
66    /// - `value`: the value with which to evaluate the polynomial.
67    ///
68    /// Returns the evaluation of the polynomial as a [`Zq`] or an error
69    /// if the moduli mismatch.
70    ///
71    /// # Examples
72    /// ```
73    /// use qfall_math::traits::*;
74    /// use qfall_math::integer_mod_q::Zq;
75    /// use qfall_math::integer_mod_q::PolyOverZq;
76    /// use std::str::FromStr;
77    ///
78    /// let poly = PolyOverZq::from_str("5  0 1 2 -3 1 mod 17").unwrap();
79    /// let value = Zq::from((3, 17));
80    /// let res = poly.evaluate(&value);
81    /// ```
82    ///
83    /// # Errors and Failures
84    /// - Returns a [`MathError`] of type [`MathError::MismatchingModulus`]
85    ///   if the moduli of the polynomial and the input mismatch.
86    pub fn evaluate_safe(&self, value: &Zq) -> Result<Zq, MathError> {
87        if !self.compare_base(value) {
88            return Err(self.call_compare_base_error(value).unwrap());
89        }
90        Ok(self.evaluate(&value.value))
91    }
92}
93
94impl Evaluate<&Zq, Zq> for PolyOverZq {
95    /// Evaluates a [`PolyOverZq`] on a given input of [`Zq`]. Note that the
96    /// [`Zq`] in this case is only a reference. Note that this function will panic if
97    /// the modulus of the input and the polynomial mismatch.
98    /// Use [`PolyOverZq::evaluate_safe`] if a panic has to be avoided.
99    ///
100    /// Parameters:
101    /// - `value`: the value with which to evaluate the polynomial.
102    ///
103    /// Returns the evaluation of the polynomial as a [`Zq`].
104    ///
105    /// # Examples
106    /// ```
107    /// use qfall_math::traits::*;
108    /// use qfall_math::integer_mod_q::Zq;
109    /// use qfall_math::integer_mod_q::PolyOverZq;
110    /// use std::str::FromStr;
111    ///
112    /// let poly = PolyOverZq::from_str("5  0 1 2 -3 1 mod 17").unwrap();
113    /// let value = Zq::from((3, 17));
114    /// let res = poly.evaluate(&value);
115    /// ```
116    ///
117    /// # Panics ...
118    /// - if the moduli of the polynomial and the input mismatch.
119    fn evaluate(&self, value: &Zq) -> Zq {
120        self.evaluate_safe(value)
121            .expect("The moduli of the provided inputs mismatch")
122    }
123}
124
125implement_for_owned!(Zq, Zq, PolyOverZq, Evaluate);
126
127#[cfg(test)]
128mod test_evaluate_z {
129    use crate::integer::Z;
130    use crate::integer_mod_q::{PolyOverZq, Zq};
131    use crate::traits::Evaluate;
132    use std::str::FromStr;
133
134    /// Tests if evaluate works for [`Z`] as input
135    #[test]
136    fn eval_z() {
137        let poly = PolyOverZq::from_str("2  1 2 mod 17").unwrap();
138
139        let res = poly.evaluate(Z::from(3));
140
141        assert_eq!(Zq::from((7, 17)), res);
142    }
143
144    /// Tests if evaluate with a reference works
145    #[test]
146    fn eval_z_ref() {
147        let poly = PolyOverZq::from_str("2  1 2 mod 17").unwrap();
148
149        let res = poly.evaluate(&Z::from(3));
150
151        assert_eq!(Zq::from((7, 17)), res);
152    }
153
154    /// Tests if evaluate works with negative values
155    #[test]
156    fn eval_z_negative() {
157        let poly = PolyOverZq::from_str("2  1 2 mod 17").unwrap();
158
159        let res = poly.evaluate(&Z::from(-5));
160
161        assert_eq!(Zq::from((8, 17)), res);
162    }
163
164    /// Tests if evaluate works with large integers
165    #[test]
166    fn eval_z_large() {
167        let poly = PolyOverZq::from_str(&format!("2  3 2 mod {}", u64::MAX)).unwrap();
168
169        let res = poly.evaluate(&Z::from(u64::MAX - 1));
170
171        assert_eq!(Zq::from((1, u64::MAX)), res);
172    }
173
174    /// Test if evaluate works with max of [`i64`],[`i32`], ...
175    #[test]
176    fn eval_max() {
177        let poly = PolyOverZq::from_str("2  1 2 mod 17").unwrap();
178
179        // signed
180        let _ = poly.evaluate(i64::MAX);
181        let _ = poly.evaluate(i32::MAX);
182        let _ = poly.evaluate(i16::MAX);
183        let _ = poly.evaluate(i8::MAX);
184
185        //unsigned
186        let _ = poly.evaluate(u64::MAX);
187        let _ = poly.evaluate(u32::MAX);
188        let _ = poly.evaluate(u16::MAX);
189        let _ = poly.evaluate(u8::MAX);
190    }
191
192    /// Test if evaluate works with min of [`i64`],[`i32`], ...
193    #[test]
194    fn eval_min() {
195        let poly = PolyOverZq::from_str("2  1 2 mod 17").unwrap();
196
197        // signed
198        let _ = poly.evaluate(i64::MIN);
199        let _ = poly.evaluate(i32::MIN);
200        let _ = poly.evaluate(i16::MIN);
201        let _ = poly.evaluate(i8::MIN);
202
203        // unsigned
204        let _ = poly.evaluate(u64::MIN);
205        let _ = poly.evaluate(u32::MIN);
206        let _ = poly.evaluate(u16::MIN);
207        let _ = poly.evaluate(u8::MIN);
208    }
209}
210
211#[cfg(test)]
212mod test_evaluate_zq {
213    use crate::{
214        integer_mod_q::{PolyOverZq, Zq},
215        traits::Evaluate,
216    };
217    use std::str::FromStr;
218
219    /// Ensures that positive values return expected evaluation
220    #[test]
221    fn evaluate_positive() {
222        let poly = PolyOverZq::from_str("2  1 3 mod 17").unwrap();
223        let value = Zq::from((6, 17));
224
225        let res_ref = poly.evaluate(&value);
226        let res = poly.evaluate(value);
227
228        assert_eq!(Zq::from((2, 17)), res);
229        assert_eq!(res_ref, res);
230    }
231
232    /// Ensures that positive large values return expected evaluation
233    #[test]
234    fn evaluate_large_positive() {
235        let poly =
236            PolyOverZq::from_str(&format!("2  {} 1 mod {}", (u64::MAX - 1) / 2 + 2, u64::MAX))
237                .unwrap();
238        let value = Zq::from(((u64::MAX - 1) / 2, u64::MAX));
239
240        let res_ref = poly.evaluate(&value);
241        let res = poly.evaluate(value);
242
243        assert_eq!(Zq::from((1, u64::MAX)), res);
244        assert_eq!(res_ref, res);
245    }
246
247    /// Ensure that evaluate panics if the moduli mismatch
248    #[test]
249    #[should_panic]
250    fn mismatching_modulus_panic() {
251        let poly = PolyOverZq::from_str(&format!("2  3 1 mod {}", u64::MAX)).unwrap();
252        let value = Zq::from((3, u64::MAX - 1));
253
254        let _ = poly.evaluate(&value);
255    }
256
257    /// Ensure that evaluate_safe returns an error if the moduli mismatch
258    #[test]
259    fn mismatching_modulus_safe() {
260        let poly = PolyOverZq::from_str(&format!("2  3 1 mod {}", u64::MAX)).unwrap();
261        let value = Zq::from((3, u64::MAX - 1));
262
263        assert!(poly.evaluate_safe(&value).is_err());
264    }
265}