qfall_math/integer_mod_q/poly_over_zq/set.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 manipulate a [`PolyOverZq`] polynomial.
10
11use super::PolyOverZq;
12use crate::{
13 integer::Z,
14 integer_mod_q::{Modulus, Zq},
15 macros::for_others::implement_for_owned,
16 traits::SetCoefficient,
17};
18use flint3_sys::{fmpz_mod_poly_set_coeff_fmpz, fmpz_mod_poly_set_fmpz_poly};
19
20impl<Integer: Into<Z>> SetCoefficient<Integer> for PolyOverZq {
21 /// Sets the coefficient of a polynomial [`PolyOverZq`].
22 /// We advise to use small coefficients, since already 2^32 coefficients take space
23 /// of roughly 34 GB. If not careful, be prepared that memory problems can occur, if
24 /// the index is very high.
25 ///
26 /// Parameters:
27 /// - `index`: the index of the coefficient to set (has to be positive)
28 /// - `value`: the new value the coefficient will be set to.
29 ///
30 /// # Examples
31 /// ```
32 /// use qfall_math::integer_mod_q::PolyOverZq;
33 /// use qfall_math::integer::Z;
34 /// use qfall_math::traits::*;
35 /// use std::str::FromStr;
36 ///
37 /// let mut poly = PolyOverZq::from_str("4 0 1 2 3 mod 17").unwrap();
38 ///
39 /// assert!(poly.set_coeff(4, 1000).is_ok());
40 /// unsafe{ poly.set_coeff_unchecked(5, 75) };
41 /// ```
42 ///
43 /// # Safety
44 /// To use this function safely, make sure that the selected index
45 /// is greater or equal than `0` and that the provided value has
46 /// the same base so that they have a matching base.
47 unsafe fn set_coeff_unchecked(&mut self, index: i64, value: Integer) {
48 let value: Z = value.into();
49
50 unsafe {
51 fmpz_mod_poly_set_coeff_fmpz(
52 &mut self.poly,
53 index,
54 &value.value,
55 self.modulus.get_fmpz_mod_ctx_struct(),
56 );
57 }
58 }
59}
60
61impl SetCoefficient<&Zq> for PolyOverZq {
62 /// Sets the coefficient of a polynomial [`PolyOverZq`].
63 /// We advise to use small coefficients, since already 2^32 coefficients take space
64 /// of roughly 34 GB. If not careful, be prepared that memory problems can occur, if
65 /// the index is very high.
66 ///
67 /// This function does not check if the modulus of the polynomial and the value match.
68 ///
69 /// Parameters:
70 /// - `index`: the index of the coefficient to set (has to be positive)
71 /// - `value`: the new value the index should have from a borrowed [`Zq`].
72 ///
73 /// # Examples
74 /// ```
75 /// use qfall_math::integer_mod_q::PolyOverZq;
76 /// use qfall_math::integer_mod_q::Zq;
77 /// use qfall_math::traits::*;
78 /// use std::str::FromStr;
79 ///
80 /// let mut poly = PolyOverZq::from_str("4 0 1 2 3 mod 17").unwrap();
81 /// let value = Zq::from((1000, 17));
82 ///
83 /// assert!(poly.set_coeff(4, &value).is_ok());
84 /// unsafe{ poly.set_coeff_unchecked(5, &value) };
85 /// ```
86 ///
87 /// # Safety
88 /// To use this function safely, make sure that the selected index
89 /// is greater or equal than `0` and that the provided value has
90 /// the same base so that they have a matching base.
91 unsafe fn set_coeff_unchecked(&mut self, index: i64, value: &Zq) {
92 unsafe { self.set_coeff_unchecked(index, &value.value) }
93 }
94}
95
96implement_for_owned!(Zq, PolyOverZq, SetCoefficient);
97
98impl PolyOverZq {
99 /// Changes the modulus of the given polynomial to the new modulus.
100 /// It takes the representation of each coefficient in [0, q) as the new
101 /// coefficients and reduces them by the new [`Modulus`].
102 ///
103 /// Parameters:
104 /// - `modulus`: the new modulus of the polynomial
105 ///
106 /// # Examples
107 /// ```
108 /// use qfall_math::integer_mod_q::PolyOverZq;
109 /// use std::str::FromStr;
110 ///
111 /// let mut poly = PolyOverZq::from_str("4 5 3 7 4 mod 13").unwrap();
112 ///
113 /// poly.change_modulus(5);
114 ///
115 /// assert_eq!(PolyOverZq::from_str("4 0 3 2 4 mod 5").unwrap(), poly);
116 /// ```
117 ///
118 /// # Panics ...
119 /// - if `modulus` is smaller than `2`.
120 pub fn change_modulus(&mut self, modulus: impl Into<Modulus>) {
121 self.modulus = modulus.into();
122 let lnr = self.get_representative_least_nonnegative_residue();
123 unsafe {
124 fmpz_mod_poly_set_fmpz_poly(
125 &mut self.poly,
126 &lnr.poly,
127 self.modulus.get_fmpz_mod_ctx_struct(),
128 );
129 }
130 }
131}
132
133#[cfg(test)]
134mod test_set_coeff_z {
135 use crate::{integer::Z, integer_mod_q::PolyOverZq, traits::SetCoefficient};
136 use std::str::FromStr;
137
138 /// Ensure that the negative indices return an error.
139 #[test]
140 fn set_min_negative_coeff() {
141 let mut poly = PolyOverZq::from_str("2 1 1 mod 11").unwrap();
142
143 assert!(poly.set_coeff(i64::MIN, 2).is_err());
144 assert!(poly.set_coeff(i32::MIN, 2).is_err());
145 assert!(poly.set_coeff(i16::MIN, 2).is_err());
146 assert!(poly.set_coeff(i8::MIN, 2).is_err());
147 }
148
149 /// Ensure that large coefficients work.
150 #[test]
151 fn set_coeff_large() {
152 let mut poly = PolyOverZq::from_str("2 1 1 mod 11").unwrap();
153
154 assert!(poly.set_coeff(2, i32::MAX).is_ok());
155 assert!(poly.set_coeff(2, i64::MAX).is_ok());
156 }
157
158 /// Ensure that the max of [`u8`] and [`u16`] works as an index.
159 #[test]
160 fn set_index_large() {
161 let mut poly = PolyOverZq::from_str("2 1 1 mod 11").unwrap();
162
163 assert!(poly.set_coeff(u8::MAX, 2).is_ok());
164 assert!(poly.set_coeff(u16::MAX, 2).is_ok());
165 }
166
167 /// Ensure that a general case is working.
168 #[test]
169 fn set_coeff_working() {
170 let mut poly = PolyOverZq::from_str("4 0 1 2 3 mod 11").unwrap();
171 let value = 10000;
172
173 poly.set_coeff(0, value).unwrap();
174 poly.set_coeff(5, value).unwrap();
175 assert_eq!(
176 PolyOverZq::from_str("6 1 1 2 3 0 1 mod 11").unwrap(),
177 poly
178 );
179 }
180
181 /// Ensure that the correct coefficient is set and all others are set to `0`.
182 #[test]
183 fn set_coeff_rest_zero() {
184 let mut poly = PolyOverZq::from_str("0 mod 11").unwrap();
185
186 poly.set_coeff(4, -10).unwrap();
187 assert_eq!(PolyOverZq::from_str("5 0 0 0 0 1 mod 11").unwrap(), poly);
188 }
189
190 /// Ensure that setting with a z works.
191 #[test]
192 fn set_coeff_z() {
193 let mut poly = PolyOverZq::from_str("0 mod 11").unwrap();
194
195 poly.set_coeff(4, Z::from(123)).unwrap();
196 assert_eq!(PolyOverZq::from_str("5 0 0 0 0 2 mod 11").unwrap(), poly);
197 }
198}
199
200/// we omit most of the tests for the correct values, since
201/// the values itself are set with set_coeff taking in a [`Z`] value
202#[cfg(test)]
203mod test_set_coeff_zq {
204 use crate::{
205 integer_mod_q::{PolyOverZq, Zq},
206 traits::SetCoefficient,
207 };
208 use std::str::FromStr;
209
210 /// Ensure that an error is returned if the moduli do not match
211 #[test]
212 fn mismatching_moduli() {
213 let mut poly = PolyOverZq::from_str(&format!("4 0 1 2 3 mod {}", u64::MAX - 58)).unwrap();
214 let value = Zq::from((u64::MAX, u64::MAX - 57));
215
216 assert!(poly.set_coeff(4, &value).is_err());
217 assert_eq!(
218 PolyOverZq::from_str(&format!("4 0 1 2 3 mod {}", u64::MAX - 58)).unwrap(),
219 poly
220 )
221 }
222
223 /// Ensure that an ok is returned if the moduli not match
224 #[test]
225 fn matching_moduli() {
226 let mut poly = PolyOverZq::from_str(&format!("4 0 1 2 3 mod {}", u64::MAX - 58)).unwrap();
227 let value = Zq::from((u64::MAX, u64::MAX - 58));
228
229 assert!(poly.set_coeff(4, &value).is_ok());
230 assert_eq!(
231 PolyOverZq::from_str(&format!("5 0 1 2 3 58 mod {}", u64::MAX - 58)).unwrap(),
232 poly
233 )
234 }
235}
236
237#[cfg(test)]
238mod test_change_modulus {
239 use super::PolyOverZq;
240 use crate::integer_mod_q::Modulus;
241 use std::str::FromStr;
242
243 /// Ensures that the modulus is changed correctly.
244 #[test]
245 fn modulus_correct() {
246 let mut poly = PolyOverZq::from_str("6 1 2 3 4 5 6 mod 7").unwrap();
247 let modulus = Modulus::from(8);
248
249 poly.change_modulus(&modulus);
250
251 assert_eq!("6 1 2 3 4 5 6 mod 8", poly.to_string());
252 }
253
254 /// Ensures that the modulus is changed correctly, if the modulus is big.
255 #[test]
256 fn big_modulus_correct() {
257 let mut poly = PolyOverZq::from_str(&format!("6 1 2 3 4 5 6 mod {}", i64::MAX)).unwrap();
258 let modulus = Modulus::from(u64::MAX);
259
260 poly.change_modulus(&modulus);
261
262 assert_eq!(format!("6 1 2 3 4 5 6 mod {}", u64::MAX), poly.to_string());
263 }
264
265 /// Ensures that the poly is reduced correctly.
266 #[test]
267 fn reduced_correct() {
268 let mut poly = PolyOverZq::from_str("6 1 2 3 4 5 6 mod 7").unwrap();
269 let modulus = Modulus::from(2);
270
271 poly.change_modulus(&modulus);
272
273 assert_eq!("5 1 0 1 0 1 mod 2", poly.to_string());
274 }
275}