1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
/*
Traits
*/
use crate::NTResult;
use crate::Mpz;
/// Trait for number-theory functions across all integer types
pub trait NumberTheory {
///Random number generation, generally high-quality
fn rng() -> Self;
///Euclidean function, normally called euclidean division, returns Q,R such that Q*y + R = x
/// # Panic
/// y == 0
fn euclidean_div(&self, other: &Self) -> (Self, Self)
where
Self: Sized;
/// Returns the representation of x in the ring Z\[n\]
fn residue(&self, ring: &Self) -> Self;
/** Strong probable prime test.Performs Artjuhov-Selfridge test exactly which means that if gcd(x,base) > 1 and x is a prime
then it will be flagged as composite
Correct primality tests account for this, so it is up to the user to account for them as well.
*/
fn is_sprp(&self, base: &Self) -> bool;
/**
Optimized for the average case. Although speed is valued over
determinism, the probability of failure is extremely small and never deterministic (i.e repeating the test will
almost certainly fail a previous composite that passed).
N < 2^64 + 2^49 Provably correct deterministic test, uniquely uses a maximum of 2 strong fermat tests giving it the lowest average
complexity publicly known. Average complexity 0.3 tests, worst-case 2.6 sprp checks (against 2^64-59)
N > 2^64 + 2^49 Weighted to ensure 2^-64 probability of failure against a random input.Performs a minimum of 3 sprp checks.
Strongest counterexamples are of the form n = p(x(p-1)+1)(y(p-1)+1) where p is prime and gcd(x,y,p) = 1 and n > 2^512, passing at
a rate of approximately 25%. Any other equally strong counterexamples are encouraged to be reported. Further strengthening the test
should be by calling [sprp_check](struct.Mpz.html#method.sprp_check) afterwards **not** by calling is_prime again. Average complexity 0.18
worst case 12 sprp checks (typical worst case is around 3.1, 12 is the absolute worst case against a very narrow interval).
Mersenne : Deterministic, not computed
Fermat : Deterministic, not computed, assumed to not exist beyond 65537 .
*/
/* {undocumented comment} is_prime is further notable for having the following properties :
highest single-shot bound (2^35 or eight times higher than 2^32 which is the standard in all other hashtable tests)
highest bound for any test with less than 12 checks (except possibly the Baille-PSW test, although it is not a MR test)
the first correct 2-shot test (see /data/hashtable for more information on assessment and comparison with other attempts)
Low memory relative to it's performance.
One might be curious as to why 3 sprp tests are selected, this is due to a special configuration of checks that makes them
equivalent to around 5 standard tests, so in reality not only does is_prime meet the advertised requirements it far exceeds it, being
fully deterministic against nearly half of all pseudoprimes. Additionally Lucas sequence and quadratic Frobenius tests are not used
because the current configuration is trivially parallelizable to the cost of only a single sprp test. (versus two for a lucas and
3 for a Frobenius). As stated in the documented comment is_prime is configured to be optimal in the average case, the Carmichael
numbers that do pass with a relatively high probability are statistically so rare that they are inconsequential.
*/
fn is_prime(&self) -> bool;
/**
Checks primality for the integer and returns the evaluation in addition to a vector of the witness
followed by the factors of n-1. For instance 269u64.prime_proof may return (true, [238, 2,67]).
Verification requires checking that 238.exp_residue(269-1, 269) == 1
and 238.exp_residue((269-1)/2, 269) != 1 and 238.exp_residue((269-1)/67, 269) != 1. See prime_proof in examples to see how.
Unable to construct a proof for Carmichael numbers.
*/
fn prime_proof(&self) -> (bool, Vec<Self>)
where
Self: Sized;
/**
Enumerates the primes between self and sup values. If sup < self then it enumerates up to self from sup.
Note that while evaluation is possible for any interval it becomes infeasible with very large numbers
(>10^6000) or very large intervals (>10^12).
*/
fn prime_list(&self, sup: &Self) -> Vec<Self>
where
Self: Sized;
/**
N-th prime, exact evaluation for less than 2^64, approximation beyond that. Not currently feasible beyond 10^12
*/
/// # DNE
/// n == 0 (there is no zeroth prime)
/// # Overflow
/// Pn > datatype MAX
fn nth_prime(&self) -> NTResult<Self>
where
Self: Sized + Clone;
/// Generates an odd positive prime in the interval 2^(k-1);2^k
/// # DNE
/// x == 0
/// # Overflow
/// x > datatype length in bits
fn prime_gen(k: u32) -> NTResult<Self>
where
Self : Sized + Clone;
/// Prime-counting function, exact evaluation for less than 2^64, approximation beyond that. Not currently feasible beyond 10^12
fn pi(&self) -> Self;
/// Factorizes into a vector of the form prime factor, power, prime factor, power . . . i.e 2,6,5,2 for 2^6 * 5^2 = 1600
/// # Failure
/// x == 0 OR x == 1
fn factor(&self) -> Vec<Self>
where
Self: Sized;
/// Factorizes into a vector of the form prime factor, power, prime factor, power . . . i.e 2,6,5,2 for 2^6 * 5^2 = 1600
/// # InfiniteSet
/// x == 0
/// # DNE
/// x == 1
fn checked_factor(&self) -> NTResult<Vec<Self>>
where
Self: Sized + Clone;
/// Returns the integer component of at least one solution to the equation x*x = n where x in Z\[i\] (aka the Gaussian integers).
/// When x < 0 the result is (sqrt(x),1) otherwise it is the (sqrt(x),0)
fn sqrt(&self) -> (Self, Self)
where
Self: Sized;
/// Returns the integer component of one of the solutions to the equation x*x..*x where x in Z\[i\]
fn nth_root(&self, n: &Self) -> (Self, Self)
where
Self: Sized;
/** Returns the representation of x as a base and exponent biasing towards high exponents. E.g 81 -> 3^4
If no higher representation of the number exists then it will return the trivial solution of x^1
*/
fn max_exp(&self) -> (Self, Self)
where
Self: Sized;
/// Binary gcd, Computes the greatest common divisor of two numbers
fn gcd(&self, other: &Self) -> Self;
/**
Extended Euclidean GCD algorithm.
The behavior of this function varies depending on if the type is in Z or N.
Z : returns the GCD and Bezout coefficients (x,y) such that gcd(a,b) = ax + by
N : returns the GCD and Bezout coefficients such that ax + by = gcd(a,b) over Z\[lcm(a,b)\]
Note that if gcd(a,b) != a OR b this is equivalent to ax mod b = gcd(a,b) and by mod a = gcd(a,b).
In the case of gcd(a,b) =1 these coefficients are the multiplicative inverses of a over Z\[b\]
and b over Z\[a\], respectively
*/
fn extended_gcd(&self, other: &Self) -> (Self, Self, Self)
where
Self: Sized;
/// Computes the least common multiple of x,y
/// # Failure
/// If lcm(x,y) > datatype MAX
///
fn lcm(&self, other: &Self) -> Self;
/// Computes the least common multiple checking for overflow, and zeroes
/// # Overflow
/// lcm(x,y) > datatype MAX
fn checked_lcm(&self, other: &Self) -> NTResult<Self>
where
Self: Sized + Clone;
/// Carmichael totient function, also the exponent of the multiplicative group Z/nZ
/// # Infinite
/// x == 0 As the infinite group of Z/0Z has no exponent
fn carmichael_totient(&self) -> NTResult<Self>
where
Self: Sized + Clone;
/// Counts the number of coprimes from 0 to self
fn euler_totient(&self) -> Self;
/// Counts the Jordan's totient
///# Overflow
/// Jordan_totient(x,k) > datatype MAX
/// # CompOverflow
/// Computation overflowed
fn jordan_totient(&self, k: &Self) -> NTResult<Self>
where
Self: Sized + Clone;
/// Higher-order Dedekind psi
/// # Overflow
/// dedekind_psi(x,k) > datatype MAX
/// # CompOverflow
/// Computational overflow
fn dedekind_psi(&self, k: &Self) -> NTResult<Self>
where
Self: Sized + Clone;
/// Returns x*y mod n
/// # Failure
/// if x * y > datatype MAX AND n == 0
fn product_residue(&self, other: &Self, n: &Self) -> Self;
/// Returns x*y mod n
/// # Overflow
/// if x * y > datatype MAX AND n == 0
fn checked_product_residue(&self, other: &Self, n: &Self) -> NTResult<Self>
where
Self: Sized + Clone;
/// Returns x*x mod n, similar to product_residue except more optimized squaring.
/// # Failure
/// if x * x > datatype MAX AND n == 0
fn quadratic_residue(&self, n: &Self) -> Self;
/// Returns x*x mod n, similar to product_residue except more optimized squaring.
/// # Overflow
/// if x * x > datatype MAX AND n == 0
fn checked_quadratic_residue(&self, n: &Self) -> NTResult<Self>
where
Self: Sized + Clone;
/** Returns x^y mod n, generally called mod_pow in other libraries. If y < 0 returns -x^|y| mod n,
aka the exponentiation of the multiplicative inverse, analogous to the behavior in the Reals.
*/
/// # Failure
/// If y < 0 and gcd(x,n) > 1, or n = 0 and x^y > datatype MAX
fn exp_residue(&self, pow: &Self, n: &Self) -> Self;
/// Exponential residue x^y mod n
/// # DNE
/// y < 0 AND gcd(x,n) > 1
/// # Overflow
/// n == 0 AND x^y > datatype MAX
fn checked_exp_residue(&self, pow: &Self, n: &Self) -> NTResult<Self>
where
Self: Sized + Clone;
/*
/// Returns an x such that x*x = a over Z/nZ
/// # None
/// If x does not exist
fn sqrt_residue(&self, n: &Self) -> Option<Self>
where
Self: Sized;
*/
/// Determines of a number is k-free, i.e square-free, cube-free etc. . .
fn k_free(&self, k: &Self) -> bool;
/*
fn partition(&self) -> Option<Self>
where
Self: Sized;
*/
/// Returns the product of each prime such that p | n AND p > 0
/// # Infinite
/// x == 0
fn radical(&self) -> NTResult<Self>
where
Self: Sized + Clone;
/// Returns the smoothness bound of n, this is the largest prime factor of n.
fn smooth(&self) -> NTResult<Self>
where
Self: Sized + Clone;
//fn checked_smooth(&self)
/// Checks if the smoothness bound is at least b
fn is_smooth(&self, b: &Self) -> bool;
/// Legendre symbol of a,p.
/// # Failure
/// P is not an odd prime
fn legendre(&self, p: &Self) -> i8;
/// Legendre symbol of a,p.
/// # Undefined
/// P is not an odd prime
fn checked_legendre(&self, p: &Self) -> NTResult<i8>;
/// Liouville function
fn liouville(&self) -> i8;
/// Lagarias derivative
/// # Overflow
/// D(x) > datatype MAX
fn derivative(&self) -> NTResult<Self>
where
Self : Sized + Clone;
///Von Mangoldt function, returns the natural logarithm of self if it is a prime-power
fn mangoldt(&self) -> f64;
/// Mobius function
fn mobius(&self) -> i8;
/// Jacobi symbol of x,p.
/// # Failure
/// P is not an odd, positive integer
fn jacobi(&self, p: &Self) -> i8;
/// Jacobi symbol of x,p.
/// # Undefined
/// P is not an odd, positive integer
fn checked_jacobi(&self, p: &Self) -> NTResult<i8>;
/// kronecker symbol
fn kronecker(&self, k: &Self) -> i8;
/*
/// Pi approximation
fn pi(&self) -> f64;
let x = self.ln();
//(self/x )*(1.0 + 1.0/x + 2.0/(x.ln()*x.ln()))
//Primitive root
Future functions
kronecker symbol
power residue
partition
multiplicative order
primitive root
primitive root of unity
index
sqrt residue
divisor list (list of all proper divisors)
index, kronecker, partition, mul_order, sqrt
*/
}
//const trait hello{}
pub(crate) trait Reduction{
fn reducible(&self) -> bool;
}
macro_rules! reducer(
($($t:ty; $s:ty),* $(,)*) => {$(
impl Reduction for $t{
#[inline]
fn reducible(&self) -> bool{
if *self < <$s>::MAX as $t{
return true
}
return false
}
}
)*}
);
reducer!(u16;u8, i16;i8, u32;u16, i32;i16, u64;u32, i64;i32, u128;u64, i128;i64 );
impl Reduction for Mpz{
fn reducible(&self) -> bool{
if self.len() < 3{
return true
}
return false
}
}
/*
NTT research
https://stackoverflow.com/questions/18465326/fast-bignum-square-computation
https://stackoverflow.com/questions/18577076/modular-arithmetics-and-ntt-finite-field-dft-optimizations
https://stackoverflow.com/questions/10260927/translation-from-complex-fft-to-finite-field-fft/18547575#18547575
https://dl.acm.org/doi/10.1145/1185448.1185568
*/