qfall_math/integer_mod_q/ntt_polynomial_ring_zq/
from.rs

1// Copyright © 2025 Niklas Siemer
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//! Implementations to create a [`NTTPolynomialRingZq`] value from other types.
10
11use super::NTTPolynomialRingZq;
12use crate::integer_mod_q::{PolyOverZq, PolynomialRingZq};
13
14impl From<&PolynomialRingZq> for NTTPolynomialRingZq {
15    /// Computes the NTT representation of `poly`.
16    ///
17    /// Parameters:
18    /// - `poly`: the polynomial that's going to be represented in NTT form.
19    ///
20    /// Returns the NTT representation as a [`NTTPolynomialRingZq`] of `poly`.
21    ///
22    /// # Examples
23    /// ```
24    /// use qfall_math::integer_mod_q::{NTTPolynomialRingZq, PolynomialRingZq, ModulusPolynomialRingZq, PolyOverZq};
25    /// use crate::qfall_math::traits::SetCoefficient;
26    /// use std::str::FromStr;
27    ///
28    /// let n = 4;
29    /// let modulus = 7681;
30    ///
31    /// let mut mod_poly = PolyOverZq::from(modulus);
32    /// mod_poly.set_coeff(0, 1).unwrap();
33    /// mod_poly.set_coeff(n, 1).unwrap();
34    ///
35    /// let mut polynomial_modulus = ModulusPolynomialRingZq::from(&mod_poly);
36    /// polynomial_modulus.set_ntt_unchecked(1925);
37    ///
38    /// let poly_ring = PolynomialRingZq::sample_uniform(&polynomial_modulus);
39    ///
40    /// let ntt_poly_ring = NTTPolynomialRingZq::from(&poly_ring);
41    /// ```
42    ///
43    /// # Panics ...
44    /// - if the [`NTTBasisPolynomialRingZq`](crate::integer_mod_q::NTTBasisPolynomialRingZq),
45    ///   which is part of the [`ModulusPolynomialRingZq`](crate::integer_mod_q::ModulusPolynomialRingZq) in `poly`
46    ///   is not set.
47    fn from(poly: &PolynomialRingZq) -> Self {
48        if let Some(ntt_basis) = poly.modulus.ntt_basis.as_ref() {
49            let value = PolyOverZq::from((
50                &poly.get_representative_least_nonnegative_residue(),
51                poly.get_mod().get_q(),
52            ));
53            NTTPolynomialRingZq {
54                poly: ntt_basis.ntt(&value),
55                modulus: poly.modulus.clone(),
56            }
57        } else {
58            panic!("The NTTBasisPolynomialRingZq is not set.")
59        }
60    }
61}
62
63impl NTTPolynomialRingZq {
64    /// Computes the inverse NTT of `self` with respect to the given `modulus`.
65    ///
66    /// Returns a new [`PolynomialRingZq`] with the specified [`ModulusPolynomialRingZq`](crate::integer_mod_q::ModulusPolynomialRingZq)
67    /// and values as defined in `self`.
68    ///
69    /// # Examples
70    /// ```
71    /// use qfall_math::integer_mod_q::{PolynomialRingZq, PolyOverZq, ModulusPolynomialRingZq, NTTPolynomialRingZq};
72    /// use qfall_math::traits::SetCoefficient;
73    ///
74    /// let n = 4;
75    /// let modulus = 7681;
76    ///
77    /// let mut mod_poly = PolyOverZq::from(modulus);
78    /// mod_poly.set_coeff(0, 1).unwrap();
79    /// mod_poly.set_coeff(n, 1).unwrap();
80    ///
81    /// let mut polynomial_modulus = ModulusPolynomialRingZq::from(&mod_poly);
82    /// polynomial_modulus.set_ntt_unchecked(1925);
83    ///
84    /// let ntt = NTTPolynomialRingZq::sample_uniform(&polynomial_modulus);
85    ///
86    /// let res = ntt.inv_ntt();
87    /// ```
88    ///
89    /// # Panics ...
90    /// - if the [`NTTBasisPolynomialRingZq`](crate::integer_mod_q::NTTBasisPolynomialRingZq) in `modulus`
91    ///   is not set.
92    pub fn inv_ntt(self) -> PolynomialRingZq {
93        self.modulus
94            .ntt_basis
95            .as_ref()
96            .as_ref()
97            .map(|basis| PolynomialRingZq {
98                poly: basis
99                    .inv_ntt(self.poly)
100                    .get_representative_least_nonnegative_residue(),
101                modulus: self.modulus.clone(),
102            })
103            .unwrap()
104    }
105}
106
107#[cfg(test)]
108mod test_from {
109    use crate::{
110        integer::{PolyOverZ, Z},
111        integer_mod_q::{ModulusPolynomialRingZq, NTTPolynomialRingZq, PolynomialRingZq},
112    };
113    use std::str::FromStr;
114
115    /// Ensures that from [`PolynomialRingZq`] works properly.
116    #[test]
117    fn from_polynomial_ring_zq() {
118        let mut modulus = ModulusPolynomialRingZq::from_str("5  1 0 0 0 1 mod 257").unwrap();
119        modulus.set_ntt_unchecked(64);
120        let poly = PolyOverZ::from_str("4  130 99 64 210").unwrap();
121        let poly_ring_zq = PolynomialRingZq::from((&poly, &modulus));
122        let cmp = vec![Z::from(114), Z::from(84), Z::from(154), Z::from(168)];
123
124        let ntt_poly = NTTPolynomialRingZq::from(&poly_ring_zq);
125
126        assert_eq!(ntt_poly.poly, cmp);
127    }
128}