qfall_math/integer_mod_q/mat_polynomial_ring_zq/
coefficient_embedding.rs1use super::MatPolynomialRingZq;
13use crate::{
14 integer::{PolyOverZ, Z},
15 integer_mod_q::{MatZq, ModulusPolynomialRingZq},
16 traits::{
17 FromCoefficientEmbedding, GetCoefficient, IntoCoefficientEmbedding, MatrixDimensions,
18 MatrixGetEntry, MatrixSetEntry, SetCoefficient,
19 },
20};
21
22impl IntoCoefficientEmbedding<(MatZq, ModulusPolynomialRingZq)> for &MatPolynomialRingZq {
23 fn into_coefficient_embedding(self, size: impl Into<i64>) -> (MatZq, ModulusPolynomialRingZq) {
57 let size = size.into();
58 let num_rows = self.get_num_rows();
59 let num_columns = self.get_num_columns();
60
61 let mut out = MatZq::new(num_rows * size, num_columns, self.modulus.get_q());
62
63 for column in 0..num_columns {
64 for row in 0..num_rows {
65 let entry: PolyOverZ = unsafe { self.get_entry_unchecked(row, column) };
66 let length = entry.get_degree() + 1;
67 assert!(
68 size >= length,
69 "The matrix can not be embedded, as the length \
70 of a polynomial ({length}) is larger than \
71 the provided size ({size})."
72 );
73
74 for index in 0..size {
75 let coeff: Z = unsafe { entry.get_coeff_unchecked(index) };
76 out.set_entry(row * size + index, column, coeff).unwrap()
77 }
78 }
79 }
80
81 (out, self.get_mod())
82 }
83}
84
85impl FromCoefficientEmbedding<(&MatZq, &ModulusPolynomialRingZq, i64)> for MatPolynomialRingZq {
86 fn from_coefficient_embedding(embedding: (&MatZq, &ModulusPolynomialRingZq, i64)) -> Self {
118 let degree = embedding.2;
119 let num_rows = embedding.0.get_num_rows();
120 let num_columns = embedding.0.get_num_columns();
121
122 assert_eq!(
123 num_rows % (degree + 1),
124 0,
125 "The provided degree of polynomials ({degree}) +1 must divide the number of rows of the embedding ({num_rows})."
126 );
127 assert_eq!(
128 Z::from(embedding.0.get_mod()),
129 embedding.1.get_q(),
130 "This is no valid embedding, since the integer moduli of matrix and modulus mismatch."
131 );
132
133 let mut out = MatPolynomialRingZq::new(num_rows / (degree + 1), num_columns, embedding.1);
134
135 for row in 0..out.get_num_rows() {
136 for column in 0..num_columns {
137 let mut poly = PolyOverZ::default();
138 for index in 0..(degree + 1) {
139 let coeff: Z = unsafe {
140 embedding
141 .0
142 .get_entry_unchecked(row * (degree + 1) + index, column)
143 };
144 unsafe { poly.set_coeff_unchecked(index, coeff) };
145 }
146 out.set_entry(row, column, poly).unwrap();
147 }
148 }
149
150 out.reduce();
151 out
152 }
153}
154
155#[cfg(test)]
156mod test_into_coefficient_embedding {
157 use crate::{
158 integer_mod_q::{MatPolynomialRingZq, MatZq},
159 traits::{Concatenate, IntoCoefficientEmbedding},
160 };
161 use std::str::FromStr;
162
163 #[test]
165 fn standard_basis() {
166 let standard_basis = MatPolynomialRingZq::from_str(
167 "[[1 1, 2 0 1, 3 0 0 1],[1 1, 2 0 1, 3 0 0 1]] / 4 1 2 3 4 mod 17",
168 )
169 .unwrap();
170
171 let basis = standard_basis.into_coefficient_embedding(3);
172
173 assert_eq!(
174 MatZq::identity(3, 3, 17)
175 .concat_vertical(&MatZq::identity(3, 3, 17))
176 .unwrap(),
177 basis.0
178 );
179
180 assert_eq!(standard_basis.get_mod(), basis.1);
181 }
182
183 #[test]
185 fn standard_basis_vector() {
186 let standard_basis =
187 MatPolynomialRingZq::from_str("[[1 1, 2 0 1]] / 3 1 2 3 mod 17").unwrap();
188
189 let basis = standard_basis.into_coefficient_embedding(3);
190
191 assert_eq!((MatZq::identity(3, 2, 17), standard_basis.get_mod()), basis);
192 }
193
194 #[test]
196 fn large_entries() {
197 let poly = MatPolynomialRingZq::from_str(&format!(
198 "[[3 17 {} {}, 1 1],[1 1, 2 0 1]] / 4 1 2 3 4 mod {}",
199 i64::MAX,
200 i64::MIN,
201 u64::MAX
202 ))
203 .unwrap();
204
205 let matrix = poly.into_coefficient_embedding(3);
206
207 let cmp_matrix = MatZq::from_str(&format!(
208 "[[17, 1],[{}, 0],[{}, 0]] mod {}",
209 i64::MAX,
210 i64::MIN,
211 u64::MAX
212 ))
213 .unwrap()
214 .concat_vertical(&MatZq::identity(3, 2, u64::MAX))
215 .unwrap();
216 assert_eq!((cmp_matrix, poly.get_mod()), matrix);
217 }
218
219 #[test]
221 fn large_entries_vector() {
222 let poly = MatPolynomialRingZq::from_str(&format!(
223 "[[3 17 {} {}, 1 1]] / 4 1 2 3 4 mod {}",
224 i64::MAX,
225 i64::MIN,
226 u64::MAX
227 ))
228 .unwrap();
229
230 let matrix = poly.into_coefficient_embedding(3);
231
232 let cmp_matrix = MatZq::from_str(&format!(
233 "[[17, 1],[{}, 0],[{}, 0]] mod {}",
234 i64::MAX,
235 i64::MIN,
236 u64::MAX
237 ))
238 .unwrap();
239 assert_eq!((cmp_matrix, poly.get_mod()), matrix);
240 }
241
242 #[test]
244 #[should_panic]
245 fn size_too_small() {
246 let poly =
247 MatPolynomialRingZq::from_str("[[3 17 5 7, 2 0 1],[1 1, 1 1]] / 4 1 2 3 4 mod 19")
248 .unwrap();
249
250 let _ = poly.into_coefficient_embedding(2);
251 }
252
253 #[test]
255 #[should_panic]
256 fn size_too_small_vector() {
257 let poly =
258 MatPolynomialRingZq::from_str("[[3 17 5 7, 2 0 1]] / 4 1 2 3 4 mod 19").unwrap();
259
260 let _ = poly.into_coefficient_embedding(2);
261 }
262}
263
264#[cfg(test)]
265mod test_from_coefficient_embedding {
266 use crate::integer_mod_q::{MatPolynomialRingZq, MatZq, ModulusPolynomialRingZq};
267 use crate::traits::FromCoefficientEmbedding;
268 use std::str::FromStr;
269
270 #[test]
272 fn large_entries() {
273 let matrix = MatZq::from_str(&format!(
274 "[[17, 0],[{}, -1],[{}, 0]] mod {}",
275 i64::MAX,
276 i64::MIN,
277 u64::MAX
278 ))
279 .unwrap();
280 let modulus =
281 ModulusPolynomialRingZq::from_str(&format!("4 1 2 3 4 mod {}", u64::MAX)).unwrap();
282
283 let poly = MatPolynomialRingZq::from_coefficient_embedding((&matrix, &modulus, 0));
284
285 let cmp_poly = MatPolynomialRingZq::from_str(&format!(
286 "[[1 17, 0],[1 {}, 1 -1],[1 {}, 0]] / 4 1 2 3 4 mod {}",
287 i64::MAX,
288 i64::MIN,
289 u64::MAX
290 ))
291 .unwrap();
292 assert_eq!(cmp_poly, poly);
293 }
294
295 #[test]
297 fn large_entries_vector() {
298 let matrix = MatZq::from_str(&format!(
299 "[[17, 0],[{}, -1],[{}, 0]] mod {}",
300 i64::MAX,
301 i64::MIN,
302 u64::MAX
303 ))
304 .unwrap();
305 let modulus =
306 ModulusPolynomialRingZq::from_str(&format!("4 1 2 3 4 mod {}", u64::MAX)).unwrap();
307
308 let poly = MatPolynomialRingZq::from_coefficient_embedding((&matrix, &modulus, 2));
309
310 let cmp_poly = MatPolynomialRingZq::from_str(&format!(
311 "[[3 17 {} {}, 2 0 -1]] / 4 1 2 3 4 mod {}",
312 i64::MAX,
313 i64::MIN,
314 u64::MAX
315 ))
316 .unwrap();
317 assert_eq!(cmp_poly, poly);
318 }
319
320 #[test]
323 #[should_panic]
324 fn degree_not_dividing() {
325 let matrix = MatZq::from_str(&format!(
326 "[[17, 0],[{}, -1],[{}, 0]] mod {}",
327 i64::MAX,
328 i64::MIN,
329 u64::MAX
330 ))
331 .unwrap();
332 let modulus =
333 ModulusPolynomialRingZq::from_str(&format!("4 1 2 3 4 mod {}", u64::MAX)).unwrap();
334
335 let _ = MatPolynomialRingZq::from_coefficient_embedding((&matrix, &modulus, 1));
336 }
337
338 #[test]
340 #[should_panic]
341 fn mismatching_moduli() {
342 let matrix = MatZq::from_str(&format!(
343 "[[17, 0],[{}, -1],[{}, 0]] mod 17",
344 i64::MAX,
345 i64::MIN
346 ))
347 .unwrap();
348 let modulus =
349 ModulusPolynomialRingZq::from_str(&format!("4 1 2 3 4 mod {}", u64::MAX)).unwrap();
350
351 let _ = MatPolynomialRingZq::from_coefficient_embedding((&matrix, &modulus, 3));
352 }
353}