1#[cfg(any(feature = "table", feature = "ssmr"))]
2use crate::hashbase::FERMAT_TABLE;
3
4#[cfg(any(feature = "lucas", feature = "table", feature = "ssmr"))]
5use crate::primes::{INV_8, PRIME_INV_64};
6
7#[cfg(all(feature = "lucas", not(any(feature = "table", feature = "ssmr"))))]
8use crate::primes::LUCAS_PARAM;
9
10#[cfg(feature = "wide")]
11use crate::double::{is_prime_128, is_prime_wc_128};
12
13pub const fn mul_inv2(n: u64) -> u64 {
19 #[cfg(not(any(feature = "lucas", feature = "table", feature = "ssmr")))]
20 {
21 let mut est: u64 = 3u64.wrapping_mul(n) ^ 2;
22 est = 2u64.wrapping_sub(est.wrapping_mul(n)).wrapping_mul(est);
23 est = 2u64.wrapping_sub(est.wrapping_mul(n)).wrapping_mul(est);
24 est = 2u64.wrapping_sub(est.wrapping_mul(n)).wrapping_mul(est);
25 est = 2u64.wrapping_sub(est.wrapping_mul(n)).wrapping_mul(est);
26 est
27 }
28
29 #[cfg(any(feature = "lucas", feature = "table", feature = "ssmr"))]
30 {
31 let mut est: u64 = INV_8[(n.wrapping_shr(1) & 0x7F) as usize] as u64;
32 est = 2u64.wrapping_sub(est.wrapping_mul(n)).wrapping_mul(est);
33 est = 2u64.wrapping_sub(est.wrapping_mul(n)).wrapping_mul(est);
34 est = 2u64.wrapping_sub(est.wrapping_mul(n)).wrapping_mul(est);
35 est
36 }
37}
38
39pub const fn mont_prod(x: u64, y: u64, n: u64, inv: u64) -> u64 {
45 let full_prod: u128 = (x as u128).wrapping_mul(y as u128);
46 let lo: u64 = (full_prod as u64).wrapping_mul(inv);
47 let lo: u64 = (lo as u128).wrapping_mul(n as u128).wrapping_shr(64) as u64;
48 let hi: u64 = full_prod.wrapping_shr(64) as u64;
49
50 if hi < lo {
51 hi.wrapping_sub(lo).wrapping_add(n)
52 } else {
53 hi.wrapping_sub(lo)
54 }
55}
56
57#[inline]
63pub const fn to_mont(x: u64, n: u64) -> u64 {
64 ((x as u128).wrapping_shl(64) % (n as u128)) as u64
65}
66
67#[inline]
73pub const fn one_mont(n: u64) -> u64 {
74 (u64::MAX % n).wrapping_add(1)
75}
76
77pub const fn two_mont(one: u64, n: u64) -> u64 {
83 let two = one.wrapping_add(one);
84 if two > n {
85 return two.wrapping_sub(n);
86 }
87 two
88}
89
90pub const fn mont_sub(x: u64, y: u64, n: u64) -> u64 {
96 if y > x {
97 return n.wrapping_sub(y.wrapping_sub(x));
98 }
99 x.wrapping_sub(y)
100}
101
102#[cfg(not(any(feature = "table", feature = "ssmr")))]
108pub const fn nqr(a: u64, k: u64) -> bool {
109 let mut n = a;
110 let mut p = k;
111 let mut t = false;
112
113 while n != 0 {
114 let zeros = n.trailing_zeros();
115 n = n.wrapping_shr(zeros);
116
117 if (p & 7 == 3 || p & 7 == 5) && (zeros & 1 == 1) {
118 t ^= true;
119 }
120
121 if p & 3 == 3 && n & 3 == 3 {
122 t ^= true;
123 }
124
125 let interim = p;
126 p = n;
127 n = interim;
128
129 n %= p;
130 }
131
132 if p == 1 {
133 t
134 } else {
135 false
136 }
137}
138
139#[cfg(not(any(feature = "table", feature = "ssmr")))]
145pub const fn param_search(n: u64) -> u64 {
146 #[cfg(all(feature = "lucas", not(any(feature = "table", feature = "ssmr"))))]
147 {
148 let rem = n % 5;
149
150 if rem == 3 || rem == 2 {
151 return 3;
152 }
153
154 let rem = n % 12;
155
156 if rem == 2 || rem == 5 || rem == 7 || rem == 8 {
157 return 4;
158 }
159
160 let rem = n % 21;
161
162 if rem == 2 || rem == 8 || rem == 11 || rem == 10 || rem == 13 || rem == 19 {
163 return 5;
164 }
165
166 let mut idx: usize = 0;
167
168 while idx < 27 {
169 let i = LUCAS_PARAM[idx] as u64;
170 if nqr(i.wrapping_mul(i).wrapping_sub(4u64), n) {
171 return i;
172 }
173 idx = idx.wrapping_add(1);
174 }
175 0u64
176 }
177
178 #[cfg(not(any(feature = "lucas", feature = "table", feature = "ssmr")))]
179 {
180 let mut d: u64;
181 let mut p = 3u64;
182 loop {
183 d = p.wrapping_mul(p).wrapping_sub(4);
184 if nqr(d, n) {
185 break;
186 }
187 p = p.wrapping_add(1);
188 }
189 p
190 }
191}
192
193#[cfg(not(any(feature = "table", feature = "ssmr")))]
199pub const fn lucas(n: u64, one: u64, two: u64, npi: u64) -> bool {
200 let param = param_search(n);
201
202 #[cfg(all(feature = "lucas", not(any(feature = "table", feature = "ssmr"))))]
203 {
204 if param == 0 {
205 return true;
206 }
207 }
208
209 let n_plus = n.wrapping_add(1);
210 let s = n_plus.trailing_zeros();
211 let d = n_plus.wrapping_shr(s);
212
213 let m_param = to_mont(param, n);
214
215 let m_2_inv = mont_prod(mont_sub(n, two, n), one, n, npi);
216
217 let mut w = mont_sub(mont_prod(m_param, m_param, n, npi), two, n);
218 let mut v = m_param;
219
220 let b = 64u32.wrapping_sub(d.leading_zeros());
221
222 let mut i = 2;
223
224 while i < b.wrapping_add(1) {
225 let t = mont_sub(mont_prod(v, w, n, npi), m_param, n);
226
227 if d.wrapping_shr(b.wrapping_sub(i)) & 1 == 1 {
228 v = t;
229 w = mont_sub(mont_prod(w, w, n, npi), two, n);
230 } else {
231 w = t;
232 v = mont_sub(mont_prod(v, v, n, npi), two, n);
233 }
234 i = i.wrapping_add(1);
235 }
236
237 if v == two || v == m_2_inv {
238 return true;
239 }
240
241 let mut counter = 1;
242
243 while counter < s {
244 if v == 0 {
245 return true;
246 }
247 v = mont_sub(mont_prod(v, v, n, npi), two, n);
248 if v == two {
249 return false;
250 }
251 counter = counter.wrapping_add(1);
252 }
253 false
254}
255
256pub const fn mont_pow(mut base: u64, mut one: u64, mut pow: u64, n: u64, npi: u64) -> u64 {
262 while pow > 1 {
263 if pow & 1 == 0 {
264 base = mont_prod(base, base, n, npi);
265 pow = pow.wrapping_shr(1);
266 } else {
267 one = mont_prod(one, base, n, npi);
268 base = mont_prod(base, base, n, npi);
269 pow = pow.wrapping_sub(1).wrapping_shr(1);
270 }
271 }
272 mont_prod(one, base, n, npi)
273}
274
275#[cfg(any(feature = "table", feature = "ssmr"))]
277#[inline]
278pub const fn base_selector(x: u64) -> u64 {
279 FERMAT_TABLE[(x as u32).wrapping_mul(811484239).wrapping_shr(14) as usize] as u64
280}
281
282pub const fn strong_fermat(n: u64, tz: u32, base: u64, one: u64, oneinv: u64, inv: u64) -> bool {
288 let d = n.wrapping_sub(1).wrapping_shr(tz);
289
290 let mut result = mont_pow(base, one, d, n, inv);
291
292 if result == one || result == oneinv {
293 return true;
294 }
295
296 let mut count = 1;
297
298 while count < tz {
299 count = count.wrapping_add(1);
300 result = mont_prod(result, result, n, inv);
301
302 if result == oneinv {
303 return true;
304 }
305 }
306 false
307}
308
309const fn core_primality(x: u64) -> bool {
310 let inv = mul_inv2(x);
311
312 let tzc = x.wrapping_sub(1).trailing_zeros();
313 let one = one_mont(x);
314 let oneinv = mont_prod(mont_sub(x, one, x), one, x, inv);
315
316 #[cfg(feature = "ssmr")]
317 {
318 let base = base_selector(x);
319 if !strong_fermat(x, tzc, to_mont(base, x), one, oneinv, inv) {
320 return false;
321 }
322
323 if x > 0x800000000000{
324 let two = two_mont(one, x);
325 return strong_fermat(x, tzc, two, one, oneinv, inv);
326 }
327 return true;
328 }
329
330 #[cfg(all(feature = "table", not(feature = "ssmr")))]
331 {
332 let two = two_mont(one, x);
333 if !strong_fermat(x, tzc, two, one, oneinv, inv) {
334 return false;
335 }
336
337 let base = base_selector(x);
338 strong_fermat(x, tzc,to_mont(base, x), one, oneinv, inv)
339 }
340
341 #[cfg(not(any(feature = "table", feature = "ssmr")))]
342 {
343 let two = two_mont(one, x);
344 if !strong_fermat(x, tzc, two, one, oneinv, inv) {
345 return false;
346 }
347
348 if x < 2047 {
349 return true;
350 }
351
352 lucas(x, one, two, inv)
353 }
354}
355
356#[no_mangle]
360pub const extern "C" fn is_prime(x: u64) -> bool {
361 if x == 1 {
362 return false;
363 }
364
365 #[cfg(not(any(feature = "table", feature = "ssmr")))]
366 {
367 if x == 1194649 || x == 12327121 {
370 return false;
371 }
372 }
373
374 if x == 2 {
375 return true;
376 }
377
378 if x & 1 == 0 {
379 return false;
380 }
381
382 #[cfg(any(feature = "lucas", feature = "table", feature = "ssmr"))]
383 {
384 if x < 55730344633563600 {
385 let mut idx: usize = 0;
386
387 while idx < 66 {
388 let prod = x.wrapping_mul(PRIME_INV_64[idx]);
389 if prod == 1 {
390 return true;
391 }
392 if prod < x {
393 return false;
394 }
395 idx = idx.wrapping_add(1);
396 }
397 }
398
399 if x > 55730344633563600 {
400 let residue = x % 13082761331670030u64;
401
402 let mut idx: usize = 0;
403
404 while idx < 13 {
405 if residue.wrapping_mul(PRIME_INV_64[idx]) < residue {
406 return false;
407 }
408 idx = idx.wrapping_add(1);
409 }
410
411 let residue = x % 10575651537777253u64;
412
413 while idx < 21 {
414 if residue.wrapping_mul(PRIME_INV_64[idx]) < residue {
415 return false;
416 }
417 idx = idx.wrapping_add(1)
418 }
419
420 let residue = x % 9823972789433423u64;
421
422 while idx < 29 {
423 if residue.wrapping_mul(PRIME_INV_64[idx]) < residue {
424 return false;
425 }
426 idx = idx.wrapping_add(1);
427 }
428
429 let residue = x % 805474958639317u64;
430
431 while idx < 35 {
432 if residue.wrapping_mul(PRIME_INV_64[idx]) < residue {
433 return false;
434 }
435 idx = idx.wrapping_add(1);
436 }
437
438 let residue = x % 4575249731290429u64;
439
440 while idx < 42 {
441 if residue.wrapping_mul(PRIME_INV_64[idx]) < residue {
442 return false;
443 }
444 idx = idx.wrapping_add(1);
445 }
446
447 let residue = x % 18506541671175721u64;
448
449 while idx < 49 {
450 if residue.wrapping_mul(PRIME_INV_64[idx]) < residue {
451 return false;
452 }
453 idx = idx.wrapping_add(1);
454 }
455
456 let residue = x % 61247129307885343u64;
457
458 while idx < 56 {
459 if residue.wrapping_mul(PRIME_INV_64[idx]) < residue {
460 return false;
461 }
462 idx = idx.wrapping_add(1);
463 }
464
465 let residue = x % 536967265590991u64;
466
467 while idx < 62 {
468 if residue.wrapping_mul(PRIME_INV_64[idx]) < residue {
469 return false;
470 }
471 idx = idx.wrapping_add(1);
472 }
473
474 let residue = x % 3442087319857u64;
475
476 while idx < 66 {
477 if residue.wrapping_mul(PRIME_INV_64[idx]) < residue {
478 return false;
479 }
480 idx = idx.wrapping_add(1);
481 }
482 } } core_primality(x)
486}
487
488#[no_mangle]
500pub const extern "C" fn is_prime_wc(x: u64) -> bool {
501 debug_assert!(x != 1 && x != 2 && x != 0);
506 #[cfg(feature = "ssmr")]
507 {
508 debug_assert!(x&1==1);
509 }
510 #[cfg(not(any(feature = "table", feature = "ssmr")))]
511 {
512 debug_assert!(x != 1194649 && x != 12327121);
513 }
514
515 core_primality(x)
516}