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