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}