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}