qfall_math/integer_mod_q/polynomial_ring_zq/sample/
discrete_gauss.rs1use crate::{
13 error::MathError,
14 integer::PolyOverZ,
15 integer_mod_q::{ModulusPolynomialRingZq, PolynomialRingZq},
16 rational::Q,
17};
18
19impl PolynomialRingZq {
20 pub fn sample_discrete_gauss(
51 modulus: impl Into<ModulusPolynomialRingZq>,
52 center: impl Into<Q>,
53 s: impl Into<Q>,
54 ) -> Result<Self, MathError> {
55 let modulus = modulus.into();
56 assert!(
57 modulus.get_degree() > 0,
58 "ModulusPolynomial of degree 0 is insufficient to sample over."
59 );
60
61 let poly_z = PolyOverZ::sample_discrete_gauss(modulus.get_degree() - 1, center, s)?;
62 let mut poly_ringzq = PolynomialRingZq {
63 poly: poly_z,
64 modulus,
65 };
66 poly_ringzq.reduce();
67
68 Ok(poly_ringzq)
69 }
70}
71
72#[cfg(test)]
73mod test_sample_discrete_gauss {
74 use crate::{
75 integer::Z,
76 integer_mod_q::{ModulusPolynomialRingZq, PolyOverZq, PolynomialRingZq},
77 rational::Q,
78 traits::{GetCoefficient, SetCoefficient},
79 };
80 use std::str::FromStr;
81
82 #[test]
86 fn availability() {
87 let center = Q::ZERO;
88 let s = Q::ONE;
89 let modulus = ModulusPolynomialRingZq::from_str("4 1 0 0 1 mod 17").unwrap();
90
91 let _ = PolynomialRingZq::sample_discrete_gauss(&modulus, 0f32, 1u8);
92 let _ = PolynomialRingZq::sample_discrete_gauss(&modulus, 0f64, 1u16);
93 let _ = PolynomialRingZq::sample_discrete_gauss(&modulus, 0f32, 1u32);
94 let _ = PolynomialRingZq::sample_discrete_gauss(&modulus, 0f64, 1u64);
95 let _ = PolynomialRingZq::sample_discrete_gauss(&modulus, 0f32, 1i8);
96 let _ = PolynomialRingZq::sample_discrete_gauss(&modulus, 0f32, 1i16);
97 let _ = PolynomialRingZq::sample_discrete_gauss(&modulus, 0f32, 1i32);
98 let _ = PolynomialRingZq::sample_discrete_gauss(&modulus, 0f64, 1i64);
99 let _ = PolynomialRingZq::sample_discrete_gauss(&modulus, center, s);
100 let _ = PolynomialRingZq::sample_discrete_gauss(&modulus, 0f32, 1f64);
101 }
102
103 #[test]
105 fn boundaries_kept_small() {
106 let modulus = ModulusPolynomialRingZq::from_str("4 1 0 0 1 mod 17").unwrap();
107
108 for _ in 0..32 {
109 let poly = PolynomialRingZq::sample_discrete_gauss(&modulus, 15, 1).unwrap();
110
111 for i in 0..3 {
112 let sample: Z = poly.get_coeff(i).unwrap();
113 assert!(Z::ZERO <= sample);
114 assert!(sample < modulus.get_q());
115 }
116 }
117 }
118
119 #[test]
121 fn boundaries_kept_large() {
122 let modulus =
123 ModulusPolynomialRingZq::from_str(&format!("4 1 0 0 1 mod {}", u64::MAX)).unwrap();
124
125 for _ in 0..256 {
126 let poly = PolynomialRingZq::sample_discrete_gauss(&modulus, 1, 1).unwrap();
127
128 for i in 0..3 {
129 let sample: Z = poly.get_coeff(i).unwrap();
130 assert!(Z::ZERO <= sample);
131 assert!(sample < modulus.get_q());
132 }
133 }
134 }
135
136 #[test]
138 fn nr_coeffs() {
139 let degrees = [1, 3, 7, 15, 32, 120];
140 for degree in degrees {
141 let mut modulus = PolyOverZq::from((1, u64::MAX));
142 modulus.set_coeff(degree, 1).unwrap();
143 let modulus = ModulusPolynomialRingZq::from(&modulus);
144
145 let res = PolynomialRingZq::sample_discrete_gauss(&modulus, i64::MAX, 1).unwrap();
146
147 assert_eq!(
148 res.get_degree() + 1,
149 modulus.get_degree(),
150 "Could fail with negligible probability."
151 );
152 }
153 }
154
155 #[test]
157 #[should_panic]
158 fn invalid_modulus() {
159 let modulus = ModulusPolynomialRingZq::from_str("1 1 mod 17").unwrap();
160
161 let _ = PolynomialRingZq::sample_discrete_gauss(&modulus, 0, 1).unwrap();
162 }
163}