qfall_math/integer_mod_q/ntt_polynomial_ring_zq/arithmetic/
sub.rs1use crate::{
12 integer::Z,
13 integer_mod_q::NTTPolynomialRingZq,
14 macros::arithmetics::{
15 arithmetic_assign_trait_borrowed_to_owned, arithmetic_trait_borrowed_to_owned,
16 arithmetic_trait_mixed_borrowed_owned,
17 },
18 traits::CompareBase,
19};
20use flint_sys::fmpz_mod::fmpz_mod_sub;
21use std::ops::{Sub, SubAssign};
22
23impl Sub for &NTTPolynomialRingZq {
24 type Output = NTTPolynomialRingZq;
25
26 fn sub(self, other: Self) -> Self::Output {
49 assert_eq!(
50 self.modulus, other.modulus,
51 "The moduli of both polynomials have to be equal for subtraction."
52 );
53 let mod_q = &self.modulus.get_fq_ctx().ctxp[0];
54
55 let mut out = NTTPolynomialRingZq {
56 poly: vec![Z::default(); self.poly.len()],
57 modulus: self.modulus.clone(),
58 };
59
60 for i in 0..self.poly.len() {
61 unsafe {
62 fmpz_mod_sub(
63 &mut out.poly[i].value,
64 &self.poly[i].value,
65 &other.poly[i].value,
66 mod_q,
67 );
68 }
69 }
70
71 out
72 }
73}
74
75arithmetic_trait_borrowed_to_owned!(
76 Sub,
77 sub,
78 NTTPolynomialRingZq,
79 NTTPolynomialRingZq,
80 NTTPolynomialRingZq
81);
82arithmetic_trait_mixed_borrowed_owned!(
83 Sub,
84 sub,
85 NTTPolynomialRingZq,
86 NTTPolynomialRingZq,
87 NTTPolynomialRingZq
88);
89
90impl SubAssign<&NTTPolynomialRingZq> for NTTPolynomialRingZq {
91 fn sub_assign(&mut self, other: &Self) {
114 if !self.compare_base(other) {
115 panic!("{}", self.call_compare_base_error(other).unwrap());
116 }
117 let mod_q = &self.modulus.get_fq_ctx().ctxp[0];
118
119 for i in 0..self.poly.len() {
120 unsafe {
121 fmpz_mod_sub(
122 &mut self.poly[i].value,
123 &self.poly[i].value,
124 &other.poly[i].value,
125 mod_q,
126 );
127 }
128 }
129 }
130}
131
132arithmetic_assign_trait_borrowed_to_owned!(
133 SubAssign,
134 sub_assign,
135 NTTPolynomialRingZq,
136 NTTPolynomialRingZq
137);
138
139#[cfg(test)]
140mod test_sub {
141 use crate::{
142 integer_mod_q::{
143 ModulusPolynomialRingZq, NTTPolynomialRingZq, PolyOverZq, PolynomialRingZq,
144 },
145 traits::SetCoefficient,
146 };
147 use std::{ops::Sub, str::FromStr};
148
149 #[test]
152 fn test_dilithium_params() {
153 let n = 256;
154 let modulus = 2_i64.pow(23) - 2_i64.pow(13) + 1;
155
156 let mut mod_poly = PolyOverZq::from(modulus);
157 mod_poly.set_coeff(0, 1).unwrap();
158 mod_poly.set_coeff(n, 1).unwrap();
159
160 let mut polynomial_modulus = ModulusPolynomialRingZq::from(&mod_poly);
161
162 polynomial_modulus.set_ntt_unchecked(1753);
163
164 let p1 = PolynomialRingZq::sample_uniform(&polynomial_modulus);
165 let p2 = PolynomialRingZq::sample_uniform(&polynomial_modulus);
166
167 let ntt1 = NTTPolynomialRingZq::from(&p1);
168 let ntt2 = NTTPolynomialRingZq::from(&p2);
169
170 let res = ntt1.sub(ntt2);
171
172 assert_eq!(&p1 - &p2, PolynomialRingZq::from(res))
173 }
174
175 #[test]
178 fn test_hawk1024_params() {
179 let n = 1024;
180 let modulus = 12289;
181
182 let mut mod_poly = PolyOverZq::from(modulus);
183 mod_poly.set_coeff(0, 1).unwrap();
184 mod_poly.set_coeff(n, 1).unwrap();
185
186 let mut polynomial_modulus = ModulusPolynomialRingZq::from(&mod_poly);
187
188 polynomial_modulus.set_ntt_unchecked(1945);
189
190 let p1 = PolynomialRingZq::sample_uniform(&polynomial_modulus);
191 let p2 = PolynomialRingZq::sample_uniform(&polynomial_modulus);
192
193 let ntt1 = NTTPolynomialRingZq::from(&p1);
194 let ntt2 = NTTPolynomialRingZq::from(&p2);
195
196 let res = ntt1.sub(&ntt2);
197
198 assert_eq!(&p1 - &p2, PolynomialRingZq::from(res))
199 }
200
201 #[test]
203 #[should_panic]
204 fn different_moduli() {
205 let mut modulus0 = ModulusPolynomialRingZq::from_str("5 1 0 0 0 1 mod 257").unwrap();
206 modulus0.set_ntt_unchecked(64);
207 let mut modulus1 = ModulusPolynomialRingZq::from_str("6 1 0 0 0 0 1 mod 257").unwrap();
208 modulus1.set_ntt_unchecked(64);
209
210 let a = NTTPolynomialRingZq::sample_uniform(&modulus0);
211 let b = NTTPolynomialRingZq::sample_uniform(&modulus1);
212
213 let _ = a - b;
214 }
215}
216
217#[cfg(test)]
218mod test_sub_assign {
219 use crate::{
220 integer_mod_q::{
221 ModulusPolynomialRingZq, NTTPolynomialRingZq, PolyOverZq, PolynomialRingZq,
222 },
223 traits::SetCoefficient,
224 };
225 use std::{ops::SubAssign, str::FromStr};
226
227 #[test]
230 fn test_dilithium_params() {
231 let n = 256;
232 let modulus = 2_i64.pow(23) - 2_i64.pow(13) + 1;
233
234 let mut mod_poly = PolyOverZq::from(modulus);
235 mod_poly.set_coeff(0, 1).unwrap();
236 mod_poly.set_coeff(n, 1).unwrap();
237
238 let mut polynomial_modulus = ModulusPolynomialRingZq::from(&mod_poly);
239
240 polynomial_modulus.set_ntt_unchecked(1753);
241
242 let p1 = PolynomialRingZq::sample_uniform(&polynomial_modulus);
243 let p2 = PolynomialRingZq::sample_uniform(&polynomial_modulus);
244
245 let mut ntt1 = NTTPolynomialRingZq::from(&p1);
246 let ntt2 = NTTPolynomialRingZq::from(&p2);
247
248 ntt1.sub_assign(&ntt2);
249
250 assert_eq!(&p1 - &p2, PolynomialRingZq::from(ntt1))
251 }
252
253 #[test]
256 fn test_hawk1024_params() {
257 let n = 1024;
258 let modulus = 12289;
259
260 let mut mod_poly = PolyOverZq::from(modulus);
261 mod_poly.set_coeff(0, 1).unwrap();
262 mod_poly.set_coeff(n, 1).unwrap();
263
264 let mut polynomial_modulus = ModulusPolynomialRingZq::from(&mod_poly);
265
266 polynomial_modulus.set_ntt_unchecked(1945);
267
268 let p1 = PolynomialRingZq::sample_uniform(&polynomial_modulus);
269 let p2 = PolynomialRingZq::sample_uniform(&polynomial_modulus);
270
271 let mut ntt1 = NTTPolynomialRingZq::from(&p1);
272 let ntt2 = NTTPolynomialRingZq::from(&p2);
273
274 ntt1.sub_assign(ntt2);
275
276 assert_eq!(&p1 - &p2, PolynomialRingZq::from(ntt1))
277 }
278
279 #[test]
281 #[should_panic]
282 fn different_moduli() {
283 let mut modulus0 = ModulusPolynomialRingZq::from_str("5 1 0 0 0 1 mod 257").unwrap();
284 modulus0.set_ntt_unchecked(64);
285 let mut modulus1 = ModulusPolynomialRingZq::from_str("6 1 0 0 0 0 1 mod 257").unwrap();
286 modulus1.set_ntt_unchecked(64);
287
288 let mut a = NTTPolynomialRingZq::sample_uniform(&modulus0);
289 let b = NTTPolynomialRingZq::sample_uniform(&modulus1);
290
291 a -= b;
292 }
293}