Skip to main content

a/math/numbers/
prime.rs

1//! Primality of [`Number`]s: [`Number::is_probable_prime`], the Baillie–PSW test, and
2//! [`Number::next_prime`], the next probable prime.
3//!
4//! A number is first divided by the small primes, in groups whose products fit in a limb: one pass
5//! of the long number for each group, four groups a pass, and a multiplication for each prime of a
6//! group to tell whether it divides the remainder. What is left is tested by Baillie–PSW
7//! ([`bpsw`]): a strong test to base 2 and a strong Lucas test with Selfridge's parameters, in
8//! Montgomery's form, in registers up to seven limbs. Numbers below `2^64` take a path of their own,
9//! all in registers.
10//!
11//! The next prime is searched for in intervals of odd numbers, first sieved by the small primes, as
12//! GMP's `mpz_nextprime` does ([`next`]).
13
14mod bpsw;
15mod next;
16mod tables;
17
18use super::add::{SMALL, read_small};
19use super::mul::{Operand, STACK_LIMBS, on_heap, on_stack, to_limbs};
20use super::pow::montgomery::{Mont1, Mont2, MontN, even};
21use super::{ByteOrder, Number};
22use bpsw::{Bits, LimbField, bpsw, bpsw_limbs, bpsw_limbs_itch, reciprocal, rem_by};
23use core::mem::MaybeUninit;
24use tables::{GROUP, Group, PRIMES, groups_below};
25
26impl Number {
27    /// Returns whether the number is a probable prime, by the Baillie–PSW test: `false` for
28    /// everything below 2, negative numbers included, and for every composite number it finds
29    /// a factor of or that fails the test; `true` for every prime.
30    ///
31    /// Small factors are found by trial division; the rest is a strong (Miller–Rabin) test to base 2
32    /// and a strong Lucas test with Selfridge's parameters. The answer is exact below `2^64`, where
33    /// the test has been checked against every composite that passes Fermat's test to base 2, which
34    /// Feitsma and Galway listed (2009), by Gilchrist: none passes both.
35    /// Above, no composite is known that passes it, though such numbers are believed to exist; GMP's
36    /// `mpz_probab_prime_p(n, 24)` is the same test.
37    ///
38    /// # Examples
39    ///
40    /// ```
41    /// use a::math::numbers::{ByteOrder, Number};
42    ///
43    /// assert!(Number::new_from_u64(1_000_000_007, ByteOrder::BigEndian).is_probable_prime());
44    /// // 2047 = 23 * 89 passes the strong test to base 2, but not the Lucas test.
45    /// assert!(!Number::new_from_u32(2047, ByteOrder::LittleEndian).is_probable_prime());
46    /// assert!(!Number::new_from_i32(-7, ByteOrder::BigEndian).is_probable_prime());
47    /// ```
48    pub fn is_probable_prime(&self) -> bool {
49        if self.value.len() <= SMALL {
50            // SAFETY: the vector holds at most 16 bytes.
51            let x = unsafe { read_small(&self.value, self.byte_order) };
52            if x == 0 || self.negative {
53                return false;
54            }
55            if x >> 64 == 0 {
56                return is_prime_u64(x as u64);
57            }
58            return x & 1 == 1 && is_prime_limbs_small(&[x as u64, (x >> 64) as u64]);
59        }
60        let n = Operand::of(self);
61        if n.significant == 0 || self.negative {
62            return false;
63        }
64        let nn = n.significant.div_ceil(8);
65        let compute = |s: *mut MaybeUninit<u64>| {
66            let s = s.cast::<u64>();
67            // SAFETY: the working memory holds the limbs of `n` and what the test needs.
68            unsafe {
69                to_limbs(n, s);
70                if nn == 1 {
71                    return is_prime_u64(*s);
72                }
73                *s & 1 == 1 && is_prime_odd(s, nn, s.add(even(nn)))
74            }
75        };
76        let need = even(nn) + prime_itch(nn);
77        if need <= STACK_LIMBS {
78            on_stack(compute)
79        } else {
80            on_heap(need, compute)
81        }
82    }
83
84    /// Returns the smallest probable prime above `self`, in the byte order of `self`, in one new
85    /// vector of exactly its length: 2 for anything below 2, negative numbers included.
86    ///
87    /// "Probable prime" is that of [`is_probable_prime`](Self::is_probable_prime): exact below
88    /// `2^64`, and with no known exception above. The odd numbers above `self` are sieved by the
89    /// small primes in intervals, and those left are tested in order.
90    ///
91    /// # Examples
92    ///
93    /// ```
94    /// use a::math::numbers::{ByteOrder, Number};
95    ///
96    /// let p = Number::new_from_u32(1_000_000_000, ByteOrder::BigEndian).next_prime();
97    /// assert_eq!(p.value, 1_000_000_007u32.to_be_bytes());
98    /// assert_eq!(Number::new_from_i32(-5, ByteOrder::BigEndian).next_prime().value, [2]);
99    /// ```
100    pub fn next_prime(&self) -> Number {
101        next::next_prime(self)
102    }
103}
104
105// Below 2^64
106
107/// The primes up to which a number below `2^64` is divided before the test: each costs a
108/// multiplication, and saves the test of the composites it finds. Measured on an Apple M4 Max,
109/// random odd numbers of 64 bits took 311 cycles with the primes to 64, 286 to 128, 271 to 256 and
110/// 259 to 512, and primes 2480 to 2550, 2540, 2550 to 2580 and 2605 to 2670.
111const TRIAL_64: u64 = 256;
112
113/// The index in [`PRIMES`] of the first prime above [`TRIAL_64`].
114const TRIAL_64_END: usize = {
115    let mut i = 0;
116    while PRIMES[i].p <= TRIAL_64 {
117        i += 1;
118    }
119    i
120};
121
122/// Whether `n` is a probable prime, exactly as it is below `2^64`.
123fn is_prime_u64(n: u64) -> bool {
124    if n < 4 {
125        return n >= 2;
126    }
127    if n & 1 == 0 {
128        return false;
129    }
130    for p in &PRIMES[..TRIAL_64_END] {
131        if p.divides(n) {
132            return n == p.p;
133        }
134    }
135    // A composite has a prime factor at most its square root, and none is below the next prime.
136    let next = PRIMES[TRIAL_64_END].p;
137    if n < next * next {
138        return true;
139    }
140    let f = Mont1::new(n);
141    let bits = Bits {
142        n: &n,
143        len: 64 - n.leading_zeros() as usize,
144    };
145    // SAFETY: the bits are those of `n`, odd and without factors up to `TRIAL_64`.
146    unsafe { bpsw(&f, bits, || selfridge_u64(n)) }
147}
148
149/// Selfridge's `D` for the odd `n`, at least 5, or `None` when `n` is a square or shares a factor
150/// with the `D`s before it.
151fn selfridge_u64(n: u64) -> Option<i64> {
152    if is_square_u64(n) {
153        return None;
154    }
155    let mut a = 5u64;
156    loop {
157        if a >= n {
158            // Every `D` below `n` has a symbol of 1 or a factor in common, which for a number
159            // without a small factor means it is prime; not reached for numbers beyond the trial
160            // primes' squares, kept for safety.
161            return Some(0);
162        }
163        let d = if a & 2 == 0 { a as i64 } else { -(a as i64) };
164        match symbol(d, n % a, n & 3) {
165            -1 => return Some(d),
166            0 => return None,
167            _ => a += 2,
168        }
169    }
170}
171
172/// Whether `n` is a perfect square.
173fn is_square_u64(n: u64) -> bool {
174    // Squares are 0, 1, 4 or 9 modulo 16.
175    if (0x0213 >> (n & 15)) & 1 == 0 {
176        return false;
177    }
178    let mut r = (n as f64).sqrt() as u64;
179    while u128::from(r) * u128::from(r) > u128::from(n) {
180        r -= 1;
181    }
182    while u128::from(r + 1) * u128::from(r + 1) <= u128::from(n) {
183        r += 1;
184    }
185    r * r == n
186}
187
188/// The Jacobi symbol `(D/n)` for `|D| = a`, from `n mod a` and `n mod 4`, `n` odd and positive: by
189/// reciprocity, `(a/n) = (n/a)` unless both are 3 modulo 4, and `(-1/n) = -1` when `n` is.
190fn symbol(d: i64, n_mod_a: u64, n_mod_4: u64) -> i32 {
191    let a = d.unsigned_abs();
192    let mut j = jacobi(n_mod_a, a);
193    if a & 3 == 3 && n_mod_4 == 3 {
194        j = -j;
195    }
196    if d < 0 && n_mod_4 == 3 {
197        j = -j;
198    }
199    j
200}
201
202/// The Jacobi symbol `(x/a)` for an odd `a`, by the binary method: the factors of two of `x` taken
203/// out (each turns the sign over when `a` is 3 or 5 modulo 8), then the larger of the two odd
204/// numbers less the smaller, swapped by reciprocity (which turns it over when both are 3 modulo 4).
205pub(super) fn jacobi(mut x: u64, mut a: u64) -> i32 {
206    debug_assert!(a & 1 == 1);
207    let mut t = 1;
208    if x >= a {
209        x %= a;
210    }
211    while x != 0 {
212        let z = x.trailing_zeros();
213        x >>= z;
214        if z & 1 == 1 && matches!(a & 7, 3 | 5) {
215            t = -t;
216        }
217        if x < a {
218            if x & a & 2 != 0 {
219                t = -t;
220            }
221            core::mem::swap(&mut x, &mut a);
222        }
223        x -= a;
224    }
225    if a == 1 { t } else { 0 }
226}
227
228// Long numbers
229
230/// The primes up to which a number of `bits` bits is divided before the test: four times its bits,
231/// from 256 to the table's 8192. Measured on an Apple M4 Max, random odd numbers of 512 bits took
232/// 20,500 cycles with the primes to its bits, 19,000 to twice and 16,000 to four times; of 1024
233/// bits 131,000, 94,000 and 94,600; primes the same.
234fn trial_bound(bits: usize) -> u64 {
235    (bits as u64 * 4).clamp(256, tables::LIMIT as u64)
236}
237
238/// The limbs of working memory of [`is_prime_odd`] for `nn` limbs.
239fn prime_itch(nn: usize) -> usize {
240    if nn >= 8 { bpsw_limbs_itch(nn) } else { 0 }
241}
242
243/// Whether the odd number of two limbs `n`, at least `2^64`, is a probable prime.
244fn is_prime_limbs_small(n: &[u64; 2]) -> bool {
245    // SAFETY: two limbs need no working memory.
246    unsafe { is_prime_odd(n.as_ptr(), 2, core::ptr::null_mut()) }
247}
248
249/// The remainders of the `nn` limbs at `n` by four groups' `d`s at once, four independent chains a
250/// limb.
251///
252/// # Safety
253///
254/// The limbs must be valid for reads.
255#[inline]
256unsafe fn rem_by_4(n: *const u64, nn: usize, g: &[Group; 4]) -> [u64; 4] {
257    let mut r = [0u64; 4];
258    // SAFETY: as the caller guarantees.
259    unsafe {
260        for i in (0..nn).rev() {
261            let x = *n.add(i);
262            for k in 0..4 {
263                r[k] = super::div::limbs::div_2by1(r[k], x, g[k].d, g[k].v).1;
264            }
265        }
266    }
267    r
268}
269
270/// Whether one of the primes of the groups `g` divides the `nn` limbs at `n`.
271///
272/// # Safety
273///
274/// The limbs must be valid for reads.
275unsafe fn has_factor_in(n: *const u64, nn: usize, groups: &[Group]) -> bool {
276    let (chunks, rest) = groups.as_chunks::<4>();
277    for g in chunks {
278        // SAFETY: as the caller guarantees.
279        let r = unsafe { rem_by_4(n, nn, g) };
280        for k in 0..4 {
281            let primes = &PRIMES[g[k].first as usize..g[k].end as usize];
282            if primes.iter().any(|p| p.divides(r[k])) {
283                return true;
284            }
285        }
286    }
287    for g in rest {
288        // SAFETY: as the caller guarantees.
289        let r = unsafe { rem_by(n, nn, g.d, g.v) };
290        let primes = &PRIMES[g.first as usize..g.end as usize];
291        if primes.iter().any(|p| p.divides(r)) {
292            return true;
293        }
294    }
295    false
296}
297
298/// Whether the odd number of `nn >= 2` limbs at `n`, at least `2^64`, is a probable prime: trial
299/// division, then Baillie–PSW, in registers up to seven limbs and in the [`prime_itch`] limbs at
300/// `s` beyond.
301///
302/// # Safety
303///
304/// The limbs must be valid for reads, the top one not zero, and `s` for the working memory,
305/// starting on 16 bytes.
306unsafe fn is_prime_odd(n: *const u64, nn: usize, s: *mut u64) -> bool {
307    // SAFETY: as the caller guarantees.
308    unsafe {
309        let bits = Bits {
310            n,
311            len: 64 * nn - (*n.add(nn - 1)).leading_zeros() as usize,
312        };
313        let g = groups_below(trial_bound(bits.len));
314        if has_factor_in(n, nn, &GROUP[..g]) {
315            return false;
316        }
317        probable_prime_odd(n, nn, bits, s)
318    }
319}
320
321/// Baillie–PSW for the odd number of `nn >= 2` limbs at `n`, at least `2^64` and with no prime
322/// factor up to 47, in registers up to seven limbs and in the [`prime_itch`] limbs at `s` beyond.
323///
324/// # Safety
325///
326/// As for [`is_prime_odd`].
327unsafe fn probable_prime_odd(n: *const u64, nn: usize, bits: Bits, s: *mut u64) -> bool {
328    let select = || {
329        // SAFETY: as the caller guarantees.
330        unsafe { selfridge(n, nn) }
331    };
332    // SAFETY: as the caller guarantees.
333    unsafe {
334        match nn {
335            2 => bpsw(&Mont2::new([*n, *n.add(1)]), bits, select),
336            3 => bpsw(&MontN::<3>::new(limbs(n)), bits, select),
337            4 => bpsw(&MontN::<4>::new(limbs(n)), bits, select),
338            5 => bpsw(&MontN::<5>::new(limbs(n)), bits, select),
339            6 => bpsw(&MontN::<6>::new(limbs(n)), bits, select),
340            7 => bpsw(&MontN::<7>::new(limbs(n)), bits, select),
341            _ => {
342                let f = LimbField::new(n, nn, s);
343                bpsw_limbs(&f, bits, s.add(LimbField::itch(nn)), select)
344            }
345        }
346    }
347}
348
349/// The `N` limbs at `n`.
350///
351/// # Safety
352///
353/// The limbs must be valid for reads.
354#[inline(always)]
355unsafe fn limbs<const N: usize>(n: *const u64) -> [u64; N] {
356    let mut a = [0; N];
357    // SAFETY: as the caller guarantees.
358    unsafe { core::ptr::copy_nonoverlapping(n, a.as_mut_ptr(), N) };
359    a
360}
361
362/// `3^2 5 7 11 ... 47`, the product of the odd primes to 47 and of 3 once more, below `2^64`: one
363/// remainder by it gives those by the first `|D|`s of Selfridge's search and by the primes that
364/// tell most squares apart.
365const SELFRIDGE: u64 = 9 * 5 * 7 * 11 * 13 * 17 * 19 * 23 * 29 * 31 * 37 * 41 * 43 * 47;
366
367/// [`SELFRIDGE`] shifted so that its top bit is set.
368const SELFRIDGE_D: u64 = SELFRIDGE << SELFRIDGE.leading_zeros();
369
370/// The reciprocal of [`SELFRIDGE_D`].
371const SELFRIDGE_V: u64 = (u128::MAX / SELFRIDGE_D as u128) as u64;
372
373/// The odd primes to 47, for the squares.
374const SQUARE_PRIMES: [u64; 14] = [3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47];
375
376/// Selfridge's `D` for the odd `n` of `nn >= 2` limbs, or `None` when `n` is a square or shares a
377/// factor with the `D`s before it: the first of `5, -7, 9, -11, ...` whose Jacobi symbol `(D/n)`
378/// is -1. A square's symbols are never -1, so squares are told apart first: the odd squares are 1
379/// modulo 8 and squares modulo every prime, which leaves the square root to check for few others.
380///
381/// # Safety
382///
383/// The limbs must be valid for reads, the top one not zero.
384unsafe fn selfridge(n: *const u64, nn: usize) -> Option<i64> {
385    // SAFETY: as the caller guarantees.
386    unsafe {
387        let r = rem_by(n, nn, SELFRIDGE_D, SELFRIDGE_V) % SELFRIDGE;
388        let low = *n;
389        if low & 7 == 1
390            && SQUARE_PRIMES
391                .iter()
392                .all(|&p| is_quadratic_residue(r % p, p))
393            && is_square(n, nn)
394        {
395            return None;
396        }
397        let mut a = 5u64;
398        loop {
399            let d = if a & 2 == 0 { a as i64 } else { -(a as i64) };
400            let n_mod_a = if SELFRIDGE.is_multiple_of(a) {
401                r % a
402            } else {
403                let s = a.leading_zeros();
404                rem_by(n, nn, a << s, reciprocal(a << s)) % a
405            };
406            match symbol(d, n_mod_a, low & 3) {
407                -1 => return Some(d),
408                0 => return None,
409                _ => a += 2,
410            }
411        }
412    }
413}
414
415/// Whether `r` is a square modulo the odd prime `p`, or zero: Euler's criterion, `r^((p-1)/2)`.
416fn is_quadratic_residue(r: u64, p: u64) -> bool {
417    r == 0 || jacobi(r, p) == 1
418}
419
420/// Whether the `nn` limbs at `n` are a perfect square: Newton's steps for the square root on
421/// numbers, from a power of two above it. Called for the few numbers that look like squares.
422///
423/// # Safety
424///
425/// The limbs must be valid for reads, the top one not zero.
426#[cold]
427#[inline(never)]
428unsafe fn is_square(n: *const u64, nn: usize) -> bool {
429    // SAFETY: as the caller guarantees.
430    let bytes: Vec<u8> = (0..nn)
431        .flat_map(|i| unsafe { *n.add(i) }.to_le_bytes())
432        .collect();
433    let x = Number::new(bytes, ByteOrder::LittleEndian);
434    // SAFETY: as the caller guarantees.
435    let bits = 64 * nn - unsafe { *n.add(nn - 1) }.leading_zeros() as usize;
436    let mut r = &Number::new_from_u8(1, ByteOrder::LittleEndian) << bits.div_ceil(2);
437    loop {
438        let next = &(&r + &(&x / &r)) >> 1;
439        if !(&next - &r).is_negative() {
440            break;
441        }
442        r = next;
443    }
444    (&r * &r).value == x.value
445}