qfall_math/integer/z/sample/
uniform.rs1use crate::{
12 error::MathError, integer::Z, macros::seeded::seedable_function,
13 utils::sample::uniform::UniformIntegerSampler,
14};
15
16impl Z {
17 seedable_function!(
18 #[unseeded]
23 #[seeded]
25 #[optionally_seeded]
27 #[optionally_seeded]
29 #[seeded]
38 #[optionally_seeded]
40 #[optionally_seeded]
42 #[unseeded]
53 #[seeded]
55 pub(crate) fn sample_uniform(
62 lower_bound: impl Into<Z>,
63 upper_bound: impl Into<Z>,
64 seed: Option<[u8; 32]>,
65 ) -> Result<Self, MathError> {
66 let lower_bound: Z = lower_bound.into();
67 let upper_bound: Z = upper_bound.into();
68
69 let interval_size = &upper_bound - &lower_bound;
70 let mut uis = UniformIntegerSampler::init(&interval_size, seed)?;
71
72 let sample = uis.sample();
73 Ok(&lower_bound + sample)
74 }
75 );
76
77 seedable_function!(
78 #[unseeded]
84 #[seeded]
86 #[optionally_seeded]
88 #[optionally_seeded]
90 #[seeded]
99 #[optionally_seeded]
101 #[optionally_seeded]
103 #[unseeded]
115 #[seeded]
117 pub(crate) fn sample_prime_uniform(
127 lower_bound: impl Into<Z>,
128 upper_bound: impl Into<Z>,
129 seed: Option<[u8; 32]>,
130 ) -> Result<Self, MathError> {
131 let lower_bound: Z = lower_bound.into();
132 let upper_bound: Z = upper_bound.into();
133
134 if lower_bound < Z::ZERO {
135 return Err(MathError::InvalidIntegerInput(format!(
136 "Primes are always positive. Hence, sample_prime_uniform expects a positive lower_bound.
137 The provided one is {lower_bound}.")));
138 }
139
140 let interval_size = &upper_bound - &lower_bound;
141 let mut uis = UniformIntegerSampler::init(&interval_size, seed)?;
142 let mut sample = &lower_bound + uis.sample();
143
144 let mut steps = 2 * &interval_size;
147 while !sample.is_prime() {
148 if steps == Z::ZERO {
149 return Err(MathError::InvalidInterval(format!(
150 "After sampling O({interval_size}) times uniform at random in the interval [{lower_bound}, {upper_bound}[
151 no prime was found. It is very likely, that no prime exists in this interval.
152 Please choose the interval larger.")));
153 }
154 sample = &lower_bound + uis.sample();
155 steps -= 1;
156 }
157
158 Ok(sample)
159 }
160 );
161}
162
163#[cfg(test)]
164mod test_sample_uniform {
165 use crate::utils::sample::test_seed;
166 use crate::{integer::Z, integer_mod_q::Modulus};
167
168 #[test]
170 fn boundaries_kept_small() {
171 for seeded in [false, true] {
172 let lower_bound = Z::from(17);
173 let upper_bound = Z::from(32);
174 for _ in 0..32 {
175 let sample = Z::sample_uniform_optionally_seeded(
176 &lower_bound,
177 &upper_bound,
178 seeded.then(test_seed),
179 )
180 .unwrap();
181 assert!(lower_bound <= sample);
182 assert!(sample < upper_bound);
183 }
184 }
185 }
186
187 #[test]
189 fn boundaries_kept_large() {
190 for seeded in [false, true] {
191 let lower_bound = Z::from(i64::MIN) - Z::from(u64::MAX);
192 let upper_bound = Z::from(i64::MIN);
193 for _ in 0..256 {
194 let sample = Z::sample_uniform_optionally_seeded(
195 &lower_bound,
196 &upper_bound,
197 seeded.then(test_seed),
198 )
199 .unwrap();
200 assert!(lower_bound <= sample);
201 assert!(sample < upper_bound);
202 }
203 }
204 }
205
206 #[test]
208 fn invalid_interval() {
209 for seeded in [false, true] {
210 let lb_0 = Z::from(i64::MIN);
211 let lb_1 = Z::from(i64::MIN);
212 let lb_2 = Z::ZERO;
213 let upper_bound = Z::from(i64::MIN);
214
215 let res_0 =
216 Z::sample_uniform_optionally_seeded(&lb_0, &upper_bound, seeded.then(test_seed));
217 let res_1 =
218 Z::sample_uniform_optionally_seeded(&lb_1, &upper_bound, seeded.then(test_seed));
219 let res_2 =
220 Z::sample_uniform_optionally_seeded(&lb_2, &upper_bound, seeded.then(test_seed));
221
222 assert!(res_0.is_err());
223 assert!(res_1.is_err());
224 assert!(res_2.is_err());
225 }
226 }
227
228 #[test]
231 fn availability() {
232 for seeded in [false, true] {
233 let modulus = Modulus::from(7);
234 let z = Z::from(7);
235
236 let _ = Z::sample_uniform_optionally_seeded(0u16, 7u8, seeded.then(test_seed));
237 let _ = Z::sample_uniform_optionally_seeded(0u32, 7u16, seeded.then(test_seed));
238 let _ = Z::sample_uniform_optionally_seeded(0u64, 7u32, seeded.then(test_seed));
239 let _ = Z::sample_uniform_optionally_seeded(0i8, 7u64, seeded.then(test_seed));
240 let _ = Z::sample_uniform_optionally_seeded(0i16, 7i8, seeded.then(test_seed));
241 let _ = Z::sample_uniform_optionally_seeded(0i32, 7i16, seeded.then(test_seed));
242 let _ = Z::sample_uniform_optionally_seeded(0i64, 7i32, seeded.then(test_seed));
243 let _ = Z::sample_uniform_optionally_seeded(&Z::ZERO, 7i64, seeded.then(test_seed));
244 let _ = Z::sample_uniform_optionally_seeded(0u8, &modulus, seeded.then(test_seed));
245 let _ = Z::sample_uniform_optionally_seeded(0, &z, seeded.then(test_seed));
246
247 if seeded {
249 let _ = Z::sample_uniform_seeded(0u16, 7u8, test_seed());
250 } else {
251 let _ = Z::sample_uniform(0u16, 7u8);
252 }
253 }
254 }
255
256 #[test]
260 fn uniformity() {
261 for seeded in [false, true] {
262 let lower_bound = Z::ZERO;
263 let upper_bound = Z::from(5);
264 let mut counts = [0; 5];
265 for _ in 0..1000 {
267 let sample_z = Z::sample_uniform_optionally_seeded(
268 &lower_bound,
269 &upper_bound,
270 seeded.then(test_seed),
271 )
272 .unwrap();
273 let sample_int = i64::try_from(&sample_z).unwrap() as usize;
274 counts[sample_int] += 1;
275 }
276
277 for count in counts {
280 assert!(count > 150, "This test can fail with probability close to 0.
281 It fails if the sampled occurrences do not look like a typical uniform random distribution.
282 If this happens, rerun the tests several times and check whether this issue comes up again.");
283 }
284 }
285 }
286
287 #[test]
289 fn same_seed_same_sample() {
290 use crate::integer::Z;
291 let sample_0 = Z::sample_uniform_seeded(17, 26, [42; 32]).unwrap();
292 let sample_1 = Z::sample_uniform_seeded(17, 26, [42; 32]).unwrap();
293
294 assert_eq!(sample_0, sample_1);
295 }
296
297 #[test]
299 fn known_answer() {
300 use crate::integer::Z;
301 let sample = Z::sample_uniform_seeded(17, 26, [42; 32]).unwrap();
302
303 assert_eq!("19", sample.to_string());
304 }
305}
306
307#[cfg(test)]
308mod test_sample_prime_uniform {
309 use crate::utils::sample::test_seed;
310 use crate::{integer::Z, integer_mod_q::Modulus};
311
312 #[test]
314 fn is_prime() {
315 for seeded in [false, true] {
316 for _ in 0..8 {
317 let sample =
318 Z::sample_prime_uniform_optionally_seeded(20, i64::MAX, seeded.then(test_seed))
319 .unwrap();
320 assert!(sample.is_prime(), "Can fail with probability ~2^-60.");
321 }
322 }
323 }
324
325 #[test]
328 fn no_prime_exists() {
329 for seeded in [false, true] {
330 let res_0 = Z::sample_prime_uniform_optionally_seeded(14, 17, seeded.then(test_seed));
331 let res_1 = Z::sample_prime_uniform_optionally_seeded(
333 u64::MAX - 57,
334 u64::MAX,
335 seeded.then(test_seed),
336 );
337
338 assert!(res_0.is_err());
339 assert!(res_1.is_err());
340 }
341 }
342
343 #[test]
345 fn negative_lower_bound() {
346 for seeded in [false, true] {
347 let res_0 = Z::sample_prime_uniform_optionally_seeded(-1, 10, seeded.then(test_seed));
348 let res_1 = Z::sample_prime_uniform_optionally_seeded(-200, 1, seeded.then(test_seed));
349
350 assert!(res_0.is_err());
351 assert!(res_1.is_err());
352 }
353 }
354
355 #[test]
357 fn boundaries_kept_small() {
358 for seeded in [false, true] {
359 let lower_bound = Z::from(17);
360 let upper_bound = Z::from(32);
361 for _ in 0..32 {
362 let sample = Z::sample_prime_uniform_optionally_seeded(
363 &lower_bound,
364 &upper_bound,
365 seeded.then(test_seed),
366 )
367 .unwrap();
368 assert!(lower_bound <= sample);
369 assert!(sample < upper_bound);
370 }
371 }
372 }
373
374 #[test]
376 fn boundaries_kept_large() {
377 for seeded in [false, true] {
378 let lower_bound = Z::ZERO;
379 let upper_bound = Z::from(i64::MAX);
380 for _ in 0..256 {
381 let sample = Z::sample_prime_uniform_optionally_seeded(
382 &lower_bound,
383 &upper_bound,
384 seeded.then(test_seed),
385 )
386 .unwrap();
387 assert!(lower_bound <= sample);
388 assert!(sample < upper_bound);
389 }
390 }
391 }
392
393 #[test]
395 fn invalid_interval() {
396 for seeded in [false, true] {
397 let lb_0 = Z::from(i64::MIN) - Z::ONE;
398 let lb_1 = Z::from(i64::MIN);
399 let lb_2 = Z::ZERO;
400 let upper_bound = Z::from(i64::MIN);
401
402 let res_0 = Z::sample_prime_uniform_optionally_seeded(
403 &lb_0,
404 &upper_bound,
405 seeded.then(test_seed),
406 );
407 let res_1 = Z::sample_prime_uniform_optionally_seeded(
408 &lb_1,
409 &upper_bound,
410 seeded.then(test_seed),
411 );
412 let res_2 = Z::sample_prime_uniform_optionally_seeded(
413 &lb_2,
414 &upper_bound,
415 seeded.then(test_seed),
416 );
417
418 assert!(res_0.is_err());
419 assert!(res_1.is_err());
420 assert!(res_2.is_err());
421 }
422 }
423
424 #[test]
427 fn availability() {
428 for seeded in [false, true] {
429 let modulus = Modulus::from(7);
430 let z = Z::from(7);
431
432 let _ = Z::sample_prime_uniform_optionally_seeded(0u16, 7u8, seeded.then(test_seed));
433 let _ = Z::sample_prime_uniform_optionally_seeded(0u32, 7u16, seeded.then(test_seed));
434 let _ = Z::sample_prime_uniform_optionally_seeded(0u64, 7u32, seeded.then(test_seed));
435 let _ = Z::sample_prime_uniform_optionally_seeded(0i8, 7u64, seeded.then(test_seed));
436 let _ = Z::sample_prime_uniform_optionally_seeded(0i16, 7i8, seeded.then(test_seed));
437 let _ = Z::sample_prime_uniform_optionally_seeded(0i32, 7i16, seeded.then(test_seed));
438 let _ = Z::sample_prime_uniform_optionally_seeded(0i64, 7i32, seeded.then(test_seed));
439 let _ =
440 Z::sample_prime_uniform_optionally_seeded(&Z::ZERO, 7i64, seeded.then(test_seed));
441 let _ =
442 Z::sample_prime_uniform_optionally_seeded(0u8, &modulus, seeded.then(test_seed));
443 let _ = Z::sample_prime_uniform_optionally_seeded(0, &z, seeded.then(test_seed));
444
445 if seeded {
447 let _ = Z::sample_prime_uniform_seeded(0u16, 7u8, test_seed());
448 } else {
449 let _ = Z::sample_prime_uniform(0u16, 7u8);
450 }
451 }
452 }
453
454 #[test]
456 fn same_seed_same_sample() {
457 use crate::integer::Z;
458 let sample_0 = Z::sample_prime_uniform_seeded(1, 100, [42; 32]).unwrap();
459 let sample_1 = Z::sample_prime_uniform_seeded(1, 100, [42; 32]).unwrap();
460
461 assert_eq!(sample_0, sample_1);
462 }
463
464 #[test]
466 fn known_answer() {
467 use crate::integer::Z;
468 let sample = Z::sample_prime_uniform_seeded(1, 100, [42; 32]).unwrap();
469
470 assert_eq!("17", sample.to_string());
471 }
472}