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