qfall_math/integer_mod_q/poly_over_zq/arithmetic/
mul.rs1use super::super::PolyOverZq;
12use crate::{
13 error::MathError,
14 integer::PolyOverZ,
15 macros::arithmetics::{
16 arithmetic_assign_trait_borrowed_to_owned, arithmetic_trait_borrowed_to_owned,
17 arithmetic_trait_mixed_borrowed_owned, arithmetic_trait_reverse,
18 },
19 traits::CompareBase,
20};
21use core::panic;
22use flint_sys::fmpz_mod_poly::fmpz_mod_poly_mul;
23use std::{
24 ops::{Mul, MulAssign},
25 str::FromStr,
26};
27
28impl MulAssign<&PolyOverZq> for PolyOverZq {
29 fn mul_assign(&mut self, other: &Self) {
57 if !self.compare_base(other) {
58 panic!("{}", self.call_compare_base_error(other).unwrap());
59 }
60
61 unsafe {
62 fmpz_mod_poly_mul(
63 &mut self.poly,
64 &self.poly,
65 &other.poly,
66 self.modulus.get_fmpz_mod_ctx_struct(),
67 )
68 };
69 }
70}
71impl MulAssign<&PolyOverZ> for PolyOverZq {
72 fn mul_assign(&mut self, other: &PolyOverZ) {
74 let other = PolyOverZq::from((other, self.get_mod()));
75
76 self.mul_assign(&other);
77 }
78}
79
80arithmetic_assign_trait_borrowed_to_owned!(MulAssign, mul_assign, PolyOverZq, PolyOverZq);
81arithmetic_assign_trait_borrowed_to_owned!(MulAssign, mul_assign, PolyOverZq, PolyOverZ);
82
83impl Mul for &PolyOverZq {
84 type Output = PolyOverZq;
85 fn mul(self, other: Self) -> Self::Output {
110 self.mul_safe(other).unwrap()
111 }
112}
113
114arithmetic_trait_borrowed_to_owned!(Mul, mul, PolyOverZq, PolyOverZq, PolyOverZq);
115arithmetic_trait_mixed_borrowed_owned!(Mul, mul, PolyOverZq, PolyOverZq, PolyOverZq);
116
117impl Mul<&PolyOverZ> for &PolyOverZq {
118 type Output = PolyOverZq;
119 fn mul(self, other: &PolyOverZ) -> Self::Output {
139 let mut out = PolyOverZq::from(&self.modulus);
140 unsafe {
141 fmpz_mod_poly_mul(
142 &mut out.poly,
143 &self.poly,
144 &PolyOverZq::from((other, &self.modulus)).poly,
145 self.modulus.get_fmpz_mod_ctx_struct(),
146 );
147 }
148 out
149 }
150}
151
152arithmetic_trait_reverse!(Mul, mul, PolyOverZ, PolyOverZq, PolyOverZq);
153
154arithmetic_trait_borrowed_to_owned!(Mul, mul, PolyOverZq, PolyOverZ, PolyOverZq);
155arithmetic_trait_borrowed_to_owned!(Mul, mul, PolyOverZ, PolyOverZq, PolyOverZq);
156arithmetic_trait_mixed_borrowed_owned!(Mul, mul, PolyOverZq, PolyOverZ, PolyOverZq);
157arithmetic_trait_mixed_borrowed_owned!(Mul, mul, PolyOverZ, PolyOverZq, PolyOverZq);
158
159impl PolyOverZq {
160 pub fn mul_safe(&self, other: &Self) -> Result<PolyOverZq, MathError> {
182 if !self.compare_base(other) {
183 return Err(self.call_compare_base_error(other).unwrap());
184 }
185 let mut out = PolyOverZq::from_str(&format!("0 mod {}", self.modulus)).unwrap();
186 unsafe {
187 fmpz_mod_poly_mul(
188 &mut out.poly,
189 &self.poly,
190 &other.poly,
191 self.modulus.get_fmpz_mod_ctx_struct(),
192 );
193 }
194 Ok(out)
195 }
196}
197
198#[cfg(test)]
199mod test_mul_assign {
200 use super::PolyOverZq;
201 use crate::integer::PolyOverZ;
202 use std::str::FromStr;
203
204 #[test]
206 fn correct_small() {
207 let mut a = PolyOverZq::from_str("3 2 4 1 mod 7").unwrap();
208 let b = PolyOverZq::from_str("2 2 4 mod 7").unwrap();
209
210 a *= b;
211
212 assert_eq!(a, PolyOverZq::from_str("4 4 2 4 4 mod 7").unwrap());
213 }
214
215 #[test]
217 fn correct_large() {
218 let mut a = PolyOverZq::from_str(&format!(
219 "2 {} {} mod {}",
220 u64::MAX,
221 i64::MAX,
222 u64::MAX - 58
223 ))
224 .unwrap();
225 let b = PolyOverZq::from_str(&format!(
226 "2 {} {} mod {}",
227 i64::MAX,
228 i64::MIN,
229 u64::MAX - 58
230 ))
231 .unwrap();
232
233 a *= b;
234
235 assert_eq!(
236 a,
237 PolyOverZq::from_str(&format!(
238 "3 {} {} {} mod {}",
239 i128::from(i64::MAX) * 58,
240 i128::from(i64::MIN) * 58 + i128::from(i64::MAX) * i128::from(i64::MAX),
241 i128::from(i64::MAX) * i128::from(i64::MIN),
242 u64::MAX - 58
243 ))
244 .unwrap()
245 );
246 }
247
248 #[test]
250 fn availability() {
251 let mut a = PolyOverZq::from_str("3 1 2 -3 mod 5").unwrap();
252 let b = PolyOverZq::from_str("3 -1 -2 3 mod 5").unwrap();
253 let c = PolyOverZ::from_str("2 -2 2").unwrap();
254
255 a *= &b;
256 a *= b;
257 a *= &c;
258 a *= c;
259 }
260
261 #[test]
263 #[should_panic]
264 fn mismatching_moduli() {
265 let mut a: PolyOverZq = PolyOverZq::from_str("3 -5 4 1 mod 7").unwrap();
266 let b: PolyOverZq = PolyOverZq::from_str("3 -5 4 1 mod 8").unwrap();
267
268 a *= b;
269 }
270}
271
272#[cfg(test)]
273mod test_mul {
274 use super::PolyOverZq;
275 use std::str::FromStr;
276
277 #[test]
279 fn mul() {
280 let a: PolyOverZq = PolyOverZq::from_str("3 2 4 1 mod 7").unwrap();
281 let b: PolyOverZq = PolyOverZq::from_str("2 2 4 mod 7").unwrap();
282 let c: PolyOverZq = a * b;
283 assert_eq!(c, PolyOverZq::from_str("4 4 2 4 4 mod 7").unwrap());
284 }
285
286 #[test]
288 fn mul_borrow() {
289 let a: PolyOverZq = PolyOverZq::from_str("3 2 4 1 mod 7").unwrap();
290 let b: PolyOverZq = PolyOverZq::from_str("2 2 4 mod 7").unwrap();
291 let c: PolyOverZq = &a * &b;
292 assert_eq!(c, PolyOverZq::from_str("4 4 2 4 4 mod 7").unwrap());
293 }
294
295 #[test]
297 fn mul_first_borrowed() {
298 let a: PolyOverZq = PolyOverZq::from_str("3 2 4 1 mod 7").unwrap();
299 let b: PolyOverZq = PolyOverZq::from_str("2 2 4 mod 7").unwrap();
300 let c: PolyOverZq = &a * b;
301 assert_eq!(c, PolyOverZq::from_str("4 4 2 4 4 mod 7").unwrap());
302 }
303
304 #[test]
306 fn mul_second_borrowed() {
307 let a: PolyOverZq = PolyOverZq::from_str("3 2 4 1 mod 7").unwrap();
308 let b: PolyOverZq = PolyOverZq::from_str("2 2 4 mod 7").unwrap();
309 let c: PolyOverZq = a * &b;
310 assert_eq!(c, PolyOverZq::from_str("4 4 2 4 4 mod 7").unwrap());
311 }
312
313 #[test]
315 fn mul_constant() {
316 let a: PolyOverZq = PolyOverZq::from_str("3 2 4 1 mod 7").unwrap();
317 let b: PolyOverZq = PolyOverZq::from_str("1 2 mod 7").unwrap();
318 let c: PolyOverZq = &a * b;
319 assert_eq!(c, PolyOverZq::from_str("3 4 1 2 mod 7").unwrap());
320 assert_eq!(
321 a * PolyOverZq::from_str("0 mod 7").unwrap(),
322 PolyOverZq::from_str("0 mod 7").unwrap()
323 );
324 }
325
326 #[test]
328 fn mul_large_numbers() {
329 let a: PolyOverZq = PolyOverZq::from_str(&format!(
330 "2 {} {} mod {}",
331 u64::MAX,
332 i64::MAX,
333 u64::MAX - 58
334 ))
335 .unwrap();
336 let b: PolyOverZq = PolyOverZq::from_str(&format!(
337 "2 {} {} mod {}",
338 i64::MAX,
339 i64::MIN,
340 u64::MAX - 58
341 ))
342 .unwrap();
343 let c: PolyOverZq = a * &b;
344 assert_eq!(
345 c,
346 PolyOverZq::from_str(&format!(
347 "3 {} {} {} mod {}",
348 i128::from(i64::MAX) * 58,
349 i128::from(i64::MIN) * 58 + i128::from(i64::MAX) * i128::from(i64::MAX),
350 i128::from(i64::MAX) * i128::from(i64::MIN),
351 u64::MAX - 58
352 ))
353 .unwrap()
354 );
355 }
356
357 #[test]
359 #[should_panic]
360 fn mul_mismatching_modulus() {
361 let a: PolyOverZq = PolyOverZq::from_str("3 2 4 1 mod 8").unwrap();
362 let b: PolyOverZq = PolyOverZq::from_str("2 -5 4 mod 7").unwrap();
363 let _c: PolyOverZq = a * b;
364 }
365
366 #[test]
368 fn mul_safe_is_err() {
369 let a: PolyOverZq = PolyOverZq::from_str("3 2 4 1 mod 9").unwrap();
370 let b: PolyOverZq = PolyOverZq::from_str("2 -5 4 mod 7").unwrap();
371 assert!(&a.mul_safe(&b).is_err());
372 }
373}
374
375#[cfg(test)]
376mod test_mul_poly_over_z {
377 use super::PolyOverZq;
378 use crate::integer::PolyOverZ;
379 use std::str::FromStr;
380
381 #[test]
383 fn borrowed_correctness() {
384 let poly_1 = PolyOverZq::from_str(&format!("1 {} mod {}", i64::MAX, u64::MAX)).unwrap();
385 let poly_2 = PolyOverZ::from_str("2 1 2").unwrap();
386 let poly_cmp = PolyOverZq::from_str(&format!(
387 "2 {} {} mod {}",
388 i64::MAX,
389 i64::MAX as u64 * 2,
390 u64::MAX
391 ))
392 .unwrap();
393
394 let poly_1 = &poly_1 * &poly_2;
395
396 assert_eq!(poly_cmp, poly_1);
397 }
398
399 #[test]
401 fn availability() {
402 let poly = PolyOverZq::from_str("3 1 2 3 mod 17").unwrap();
403 let z = PolyOverZ::from(2);
404
405 _ = poly.clone() * z.clone();
406 _ = z.clone() * poly.clone();
407 _ = &poly * &z;
408 _ = &z * &poly;
409 _ = &poly * z.clone();
410 _ = z.clone() * &poly;
411 _ = &z * poly.clone();
412 _ = poly.clone() * &z;
413 }
414}