qfall_math/integer_mod_q/poly_over_zq/sample/
uniform.rs1use crate::{
12 error::MathError,
13 integer::Z,
14 integer_mod_q::{Modulus, PolyOverZq},
15 macros::seeded::seedable_function,
16 traits::SetCoefficient,
17 utils::{index::evaluate_index, sample::uniform::UniformIntegerSampler},
18};
19use std::fmt::Display;
20
21impl PolyOverZq {
22 seedable_function!(
23 #[unseeded]
28 #[seeded]
30 #[optionally_seeded]
32 #[optionally_seeded]
34 #[seeded]
43 #[optionally_seeded]
45 #[optionally_seeded]
47 #[unseeded]
58 #[seeded]
60 pub(crate) fn sample_uniform(
72 max_degree: impl TryInto<i64> + Display + Copy,
73 modulus: impl Into<Z>,
74 seed: Option<[u8; 32]>,
75 ) -> Result<Self, MathError> {
76 let max_degree = evaluate_index(max_degree)?;
77 let interval_size = modulus.into();
78 let modulus = Modulus::from(&interval_size);
79 let mut poly_zq = PolyOverZq::from(&modulus);
80
81 let mut uis = UniformIntegerSampler::init(&interval_size, seed)?;
82
83 for index in 0..=max_degree {
84 let sample = uis.sample();
85 unsafe { poly_zq.set_coeff_unchecked(index, sample) };
86 }
87 Ok(poly_zq)
88 }
89 );
90}
91
92#[cfg(test)]
93mod test_sample_uniform {
94 use crate::utils::sample::test_seed;
95 use crate::{
96 integer::Z,
97 integer_mod_q::{Modulus, PolyOverZq},
98 traits::GetCoefficient,
99 };
100
101 #[test]
103 fn boundaries_kept_small() {
104 for seeded in [false, true] {
105 let modulus = Z::from(17);
106
107 let poly_zq =
108 PolyOverZq::sample_uniform_optionally_seeded(32, &modulus, seeded.then(test_seed))
109 .unwrap();
110
111 for i in 0..32 {
112 let sample: Z = poly_zq.get_coeff(i).unwrap();
113 assert!(Z::ZERO <= sample);
114 assert!(sample < modulus);
115 }
116 }
117 }
118
119 #[test]
121 fn boundaries_kept_large() {
122 for seeded in [false, true] {
123 let modulus = Z::from(i64::MAX);
124
125 let poly_zq =
126 PolyOverZq::sample_uniform_optionally_seeded(256, &modulus, seeded.then(test_seed))
127 .unwrap();
128
129 for i in 0..256 {
130 let sample: Z = poly_zq.get_coeff(i).unwrap();
131 assert!(Z::ZERO <= sample);
132 assert!(sample < modulus);
133 }
134 }
135 }
136
137 #[test]
139 fn nr_coeffs() {
140 for seeded in [false, true] {
141 let degrees = [1, 3, 7, 15, 32, 120];
142 for degree in degrees {
143 let res = PolyOverZq::sample_uniform_optionally_seeded(
144 degree,
145 u64::MAX,
146 seeded.then(test_seed),
147 )
148 .unwrap();
149
150 assert_eq!(
151 degree,
152 res.get_degree(),
153 "Could fail with probability 1/{}.",
154 u64::MAX
155 );
156 }
157 }
158 }
159
160 #[test]
162 fn invalid_modulus_negative() {
163 for seeded in [false, true] {
164 let result = std::panic::catch_unwind(|| {
165 let _ = PolyOverZq::sample_uniform_optionally_seeded(
166 1,
167 i64::MIN,
168 seeded.then(test_seed),
169 );
170 });
171 assert!(result.is_err());
172 }
173 }
174
175 #[test]
177 fn invalid_modulus_one() {
178 for seeded in [false, true] {
179 let result = std::panic::catch_unwind(|| {
180 let _ = PolyOverZq::sample_uniform_optionally_seeded(1, 1, seeded.then(test_seed));
181 });
182 assert!(result.is_err());
183 }
184 }
185
186 #[test]
188 fn invalid_max_degree() {
189 for seeded in [false, true] {
190 let modulus = Z::from(15);
191
192 let res_0 =
193 PolyOverZq::sample_uniform_optionally_seeded(-1, &modulus, seeded.then(test_seed));
194 let res_1 = PolyOverZq::sample_uniform_optionally_seeded(
195 i64::MIN,
196 &modulus,
197 seeded.then(test_seed),
198 );
199
200 assert!(res_0.is_err());
201 assert!(res_1.is_err());
202 }
203 }
204
205 #[test]
208 fn availability() {
209 for seeded in [false, true] {
210 let modulus = Modulus::from(10);
211 let z = Z::from(10);
212
213 let _ =
214 PolyOverZq::sample_uniform_optionally_seeded(1u64, 10u16, seeded.then(test_seed))
215 .unwrap();
216 let _ =
217 PolyOverZq::sample_uniform_optionally_seeded(1i64, 10u32, seeded.then(test_seed))
218 .unwrap();
219 let _ =
220 PolyOverZq::sample_uniform_optionally_seeded(1u8, 10u64, seeded.then(test_seed))
221 .unwrap();
222 let _ =
223 PolyOverZq::sample_uniform_optionally_seeded(1u16, 10i8, seeded.then(test_seed))
224 .unwrap();
225 let _ =
226 PolyOverZq::sample_uniform_optionally_seeded(1u32, 10i16, seeded.then(test_seed))
227 .unwrap();
228 let _ =
229 PolyOverZq::sample_uniform_optionally_seeded(1i32, 10i32, seeded.then(test_seed))
230 .unwrap();
231 let _ =
232 PolyOverZq::sample_uniform_optionally_seeded(1i16, 10i64, seeded.then(test_seed))
233 .unwrap();
234 let _ = PolyOverZq::sample_uniform_optionally_seeded(1i8, &z, seeded.then(test_seed))
235 .unwrap();
236 let _ =
237 PolyOverZq::sample_uniform_optionally_seeded(1, z, seeded.then(test_seed)).unwrap();
238 let _ =
239 PolyOverZq::sample_uniform_optionally_seeded(1, &modulus, seeded.then(test_seed))
240 .unwrap();
241 let _ =
242 PolyOverZq::sample_uniform_optionally_seeded(1, modulus, seeded.then(test_seed))
243 .unwrap();
244
245 if seeded {
247 let _ = PolyOverZq::sample_uniform_seeded(1u64, 10u16, test_seed());
248 } else {
249 let _ = PolyOverZq::sample_uniform(1u64, 10u16);
250 }
251 }
252 }
253
254 #[test]
256 fn same_seed_same_sample() {
257 use crate::integer_mod_q::PolyOverZq;
258 let sample_0 = PolyOverZq::sample_uniform_seeded(3, 17, [42; 32]).unwrap();
259 let sample_1 = PolyOverZq::sample_uniform_seeded(3, 17, [42; 32]).unwrap();
260
261 assert_eq!(sample_0, sample_1);
262 }
263
264 #[test]
266 fn known_answer() {
267 use crate::integer_mod_q::PolyOverZq;
268 let sample = PolyOverZq::sample_uniform_seeded(3, 17, [42; 32]).unwrap();
269
270 assert_eq!("4 2 16 3 7 mod 17", sample.to_string());
271 }
272}