qfall_tools/utils/common_moduli.rs
1// Copyright © 2023 Niklas Siemer
2//
3// This file is part of qFALL-tools.
4//
5// qFALL-tools 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//! Contains functions to quickly instantiate
10//! common moduli for ring-based lattice cryptography.
11
12use qfall_math::{
13 error::MathError,
14 integer_mod_q::{Modulus, ModulusPolynomialRingZq, PolyOverZq},
15 traits::SetCoefficient,
16};
17use std::fmt::Display;
18
19/// Outputs a [`ModulusPolynomialRingZq`] of the form `X^n + 1 mod q`.
20///
21/// Parameters:
22/// - `n`: specifies the degree of the modulus polynomial
23/// - `q`: specifies the modulus of the modulus polynomial
24///
25/// Returns a [`ModulusPolynomialRingZq`] of the form `X^n + 1 mod q` or
26/// a [`MathError`] if `q <= 1`, `n < 0`, or `n` does not into an [`i64`].
27///
28/// # Examples
29/// ```
30/// use qfall_tools::utils::common_moduli::new_anticyclic;
31///
32/// let poly_mod = new_anticyclic(8, 17);
33/// ```
34///
35/// # Errors and Failures
36/// - Returns a [`MathError`] of type [`OutOfBounds`](MathError::OutOfBounds) if
37/// the `n` is negative or it does not fit into an [`i64`].
38///
39/// # Panics ...
40/// - if the `q` is not larger than `1`.
41pub fn new_anticyclic(
42 n: impl TryInto<i64> + Display,
43 q: impl Into<Modulus>,
44) -> Result<ModulusPolynomialRingZq, MathError> {
45 let mut poly = PolyOverZq::from((1, q));
46 poly.set_coeff(n, 1)?;
47 Ok(ModulusPolynomialRingZq::from(&poly))
48}
49
50/// Outputs a [`ModulusPolynomialRingZq`] of the form `X^n - 1 mod q`.
51///
52/// Parameters:
53/// - `n`: specifies the degree of the modulus polynomial
54/// - `q`: specifies the modulus of the modulus polynomial
55///
56/// Returns a [`ModulusPolynomialRingZq`] of the form `X^n - 1 mod q` or
57/// a [`MathError`] if `q <= 1`, `n < 0`, or `n` does not into an [`i64`].
58///
59/// # Examples
60/// ```
61/// use qfall_tools::utils::common_moduli::new_cyclic;
62///
63/// let poly_mod = new_cyclic(8, 17);
64/// ```
65///
66/// # Errors and Failures
67/// - Returns a [`MathError`] of type [`OutOfBounds`](MathError::OutOfBounds) if
68/// the `n` is negative or it does not fit into an [`i64`].
69///
70/// # Panics ...
71/// - if the `q` is not larger than `1`.
72pub fn new_cyclic(
73 n: impl TryInto<i64> + Display,
74 q: impl Into<Modulus>,
75) -> Result<ModulusPolynomialRingZq, MathError> {
76 let mut poly = PolyOverZq::from((-1, q));
77 poly.set_coeff(n, 1)?;
78 Ok(ModulusPolynomialRingZq::from(&poly))
79}
80
81#[cfg(test)]
82mod test_new_anticyclic {
83 use super::new_anticyclic;
84 use qfall_math::{integer::Z, integer_mod_q::PolyOverZq, traits::GetCoefficient};
85
86 /// Ensure that the modulus polynomial has the specified degree.
87 #[test]
88 fn degree() {
89 let degrees = [1, 4, 7, 16, 32, 128];
90 for degree in degrees {
91 let poly_mod = new_anticyclic(degree, 7).unwrap();
92
93 assert_eq!(degree, poly_mod.get_degree());
94 }
95 }
96
97 /// Check whether the method outputs the correct polynomial.
98 #[test]
99 fn correct_polynomial() {
100 let degrees = [1, 4, 7, 16, 32, 128];
101 for degree in degrees {
102 let poly_mod = new_anticyclic(degree, 7).unwrap();
103 let poly_zq = PolyOverZq::from(&poly_mod);
104
105 assert_eq!(
106 Z::ONE,
107 GetCoefficient::<Z>::get_coeff(&poly_zq, degree).unwrap()
108 );
109 assert_eq!(Z::ONE, GetCoefficient::<Z>::get_coeff(&poly_zq, 0).unwrap());
110 for i in 1..degree {
111 assert_eq!(
112 Z::ZERO,
113 GetCoefficient::<Z>::get_coeff(&poly_zq, i).unwrap()
114 );
115 }
116 }
117 }
118
119 /// Ensures that the correct modulus is set as
120 /// the integer modulus of the output modulus polynomial.
121 #[test]
122 fn correct_modulus() {
123 let moduli = [7, 10, i64::MAX];
124 for modulus in moduli {
125 let poly_mod = new_anticyclic(2, modulus).unwrap();
126
127 assert_eq!(Z::from(modulus), poly_mod.get_q());
128 }
129 }
130
131 /// Ensures that an invalid degree for the modulus polynomial results in an error.
132 #[test]
133 fn invalid_n() {
134 let res = new_anticyclic(-1, 7);
135
136 assert!(res.is_err());
137 }
138
139 /// Ensures that an invalid modulus for the modulus polynomial results in a panic.
140 #[test]
141 #[should_panic]
142 fn invalid_modulus() {
143 let _ = new_anticyclic(2, 0);
144 }
145}
146
147#[cfg(test)]
148mod test_new_cyclic {
149 use super::new_cyclic;
150 use qfall_math::{integer::Z, integer_mod_q::PolyOverZq, traits::GetCoefficient};
151
152 /// Ensure that the modulus polynomial has the specified degree.
153 #[test]
154 fn degree() {
155 let degrees = [1, 4, 7, 16, 32, 128];
156 for degree in degrees {
157 let poly_mod = new_cyclic(degree, 7).unwrap();
158
159 assert_eq!(degree, poly_mod.get_degree());
160 }
161 }
162
163 /// Check whether the method outputs the correct polynomial.
164 #[test]
165 fn correct_polynomial() {
166 let degrees = [1, 4, 7, 16, 32, 128];
167 for degree in degrees {
168 let poly_mod = new_cyclic(degree, 7).unwrap();
169 let poly_zq = PolyOverZq::from(&poly_mod);
170
171 assert_eq!(
172 Z::ONE,
173 GetCoefficient::<Z>::get_coeff(&poly_zq, degree).unwrap()
174 );
175 assert_eq!(
176 Z::from(6),
177 GetCoefficient::<Z>::get_coeff(&poly_zq, 0).unwrap()
178 );
179 for i in 1..degree {
180 assert_eq!(
181 Z::ZERO,
182 GetCoefficient::<Z>::get_coeff(&poly_zq, i).unwrap()
183 );
184 }
185 }
186 }
187
188 /// Ensures that the correct modulus is set as
189 /// the integer modulus of the output modulus polynomial.
190 #[test]
191 fn correct_modulus() {
192 let moduli = [7, 10, i64::MAX];
193 for modulus in moduli {
194 let poly_mod = new_cyclic(2, modulus).unwrap();
195
196 assert_eq!(Z::from(modulus), poly_mod.get_q());
197 }
198 }
199
200 /// Ensures that an invalid degree for the modulus polynomial results in an error.
201 #[test]
202 fn invalid_n() {
203 let res = new_cyclic(-1, 7);
204
205 assert!(res.is_err());
206 }
207
208 /// Ensures that an invalid modulus for the modulus polynomial results in a panic.
209 #[test]
210 #[should_panic]
211 fn invalid_modulus() {
212 let _ = new_cyclic(2, 0);
213 }
214}