qfall_math/integer/z/sample/
uniform.rs1use crate::{error::MathError, integer::Z, utils::sample::uniform::UniformIntegerSampler};
12
13impl Z {
14 pub fn sample_uniform(
42 lower_bound: impl Into<Z>,
43 upper_bound: impl Into<Z>,
44 ) -> Result<Self, MathError> {
45 let lower_bound: Z = lower_bound.into();
46 let upper_bound: Z = upper_bound.into();
47
48 let interval_size = &upper_bound - &lower_bound;
49 let mut uis = UniformIntegerSampler::init(&interval_size)?;
50
51 let sample = uis.sample();
52 Ok(&lower_bound + sample)
53 }
54
55 pub fn sample_prime_uniform(
88 lower_bound: impl Into<Z>,
89 upper_bound: impl Into<Z>,
90 ) -> Result<Self, MathError> {
91 let lower_bound: Z = lower_bound.into();
92 let upper_bound: Z = upper_bound.into();
93
94 if lower_bound < Z::ZERO {
95 return Err(MathError::InvalidIntegerInput(format!(
96 "Primes are always positive. Hence, sample_prime_uniform expects a positive lower_bound.
97 The provided one is {lower_bound}.")));
98 }
99
100 let interval_size = &upper_bound - &lower_bound;
101 let mut uis = UniformIntegerSampler::init(&interval_size)?;
102 let mut sample = &lower_bound + uis.sample();
103
104 let mut steps = 2 * &interval_size;
107 while !sample.is_prime() {
108 if steps == Z::ZERO {
109 return Err(MathError::InvalidInterval(format!(
110 "After sampling O({interval_size}) times uniform at random in the interval [{lower_bound}, {upper_bound}[
111 no prime was found. It is very likely, that no prime exists in this interval.
112 Please choose the interval larger.")));
113 }
114 sample = &lower_bound + uis.sample();
115 steps -= 1;
116 }
117
118 Ok(sample)
119 }
120}
121
122#[cfg(test)]
123mod test_sample_uniform {
124 use crate::{integer::Z, integer_mod_q::Modulus};
125
126 #[test]
128 fn boundaries_kept_small() {
129 let lower_bound = Z::from(17);
130 let upper_bound = Z::from(32);
131 for _ in 0..32 {
132 let sample = Z::sample_uniform(&lower_bound, &upper_bound).unwrap();
133 assert!(lower_bound <= sample);
134 assert!(sample < upper_bound);
135 }
136 }
137
138 #[test]
140 fn boundaries_kept_large() {
141 let lower_bound = Z::from(i64::MIN) - Z::from(u64::MAX);
142 let upper_bound = Z::from(i64::MIN);
143 for _ in 0..256 {
144 let sample = Z::sample_uniform(&lower_bound, &upper_bound).unwrap();
145 assert!(lower_bound <= sample);
146 assert!(sample < upper_bound);
147 }
148 }
149
150 #[test]
152 fn invalid_interval() {
153 let lb_0 = Z::from(i64::MIN);
154 let lb_1 = Z::from(i64::MIN);
155 let lb_2 = Z::ZERO;
156 let upper_bound = Z::from(i64::MIN);
157
158 let res_0 = Z::sample_uniform(&lb_0, &upper_bound);
159 let res_1 = Z::sample_uniform(&lb_1, &upper_bound);
160 let res_2 = Z::sample_uniform(&lb_2, &upper_bound);
161
162 assert!(res_0.is_err());
163 assert!(res_1.is_err());
164 assert!(res_2.is_err());
165 }
166
167 #[test]
170 fn availability() {
171 let modulus = Modulus::from(7);
172 let z = Z::from(7);
173
174 let _ = Z::sample_uniform(0u16, 7u8);
175 let _ = Z::sample_uniform(0u32, 7u16);
176 let _ = Z::sample_uniform(0u64, 7u32);
177 let _ = Z::sample_uniform(0i8, 7u64);
178 let _ = Z::sample_uniform(0i16, 7i8);
179 let _ = Z::sample_uniform(0i32, 7i16);
180 let _ = Z::sample_uniform(0i64, 7i32);
181 let _ = Z::sample_uniform(&Z::ZERO, 7i64);
182 let _ = Z::sample_uniform(0u8, &modulus);
183 let _ = Z::sample_uniform(0, &z);
184 }
185
186 #[test]
190 fn uniformity() {
191 let lower_bound = Z::ZERO;
192 let upper_bound = Z::from(5);
193 let mut counts = [0; 5];
194 for _ in 0..1000 {
196 let sample_z = Z::sample_uniform(&lower_bound, &upper_bound).unwrap();
197 let sample_int = i64::try_from(&sample_z).unwrap() as usize;
198 counts[sample_int] += 1;
199 }
200
201 for count in counts {
204 assert!(count > 150, "This test can fail with probability close to 0.
205 It fails if the sampled occurrences do not look like a typical uniform random distribution.
206 If this happens, rerun the tests several times and check whether this issue comes up again.");
207 }
208 }
209}
210
211#[cfg(test)]
212mod test_sample_prime_uniform {
213 use crate::{integer::Z, integer_mod_q::Modulus};
214
215 #[test]
217 fn is_prime() {
218 for _ in 0..8 {
219 let sample = Z::sample_prime_uniform(20, i64::MAX).unwrap();
220 assert!(sample.is_prime(), "Can fail with probability ~2^-60.");
221 }
222 }
223
224 #[test]
227 fn no_prime_exists() {
228 let res_0 = Z::sample_prime_uniform(14, 17);
229 let res_1 = Z::sample_prime_uniform(u64::MAX - 57, u64::MAX);
231
232 assert!(res_0.is_err());
233 assert!(res_1.is_err());
234 }
235
236 #[test]
238 fn negative_lower_bound() {
239 let res_0 = Z::sample_prime_uniform(-1, 10);
240 let res_1 = Z::sample_prime_uniform(-200, 1);
241
242 assert!(res_0.is_err());
243 assert!(res_1.is_err());
244 }
245
246 #[test]
248 fn boundaries_kept_small() {
249 let lower_bound = Z::from(17);
250 let upper_bound = Z::from(32);
251 for _ in 0..32 {
252 let sample = Z::sample_prime_uniform(&lower_bound, &upper_bound).unwrap();
253 assert!(lower_bound <= sample);
254 assert!(sample < upper_bound);
255 }
256 }
257
258 #[test]
260 fn boundaries_kept_large() {
261 let lower_bound = Z::ZERO;
262 let upper_bound = Z::from(i64::MAX);
263 for _ in 0..256 {
264 let sample = Z::sample_prime_uniform(&lower_bound, &upper_bound).unwrap();
265 assert!(lower_bound <= sample);
266 assert!(sample < upper_bound);
267 }
268 }
269
270 #[test]
272 fn invalid_interval() {
273 let lb_0 = Z::from(i64::MIN) - Z::ONE;
274 let lb_1 = Z::from(i64::MIN);
275 let lb_2 = Z::ZERO;
276 let upper_bound = Z::from(i64::MIN);
277
278 let res_0 = Z::sample_prime_uniform(&lb_0, &upper_bound);
279 let res_1 = Z::sample_prime_uniform(&lb_1, &upper_bound);
280 let res_2 = Z::sample_prime_uniform(&lb_2, &upper_bound);
281
282 assert!(res_0.is_err());
283 assert!(res_1.is_err());
284 assert!(res_2.is_err());
285 }
286
287 #[test]
290 fn availability() {
291 let modulus = Modulus::from(7);
292 let z = Z::from(7);
293
294 let _ = Z::sample_prime_uniform(0u16, 7u8);
295 let _ = Z::sample_prime_uniform(0u32, 7u16);
296 let _ = Z::sample_prime_uniform(0u64, 7u32);
297 let _ = Z::sample_prime_uniform(0i8, 7u64);
298 let _ = Z::sample_prime_uniform(0i16, 7i8);
299 let _ = Z::sample_prime_uniform(0i32, 7i16);
300 let _ = Z::sample_prime_uniform(0i64, 7i32);
301 let _ = Z::sample_prime_uniform(&Z::ZERO, 7i64);
302 let _ = Z::sample_prime_uniform(0u8, &modulus);
303 let _ = Z::sample_prime_uniform(0, &z);
304 }
305}