number_theory/arithmetic/
mpz_prime.rs1use crate::data::primes::PRIMELIST;
8
9use crate::ntrait::NumberTheory;
10use crate::Mpz;
11use crate::NTResult;
12
13use crate::arithmetic::sliceops::{mod_slice,sub_slice};
14
15
16impl Mpz {
17 pub(crate) fn sprp(&self, base: Self) -> bool {
19 let mut p_minus = self.clone();
20 let one = Mpz::one();
21
22 sub_slice(&mut p_minus.limbs[..], &one.limbs[..]); let zeroes = p_minus.trailing_zeros() as usize;
25
26 let d = p_minus.shr(zeroes);
27 let mut x = base.u_mod_pow(&d, self);
28
29 if x == Mpz::one() || x == p_minus {
30 return true;
31 }
32
33 for _ in 1..zeroes{
34 x = x.u_quadratic_residue(self);
35
36 if x == p_minus {
37 return true;
38 }
39 }
40 false
41 }
42
43 #[cfg(not(feature = "parallel"))]
44 pub fn sprp_check(&self, n: usize) -> bool {
58 if self.len() < 2 {
59 return u64::try_from(self.clone()).unwrap().is_prime();
60 } if self.is_fermat() {
63 return false;
64 }
65
66 for _ in 0..n {
67 let z = Mpz::rand((self.bit_length()-1) as usize);
68
69 if !self.sprp(z) {
70 return false;
71 } }
73
74 true
75 }
76
77 #[cfg(feature = "parallel")] pub fn sprp_check(&self, k: usize) -> bool {
80 if self.len() < 2 {
81 return self.to_u64().unwrap().is_prime();
82 } if self.is_fermat() {
85 return false;
86 }
87
88
89 let single = |x: Mpz, n: usize| {
90 for _ in 0..n {
91 let z = Mpz::rand(x.bit_length() as usize-1);
92 if !x.sprp(z) {
93 return false;
94 }
95 }
96 return true;
97 };
98
99 let threadcount = usize::from(std::thread::available_parallelism().unwrap()) - 2;
100 let q = self.clone();
101 let mut threadvec = vec![];
119 let mut xclone = vec![];
120 for _ in 0..threadcount {
121 xclone.push(self.clone())
122 }
123
124 for i in xclone {
125 threadvec.push(std::thread::spawn(move || single(i, k / threadcount)));
126 }
127 let tally = single(q, k / threadcount); for j in threadvec {
130 if !j.join().unwrap() {
131 return false;
132 }
133 }
134 return tally;
135 }
136
137 pub(crate) fn form_check(&self) -> bool {
142 let sqrt = self.sqrt().0;
145 if sqrt.sqr() == self.clone() {
146 return false;
148 }
149
150 !detect_pseudo_mpz(self)
151 }
152
153 pub(crate) fn trial_div(&self) -> bool {
154 if self.is_even() {
157 return false;
158 }
159
160 let rem = mod_slice(&self.limbs[..], 16294579238595022365);
161
162 for i in PRIMELIST[1..16usize].iter() {
163 if rem % *i as u64 == 0 {
164 return false;
165 }
166 }
167
168 let mut supremum: usize = 2048;
169
170 if self.len() < 40 {
171 supremum = self.len() * 50
172 }
173 for i in PRIMELIST[17..supremum].iter() {
174 if self.congruence_u64(*i as u64, 0) {
175 return false;
176 }
177 }
178
179 true
181 }
182
183 pub(crate) fn _trial_list(&self, primes: &[u64]) -> bool{
184 for i in primes{
185 if self.congruence_u64(*i,0){
186 return false
187 }
188 }
189 true
190 }
191
192 pub(crate) fn weighted_sprp(&self) -> bool {
194 const CHECK_LUT: [u8; 5] = [8, 6, 5, 4, 2]; let mut check: usize = 1;
196
197 if self.len() < 8 {
198 check = CHECK_LUT[self.len() - 3] as usize;
199 }
200
201 self.sprp_check(check)
202 }
203
204 pub(crate) fn llt(&self, p: u64) -> bool {
205 let mut s = Mpz::from(4u64);
207
208 for _ in 0..(p - 2) {
209 s = s.ref_product(&s);
210 s.normalize();
211 sub_slice(&mut s.limbs[..], &[2]);
212
213 s = s.ref_euclidean(self).1;
214 }
215 s.normalize();
216 if s == Mpz::zero() {
217 return true;
218 }
219 false
220 }
221
222 pub fn is_sophie(&self) -> Option<Self> {
227 if self.is_prime() {
228 let mut safe = self.shl(1);
229 let p = safe.clone();
230 let two = Mpz::two();
231 safe.successor();
232
233 if two.exp_residue(p, safe.clone()) == Mpz::one() {
234 return Some(safe);
235 }
236 }
237 None
238 }
239
240 pub(crate) fn jacobi_check_mpz(&self) -> bool {
241 let mut witness = 3u64;
243 loop {
244 if fast_jacobi_mpz(self, witness) == -1 {
245 break;
246 }
247 witness += 1;
248 }
249
250 let witty = Mpz::from(witness);
251 self.sprp(witty)
252 }
253
254pub fn psp(k: usize) -> NTResult<Self>{
258
259 let corrector = 1 + (k&1)*2 ;
260 if k < 14{
261 return NTResult::DNE
262 }
263 if k > (1<<32){
264 return NTResult::CompExceeded
265 }
266 loop {
267 let len = (k-corrector)/2;
268 let mut x = Mpz::rand(len);
269 if corrector == 3 && !x.check_bit(len-2){
270 x.flip_bit(len-2);
271 }
272 if corrector == 1{
273 if x.check_bit(len-2){
274 x.flip_bit(len-2);
275 }
276 if x.check_bit(len-3){
277 x.flip_bit(len-3);
278 }
279 }
280
281 let lhs = x.shl(1).ref_addition(&Mpz::one());
282 let rhs = x.shl(2).ref_addition(&Mpz::one());
283 if lhs.is_prime() & rhs.is_prime(){
284 let product = lhs.ref_product(&rhs);
285 assert_eq!(product.bit_length(),k as u64);
286
287 return NTResult::Eval(product)
288 }
289 }
290}
291pub fn fermat(&self, base: &Self) -> bool{
293 base.exp_residue(self.ref_subtraction(&Mpz::one()),self.clone()).is_unit()
294}
295
296pub fn miller(&self) -> bool{
298 let sup = (self.ln()*self.ln()*2.0) as u64;
299
300 match self.to_u128(){
301 Some(x) => {
302 for i in 2..sup{
303 if !x.strong_fermat(i as u128){
304 return false
305 }
306 }
307 }
308 None => {
309 for i in 2..sup{
310 if !self.sprp(Mpz::from(i)){
311 return false
312 }
313 }
314 }
315 }
316 true
317}
318
319
320}
321
322pub(crate) fn fast_jacobi_mpz(x: &Mpz, p: u64) -> i8 {
323 let k = x.word_div(p).1;
324 k.jacobi(p).unwrap()
325}
326
327 pub(crate) fn detect_pseudo_mpz(x: &Mpz) -> bool {
329 let mut xminus = x.abs();
330 let copy = xminus.clone();
331 let eightprod = copy.scale_add(8,1);
332 let eightsqrt = eightprod.sqrt().0;
333
334 if eightsqrt.sqr() == eightprod{
335 return true
336 }
337
338 let threeprod = copy.scale_add(3,1);
339 let threesqrt = threeprod.sqrt().0;
340 if threesqrt.sqr() == threeprod{
341 return true
342 }
343 xminus.predecessor();
344
345
346 for i in 1..16 {
347 let sq = xminus.word_div(2 * i + 1).0.sqrt().0; let lhs = sq.ref_product(&sq).ref_addition(&sq);
349 let lhs2 = lhs.ref_product(&Mpz::from(2 * i + 1));
350 if lhs.ref_addition(&lhs2).ref_addition(&Mpz::one()) == copy {
351 return true;
352 }
353 }
354 false
355}