qfall_math/integer_mod_q/poly_over_zq/coefficient_embedding.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//! This module contains implementations to transform a [`PolyOverZq`]
10//! into a [`MatZq`] and reverse by using the coefficient embedding.
11
12use crate::{
13 integer::Z,
14 integer_mod_q::{MatZq, PolyOverZq},
15 traits::{
16 FromCoefficientEmbedding, GetCoefficient, IntoCoefficientEmbedding, MatrixDimensions,
17 MatrixGetEntry, MatrixSetEntry, SetCoefficient,
18 },
19};
20
21impl IntoCoefficientEmbedding<MatZq> for &PolyOverZq {
22 /// Computes the coefficient embedding of the polynomial
23 /// in a [`MatZq`] as a column vector, where the i-th entry
24 /// of the vector corresponds to the i-th coefficient.
25 /// It inverts the operation of [`PolyOverZq::from_coefficient_embedding`].
26 ///
27 /// Parameters:
28 /// - `size`: determines the number of rows of the embedding. It has to be larger
29 /// than the degree of the polynomial.
30 ///
31 /// Returns a coefficient embedding as a column vector if `size` is large enough.
32 ///
33 /// # Examples
34 /// ```
35 /// use std::str::FromStr;
36 /// use qfall_math::{
37 /// integer_mod_q::{MatZq, PolyOverZq},
38 /// traits::IntoCoefficientEmbedding,
39 /// };
40 ///
41 /// let poly = PolyOverZq::from_str("3 17 3 -5 mod 19").unwrap();
42 /// let vector = poly.into_coefficient_embedding(4);
43 /// let cmp_vector = MatZq::from_str("[[17],[3],[-5],[0]] mod 19").unwrap();
44 /// assert_eq!(cmp_vector, vector);
45 /// ```
46 ///
47 /// # Panics ...
48 /// - if `size` is not larger than the degree of the polynomial, i.e.
49 /// not all coefficients can be embedded.
50 fn into_coefficient_embedding(self, size: impl Into<i64>) -> MatZq {
51 let size = size.into();
52 let length = self.get_degree() + 1;
53 assert!(
54 size >= length,
55 "The polynomial can not be embedded in the vector, \
56 as the length of the polynomial ({length}) is larger than \
57 the provided size ({size})."
58 );
59 let mut out = MatZq::new(size, 1, &self.modulus);
60 for j in 0..size {
61 let coeff: Z = unsafe { self.get_coeff_unchecked(j) };
62 unsafe { out.set_entry_unchecked(j, 0, coeff) };
63 }
64
65 out
66 }
67}
68
69impl FromCoefficientEmbedding<&MatZq> for PolyOverZq {
70 /// Computes a polynomial from a vector.
71 /// The first i-th entry of the column vector is taken
72 /// as the coefficient of the polynomial.
73 /// It inverts the operation of
74 /// [`PolyOverZq::into_coefficient_embedding`](#method.into_coefficient_embedding).
75 ///
76 /// Parameters:
77 /// - `embedding`: the column vector that encodes the embedding
78 ///
79 /// Returns a polynomial that corresponds to the embedding.
80 ///
81 /// # Examples
82 /// ```
83 /// use std::str::FromStr;
84 /// use qfall_math::{
85 /// integer_mod_q::{MatZq, PolyOverZq},
86 /// traits::FromCoefficientEmbedding,
87 /// };
88 ///
89 /// let vector = MatZq::from_str("[[17],[3],[-5]] mod 19").unwrap();
90 /// let poly = PolyOverZq::from_coefficient_embedding(&vector);
91 /// let cmp_poly = PolyOverZq::from_str("3 17 3 -5 mod 19").unwrap();
92 /// assert_eq!(cmp_poly, poly);
93 /// ```
94 ///
95 /// # Panics ...
96 /// - if the provided embedding is not a column vector.
97 fn from_coefficient_embedding(embedding: &MatZq) -> Self {
98 assert!(
99 embedding.is_column_vector(),
100 "This is no valid embedding, since the matrix is no column vector."
101 );
102 let mut out = PolyOverZq::from(&embedding.get_mod());
103 for i in 0..embedding.get_num_rows() {
104 let entry: Z = unsafe { embedding.get_entry_unchecked(i, 0) };
105 unsafe { out.set_coeff_unchecked(i, entry) }
106 }
107 out
108 }
109}
110
111#[cfg(test)]
112mod test_into_coefficient_embedding {
113 use crate::{
114 integer_mod_q::{MatZq, PolyOverZq},
115 traits::IntoCoefficientEmbedding,
116 };
117 use std::str::FromStr;
118
119 /// Ensure that the embedding works with large entries.
120 #[test]
121 fn large_entries() {
122 let poly =
123 PolyOverZq::from_str(&format!("3 17 {} {} mod {}", i64::MAX, i64::MIN, u64::MAX))
124 .unwrap();
125
126 let vector = poly.into_coefficient_embedding(3);
127
128 let cmp_vector = MatZq::from_str(&format!(
129 "[[17],[{}],[{}]] mod {}",
130 i64::MAX,
131 i64::MIN,
132 u64::MAX
133 ))
134 .unwrap();
135 assert_eq!(cmp_vector, vector);
136 }
137
138 /// Ensure that the function panics if the the provided size is too small.
139 #[test]
140 #[should_panic]
141 fn size_too_small() {
142 let poly = PolyOverZq::from_str("3 17 1 2 mod 19").unwrap();
143
144 let _ = poly.into_coefficient_embedding(2);
145 }
146}
147
148#[cfg(test)]
149mod test_from_coefficient_embedding {
150 use crate::{
151 integer_mod_q::{MatZq, PolyOverZq},
152 traits::FromCoefficientEmbedding,
153 };
154 use std::str::FromStr;
155
156 /// Ensure that the embedding works with large entries.
157 #[test]
158 fn large_entries() {
159 let vector = MatZq::from_str(&format!(
160 "[[17],[{}],[{}]] mod {}",
161 i64::MAX,
162 i64::MIN,
163 u64::MAX
164 ))
165 .unwrap();
166
167 let poly = PolyOverZq::from_coefficient_embedding(&vector);
168
169 let cmp_poly =
170 PolyOverZq::from_str(&format!("3 17 {} {} mod {}", i64::MAX, i64::MIN, u64::MAX))
171 .unwrap();
172 assert_eq!(cmp_poly, poly);
173 }
174
175 /// Ensure that the function panics if the provided matrix is not a column vector.
176 #[test]
177 #[should_panic]
178 fn not_column_vector() {
179 let vector = MatZq::from_str("[[17, 1],[-17, -1],[5, 9]] mod 42").unwrap();
180
181 let _ = PolyOverZq::from_coefficient_embedding(&vector);
182 }
183}