1use core::default::Default;
2use std::ops::{BitAnd, BitOr, Mul};
3
4use either::Either;
5use num_integer::{Integer, Roots};
6use num_traits::Pow;
7
8pub trait BitTest {
10 fn bits(&self) -> usize;
12
13 fn bit(&self, position: usize) -> bool;
15
16 fn trailing_zeros(&self) -> usize;
18}
19
20#[derive(Debug, Clone, Copy, PartialEq)]
22pub enum Primality {
23 Yes,
25 No,
27 Probable(f32),
31}
32
33impl Primality {
34 #[inline(always)]
37 #[must_use]
38 pub fn probably(self) -> bool {
39 !matches!(self, Primality::No)
40 }
41}
42
43impl BitAnd<Primality> for Primality {
44 type Output = Primality;
45
46 fn bitand(self, rhs: Primality) -> Self::Output {
48 match self {
49 Primality::No => Primality::No,
50 Primality::Yes => rhs,
51 Primality::Probable(p) => match rhs {
52 Primality::No => Primality::No,
53 Primality::Yes => Primality::Probable(p),
54 Primality::Probable(p2) => {
55 let combined = p.mul(p2);
56 Primality::Probable(combined)
57 }
58 },
59 }
60 }
61}
62
63impl BitOr<Primality> for Primality {
64 type Output = Primality;
65
66 fn bitor(self, rhs: Primality) -> Self::Output {
68 match self {
69 Primality::No => rhs,
70 Primality::Yes => Primality::Yes,
71 Primality::Probable(p) => match rhs {
72 Primality::No => Primality::Probable(p),
73 Primality::Yes => Primality::Yes,
74 Primality::Probable(p2) => Primality::Probable(1. - (1. - p) * (1. - p2)),
75 },
76 }
77 }
78}
79
80#[derive(Debug, Clone, Copy)]
82#[non_exhaustive]
83pub struct PrimalityTestConfig {
84 pub sprp_trials: usize,
88
89 pub sprp_random_trials: usize,
91
92 pub slprp_test: bool,
94
95 pub eslprp_test: bool,
97}
98
99impl Default for PrimalityTestConfig {
100 fn default() -> Self {
103 Self {
104 sprp_trials: 2, sprp_random_trials: 3, slprp_test: false,
107 eslprp_test: false,
108 }
109 }
110}
111
112impl PrimalityTestConfig {
113 #[must_use]
117 pub fn strict() -> Self {
118 let mut config = Self::bpsw();
119 config.sprp_random_trials = 1;
120 config
121 }
122
123 #[must_use]
125 pub fn bpsw() -> Self {
126 Self {
127 sprp_trials: 1,
128 sprp_random_trials: 0,
129 slprp_test: true,
130 eslprp_test: false,
131 }
132 }
133}
134
135#[derive(Debug, Clone, Copy)]
137#[non_exhaustive]
138pub struct FactorizationConfig {
139 pub primality_config: PrimalityTestConfig,
141
142 pub td_limit: Option<u64>,
145
146 pub rho_trials: usize,
148}
149
150impl Default for FactorizationConfig {
151 fn default() -> Self {
154 const THRESHOLD_DEFAULT_TD: u64 = 1 << 14;
155 Self {
156 primality_config: PrimalityTestConfig::default(),
157 td_limit: Some(THRESHOLD_DEFAULT_TD),
158 rho_trials: 4,
159 }
160 }
161}
162
163impl FactorizationConfig {
164 #[must_use]
166 pub fn strict() -> Self {
167 Self {
168 primality_config: PrimalityTestConfig::strict(),
169 ..Self::default()
170 }
171 }
172}
173
174pub trait ExactRoots: Roots + Pow<u32, Output = Self> + Clone {
177 fn nth_root_exact(&self, n: u32) -> Option<Self> {
178 let r = self.nth_root(n);
179 if &r.clone().pow(n) == self {
180 Some(r)
181 } else {
182 None
183 }
184 }
185 fn sqrt_exact(&self) -> Option<Self> {
186 self.nth_root_exact(2)
187 }
188 fn cbrt_exact(&self) -> Option<Self> {
189 self.nth_root_exact(3)
190 }
191 fn is_nth_power(&self, n: u32) -> bool {
192 self.nth_root_exact(n).is_some()
193 }
194 fn is_square(&self) -> bool {
195 self.sqrt_exact().is_some()
196 }
197 fn is_cubic(&self) -> bool {
198 self.cbrt_exact().is_some()
199 }
200}
201
202pub trait PrimeBuffer<'a> {
213 type PrimeIter: Iterator<Item = &'a u64>;
214
215 fn iter(&'a self) -> Self::PrimeIter;
217
218 fn reserve(&mut self, limit: u64);
220
221 fn bound(&self) -> u64;
223
224 fn contains(&self, num: u64) -> bool;
227
228 fn clear(&mut self);
230}
231
232pub trait PrimalityUtils: Integer + Clone {
237 fn is_prp(&self, base: Self) -> bool;
239
240 fn is_sprp(&self, base: Self) -> bool;
242
243 fn test_sprp(&self, base: Self) -> Either<bool, Self>;
246
247 fn is_lprp(&self, p: Option<usize>, q: Option<isize>) -> bool;
250
251 fn is_slprp(&self, p: Option<usize>, q: Option<isize>) -> bool;
254
255 fn is_eslprp(&self, p: Option<usize>) -> bool;
258
259 }
265
266pub trait RandPrime<T> {
268 fn gen_prime(&mut self, bit_size: usize, config: Option<PrimalityTestConfig>) -> T;
273
274 fn gen_prime_exact(&mut self, bit_size: usize, config: Option<PrimalityTestConfig>) -> T;
279
280 fn gen_safe_prime(&mut self, bit_size: usize) -> T;
286
287 fn gen_safe_prime_exact(&mut self, bit_size: usize) -> T;
293}
294
295#[cfg(test)]
296mod tests {
297 use super::*;
298
299 #[test]
301 fn primality_probably() {
302 assert!(Primality::Yes.probably());
303 assert!(!Primality::No.probably());
304 assert!(Primality::Probable(0.9).probably());
305 }
306
307 #[test]
309 fn primality_bitand_no_lhs() {
310 assert_eq!(Primality::No & Primality::No, Primality::No);
311 assert_eq!(Primality::No & Primality::Yes, Primality::No);
312 assert_eq!(Primality::No & Primality::Probable(0.9), Primality::No);
313 }
314
315 #[test]
316 fn primality_bitand_yes_lhs() {
317 assert_eq!(Primality::Yes & Primality::No, Primality::No);
318 assert_eq!(Primality::Yes & Primality::Yes, Primality::Yes);
319 assert_eq!(
320 Primality::Yes & Primality::Probable(0.8),
321 Primality::Probable(0.8)
322 );
323 }
324
325 #[test]
326 fn primality_bitand_probable_lhs() {
327 assert_eq!(Primality::Probable(0.9) & Primality::No, Primality::No);
328 assert_eq!(
329 Primality::Probable(0.9) & Primality::Yes,
330 Primality::Probable(0.9)
331 );
332 let result = Primality::Probable(0.8) & Primality::Probable(0.9);
334 match result {
335 Primality::Probable(p) => assert!((p - 0.72).abs() < 1e-6),
336 _ => panic!("expected Probable"),
337 }
338 }
339
340 #[test]
342 fn primality_bitor_no_lhs() {
343 assert_eq!(Primality::No | Primality::No, Primality::No);
344 assert_eq!(Primality::No | Primality::Yes, Primality::Yes);
345 assert_eq!(
346 Primality::No | Primality::Probable(0.8),
347 Primality::Probable(0.8)
348 );
349 }
350
351 #[test]
352 fn primality_bitor_yes_lhs() {
353 assert_eq!(Primality::Yes | Primality::No, Primality::Yes);
354 assert_eq!(Primality::Yes | Primality::Yes, Primality::Yes);
355 assert_eq!(Primality::Yes | Primality::Probable(0.8), Primality::Yes);
356 }
357
358 #[test]
359 fn primality_bitor_probable_lhs() {
360 assert_eq!(
361 Primality::Probable(0.9) | Primality::No,
362 Primality::Probable(0.9)
363 );
364 assert_eq!(Primality::Probable(0.9) | Primality::Yes, Primality::Yes);
365 let result = Primality::Probable(0.8) | Primality::Probable(0.9);
367 match result {
368 Primality::Probable(p) => assert!((p - 0.98).abs() < 1e-6),
369 _ => panic!("expected Probable"),
370 }
371 }
372
373 #[test]
375 fn primality_test_config_default() {
376 let c = PrimalityTestConfig::default();
377 assert_eq!(c.sprp_trials, 2);
378 assert_eq!(c.sprp_random_trials, 3);
379 assert!(!c.slprp_test);
380 assert!(!c.eslprp_test);
381 }
382
383 #[test]
384 fn primality_test_config_bpsw() {
385 let c = PrimalityTestConfig::bpsw();
386 assert_eq!(c.sprp_trials, 1);
387 assert_eq!(c.sprp_random_trials, 0);
388 assert!(c.slprp_test);
389 assert!(!c.eslprp_test);
390 }
391
392 #[test]
393 fn primality_test_config_strict() {
394 let c = PrimalityTestConfig::strict();
395 assert_eq!(c.sprp_trials, 1);
396 assert_eq!(c.sprp_random_trials, 1);
397 assert!(c.slprp_test);
398 assert!(!c.eslprp_test);
399 }
400
401 #[test]
403 fn factorization_config_default() {
404 let c = FactorizationConfig::default();
405 assert_eq!(c.td_limit, Some(1 << 14));
406 assert_eq!(c.rho_trials, 4);
407 }
408
409 #[test]
410 fn factorization_config_strict() {
411 let c = FactorizationConfig::strict();
412 assert_eq!(c.td_limit, Some(1 << 14));
413 assert_eq!(c.rho_trials, 4);
414 assert_eq!(c.primality_config.sprp_trials, 1);
416 assert_eq!(c.primality_config.sprp_random_trials, 1);
417 assert!(c.primality_config.slprp_test);
418 }
419
420 #[test]
422 fn exact_roots_is_square() {
423 assert!(16u64.is_square());
424 assert!(!15u64.is_square());
425 assert!(1u64.is_square());
426 assert!(100u64.is_square());
427 assert!(!99u64.is_square());
428 }
429
430 #[test]
431 fn exact_roots_is_cubic() {
432 assert!(27u64.is_cubic());
433 assert!(!26u64.is_cubic());
434 assert!(1u64.is_cubic());
435 assert!(64u64.is_cubic());
436 }
437
438 #[test]
439 fn exact_roots_is_nth_power() {
440 assert!(256u64.is_nth_power(4));
441 assert!(!255u64.is_nth_power(4));
442 }
443
444 #[test]
445 fn exact_roots_sqrt_exact() {
446 assert_eq!(49u64.sqrt_exact(), Some(7));
447 assert_eq!(50u64.sqrt_exact(), None);
448 }
449
450 #[test]
451 fn exact_roots_cbrt_exact() {
452 assert_eq!(125u64.cbrt_exact(), Some(5));
453 assert_eq!(126u64.cbrt_exact(), None);
454 }
455}