qfall_math/integer_mod_q/modulus_polynomial_ring_zq/
ntt_basis.rs

1// Copyright © 2025 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 instantiate
10//! the ntt basis for a given `[ModulusPolynomialRingZq`] object.
11//!
12//! This includes a collection of fixed NTT-viable rings, and the option to set them
13//! unchecked.
14//!
15//! The explicit functions contain the documentation.
16
17use super::ModulusPolynomialRingZq;
18use crate::{
19    integer::Z,
20    integer_mod_q::{
21        Modulus,
22        ntt_basis_polynomial_ring_zq::{ConvolutionType, NTTBasisPolynomialRingZq},
23    },
24    traits::GetCoefficient,
25};
26use std::rc::Rc;
27
28impl ModulusPolynomialRingZq {
29    /// Initiates the NTT-basis for the [`ModulusPolynomialRingZq`] by providing a
30    /// root of unity.
31    /// It is not checked if it is actually a root of unity.
32    /// Based on the constant coefficient, it will either be instantiated for cyclic or negacyclic convolution.
33    /// If it is 1, then it will be interpreted as negacyclic and as cyclic otherwise.
34    /// The rest of the modulus-polynomial will not be checked, whether it is suited, and it will not be checked
35    /// if the provided root is actually a root of unity in the ring.
36    /// Setting the basis only works if `n` is a power of two.
37    ///
38    /// Parameters:
39    /// - `root_of_unity`: the `n`th or respectivley `2n`th root of unity over the modulus
40    ///
41    /// Defines the NTT-basis for the modulus ring without checking the context.
42    ///
43    /// # Examples
44    /// ```
45    /// use qfall_math::integer_mod_q::ModulusPolynomialRingZq;
46    /// use qfall_math::integer_mod_q::PolyOverZq;
47    /// use crate::qfall_math::traits::SetCoefficient;
48    ///
49    /// let n = 256;
50    /// let modulus = 2_i64.pow(23) - 2_i64.pow(13) + 1;
51    ///
52    /// let mut mod_poly = PolyOverZq::from(modulus);
53    /// mod_poly.set_coeff(0, 1).unwrap();
54    /// mod_poly.set_coeff(n, 1).unwrap();
55    ///
56    /// let mut polynomial_modulus = ModulusPolynomialRingZq::from(&mod_poly);
57    ///
58    /// polynomial_modulus.set_ntt_unchecked(1753);
59    /// ```
60    ///
61    /// # Safety
62    /// The caller is responsible in ensuring that the  given root is actually a proper
63    /// root, under the associated polynomial. For negacyclic polynomials, this means
64    /// that the root must be a 2nth root of unity and for cyclic polynomials this means
65    /// that it must be an nth root.
66    ///
67    /// # Panics
68    /// - if `n` is not a power of two.
69    pub fn set_ntt_unchecked(&mut self, root_of_unity: impl Into<Z>) {
70        let n = self.get_degree();
71        let one_coeff: Z = self.get_coeff(0).unwrap();
72
73        let convolution_type = {
74            if one_coeff == Z::ONE {
75                ConvolutionType::Negacyclic
76            } else {
77                ConvolutionType::Cyclic
78            }
79        };
80
81        let ntt_basis = NTTBasisPolynomialRingZq::init(
82            n as usize,
83            root_of_unity,
84            Modulus::from(self.get_q()),
85            convolution_type,
86        );
87        self.ntt_basis = Rc::new(Some(ntt_basis))
88    }
89}