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}