qfall_math/integer_mod_q/poly_over_zq/arithmetic/
mul_scalar.rs1use super::super::PolyOverZq;
12use crate::error::MathError;
13use crate::integer::Z;
14use crate::integer_mod_q::Zq;
15use crate::macros::arithmetics::{
16 arithmetic_assign_between_types, arithmetic_assign_trait_borrowed_to_owned,
17 arithmetic_trait_borrowed_to_owned, arithmetic_trait_mixed_borrowed_owned,
18 arithmetic_trait_reverse,
19};
20use crate::macros::for_others::implement_for_others;
21use crate::traits::CompareBase;
22use flint_sys::fmpz_mod_poly::{fmpz_mod_poly_scalar_mul_fmpz, fmpz_mod_poly_scalar_mul_ui};
23use std::ops::{Mul, MulAssign};
24
25impl Mul<&Z> for &PolyOverZq {
26 type Output = PolyOverZq;
27 fn mul(self, scalar: &Z) -> Self::Output {
48 let mut out = PolyOverZq::from(&self.modulus);
49 unsafe {
50 fmpz_mod_poly_scalar_mul_fmpz(
51 &mut out.poly,
52 &self.poly,
53 &scalar.value,
54 self.modulus.get_fmpz_mod_ctx_struct(),
55 );
56 }
57 out
58 }
59}
60
61arithmetic_trait_reverse!(Mul, mul, Z, PolyOverZq, PolyOverZq);
62
63arithmetic_trait_borrowed_to_owned!(Mul, mul, PolyOverZq, Z, PolyOverZq);
64arithmetic_trait_borrowed_to_owned!(Mul, mul, Z, PolyOverZq, PolyOverZq);
65arithmetic_trait_mixed_borrowed_owned!(Mul, mul, PolyOverZq, Z, PolyOverZq);
66arithmetic_trait_mixed_borrowed_owned!(Mul, mul, Z, PolyOverZq, PolyOverZq);
67
68implement_for_others!(Z, PolyOverZq, PolyOverZq, Mul Scalar for i8 i16 i32 i64 u8 u16 u32 u64);
69
70impl Mul<&Zq> for &PolyOverZq {
71 type Output = PolyOverZq;
72 fn mul(self, scalar: &Zq) -> PolyOverZq {
95 self.mul_scalar_zq_safe(scalar).unwrap()
96 }
97}
98
99arithmetic_trait_reverse!(Mul, mul, Zq, PolyOverZq, PolyOverZq);
100
101arithmetic_trait_borrowed_to_owned!(Mul, mul, PolyOverZq, Zq, PolyOverZq);
102arithmetic_trait_borrowed_to_owned!(Mul, mul, Zq, PolyOverZq, PolyOverZq);
103arithmetic_trait_mixed_borrowed_owned!(Mul, mul, PolyOverZq, Zq, PolyOverZq);
104arithmetic_trait_mixed_borrowed_owned!(Mul, mul, Zq, PolyOverZq, PolyOverZq);
105
106impl PolyOverZq {
107 pub fn mul_scalar_zq_safe(&self, scalar: &Zq) -> Result<Self, MathError> {
130 if !self.compare_base(scalar) {
131 return Err(self.call_compare_base_error(scalar).unwrap());
132 }
133
134 let mut out = PolyOverZq::from(&scalar.modulus);
135 unsafe {
136 fmpz_mod_poly_scalar_mul_fmpz(
137 &mut out.poly,
138 &self.poly,
139 &scalar.value.value,
140 out.modulus.get_fmpz_mod_ctx_struct(),
141 )
142 }
143 Ok(out)
144 }
145}
146
147impl MulAssign<&Z> for PolyOverZq {
148 fn mul_assign(&mut self, scalar: &Z) {
174 unsafe {
175 fmpz_mod_poly_scalar_mul_fmpz(
176 &mut self.poly,
177 &self.poly,
178 &scalar.value,
179 self.modulus.get_fmpz_mod_ctx_struct(),
180 )
181 };
182 }
183}
184
185impl MulAssign<&Zq> for PolyOverZq {
186 fn mul_assign(&mut self, scalar: &Zq) {
191 if !self.compare_base(scalar) {
192 panic!("{}", self.call_compare_base_error(scalar).unwrap())
193 }
194 unsafe {
195 fmpz_mod_poly_scalar_mul_fmpz(
196 &mut self.poly,
197 &self.poly,
198 &scalar.value.value,
199 self.modulus.get_fmpz_mod_ctx_struct(),
200 )
201 };
202 }
203}
204
205arithmetic_assign_trait_borrowed_to_owned!(MulAssign, mul_assign, PolyOverZq, Zq);
206
207impl MulAssign<i64> for PolyOverZq {
208 fn mul_assign(&mut self, other: i64) {
210 let z = Z::from(other);
211 unsafe {
212 fmpz_mod_poly_scalar_mul_fmpz(
213 &mut self.poly,
214 &self.poly,
215 &z.value,
216 self.modulus.get_fmpz_mod_ctx_struct(),
217 )
218 };
219 }
220}
221
222impl MulAssign<u64> for PolyOverZq {
223 fn mul_assign(&mut self, other: u64) {
225 unsafe {
226 fmpz_mod_poly_scalar_mul_ui(
227 &mut self.poly,
228 &self.poly,
229 other,
230 self.modulus.get_fmpz_mod_ctx_struct(),
231 )
232 };
233 }
234}
235
236arithmetic_assign_trait_borrowed_to_owned!(MulAssign, mul_assign, PolyOverZq, Z);
237arithmetic_assign_between_types!(MulAssign, mul_assign, PolyOverZq, i64, i32 i16 i8);
238arithmetic_assign_between_types!(MulAssign, mul_assign, PolyOverZq, u64, u32 u16 u8);
239
240#[cfg(test)]
241mod test_mul_z {
242 use super::PolyOverZq;
243 use crate::integer::Z;
244 use std::str::FromStr;
245
246 #[test]
248 fn borrowed_correctness() {
249 let poly_1 =
250 PolyOverZq::from_str(&format!("3 1 2 {} mod {}", i64::MAX, u64::MAX)).unwrap();
251 let poly_2 = poly_1.clone();
252 let poly_3 = PolyOverZq::from_str(&format!(
253 "3 2 4 {} mod {}",
254 (i64::MAX as u64) * 2,
255 u64::MAX
256 ))
257 .unwrap();
258 let integer = Z::from(2);
259
260 let poly_1 = &poly_1 * &integer;
261 let poly_2 = &integer * &poly_2;
262
263 assert_eq!(poly_3, poly_1);
264 assert_eq!(poly_3, poly_2);
265 }
266
267 #[test]
269 fn availability() {
270 let poly = PolyOverZq::from_str("3 1 2 3 mod 17").unwrap();
271 let z = Z::from(2);
272
273 _ = poly.clone() * z.clone();
274 _ = poly.clone() * 2i8;
275 _ = poly.clone() * 2u8;
276 _ = poly.clone() * 2i16;
277 _ = poly.clone() * 2u16;
278 _ = poly.clone() * 2i32;
279 _ = poly.clone() * 2u32;
280 _ = poly.clone() * 2i64;
281 _ = poly.clone() * 2u64;
282
283 _ = z.clone() * poly.clone();
284 _ = 2i8 * poly.clone();
285 _ = 2u64 * poly.clone();
286
287 _ = &poly * &z;
288 _ = &z * &poly;
289 _ = &poly * z.clone();
290 _ = z.clone() * &poly;
291 _ = poly.clone() * &z;
292 _ = &z * poly.clone();
293 _ = &poly * 2i8;
294 _ = 2i8 * &poly;
295 }
296}
297
298#[cfg(test)]
299mod test_mul_zq {
300 use super::PolyOverZq;
301 use crate::integer_mod_q::Zq;
302 use std::str::FromStr;
303
304 #[test]
306 fn borrowed_correctness() {
307 let poly_1 =
308 PolyOverZq::from_str(&format!("3 1 2 {} mod {}", i64::MAX, u64::MAX)).unwrap();
309 let poly_2 = poly_1.clone();
310 let poly_3 = PolyOverZq::from_str(&format!(
311 "3 2 4 {} mod {}",
312 (i64::MAX as u64) * 2,
313 u64::MAX
314 ))
315 .unwrap();
316 let integer = Zq::from((2, u64::MAX));
317
318 let poly_1 = &poly_1 * &integer;
319 let poly_2 = &integer * &poly_2;
320
321 assert_eq!(poly_3, poly_1);
322 assert_eq!(poly_3, poly_2);
323 }
324
325 #[test]
327 fn availability() {
328 let poly = PolyOverZq::from_str("3 1 2 3 mod 17").unwrap();
329 let z = Zq::from((2, 17));
330
331 _ = poly.clone() * z.clone();
332 _ = z.clone() * poly.clone();
333 _ = &poly * &z;
334 _ = &z * &poly;
335 _ = &poly * z.clone();
336 _ = z.clone() * &poly;
337 _ = &z * poly.clone();
338 _ = poly.clone() * &z;
339 }
340
341 #[test]
343 #[should_panic]
344 fn different_moduli_panic() {
345 let poly = PolyOverZq::from_str("3 1 2 3 mod 17").unwrap();
346 let z = Zq::from((2, 16));
347
348 _ = &poly * &z;
349 }
350
351 #[test]
353 fn different_moduli_error() {
354 let poly = PolyOverZq::from_str("3 1 2 3 mod 17").unwrap();
355 let z = Zq::from((2, 16));
356
357 assert!(poly.mul_scalar_zq_safe(&z).is_err());
358 }
359}
360
361#[cfg(test)]
362mod test_mul_assign {
363 use crate::integer::{PolyOverZ, Z};
364 use crate::integer_mod_q::{PolyOverZq, Zq};
365 use std::str::FromStr;
366
367 #[test]
369 fn consistency() {
370 let mut a = PolyOverZq::from_str(&format!("2 2 -1 mod {}", u64::MAX - 1)).unwrap();
371 let cmp = &a * i32::MAX;
372
373 a *= i32::MAX;
374
375 assert_eq!(cmp, a);
376 }
377
378 #[test]
380 fn availability() {
381 let mut poly_zq = PolyOverZq::from_str("3 1 2 -3 mod 8").unwrap();
382
383 let z = Z::from(2);
384 let zq = Zq::from((2, 8));
385 let poly_z = PolyOverZ::from_str("2 3 1").unwrap();
386
387 poly_zq *= &z;
388 poly_zq *= z;
389 poly_zq *= &zq;
390 poly_zq *= zq;
391 poly_zq *= &poly_z;
392 poly_zq *= poly_z;
393 poly_zq *= 1_u8;
394 poly_zq *= 1_u16;
395 poly_zq *= 1_u32;
396 poly_zq *= 1_u64;
397 poly_zq *= 1_i8;
398 poly_zq *= 1_i16;
399 poly_zq *= 1_i32;
400 poly_zq *= 1_i64;
401 }
402
403 #[test]
405 #[should_panic]
406 fn mismatching_modulus_zq() {
407 let mut poly_zq = PolyOverZq::from_str("3 1 2 -3 mod 8").unwrap();
408
409 let zq = Zq::from((2, u64::MAX - 1));
410
411 poly_zq *= &zq;
412 }
413}