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}