machine_factor/
mfactor.rs

1use crate::primes::PRIMES_101;
2
3/// Deterministic Random Bit Generator (xorshift)
4pub const fn drbg(mut x: u64) -> u64 {
5    x ^= x.wrapping_shr(12);
6    x ^= x.wrapping_shl(25);
7    x ^= x.wrapping_shr(27);
8    x.wrapping_mul(0x2545F4914F6CDD1D)
9}
10
11/// GCD(A,B) where B is odd
12#[no_mangle]
13pub const extern "C" fn partial_gcd(mut a: u64, mut b: u64) -> u64 {
14    if a == 0 {
15        return b;
16    }
17
18    let self_two_factor = a.trailing_zeros();
19
20    a >>= self_two_factor;
21
22    loop {
23        if b > a {
24            let interim = b;
25            b = a;
26            a = interim;
27        }
28        a -= b;
29
30        if a == 0 {
31            return b;
32        }
33        a >>= a.trailing_zeros();
34    }
35}
36
37const fn poly_eval(x: u64, subtrahend: u64, n: u64, npi: u64) -> u64 {
38    machine_prime::mont_sub(machine_prime::mont_prod(x, x, n, npi), subtrahend, n)
39}
40
41const fn pollard_brent(base: u64, inv: u64, subtrahend: u64, n: u64) -> Option<u64> {
42    let m = 128;
43    let mut r = 1;
44    let mut q = 1;
45    let mut g = 1;
46    let mut ys = 1;
47    let mut y = base;
48    let mut x = y;
49    let mut cycle = 0;
50
51    while cycle < 17 {
52        cycle += 1;
53        x = y;
54
55        let mut yloop = 0;
56
57        while yloop < r {
58            yloop += 1;
59            y = poly_eval(y, subtrahend, n, inv);
60        }
61
62        let mut k = 0;
63
64        loop {
65            let mut i = 0;
66
67            while i < m * cycle {
68                if i >= r - k {
69                    break;
70                }
71
72                y = poly_eval(y, subtrahend, n, inv);
73                q = machine_prime::mont_prod(q, x.abs_diff(y), n, inv);
74                i += 1;
75            } // end loop
76
77            ys = y;
78            g = partial_gcd(q, n);
79            k += m;
80            if k >= r || g != 1 {
81                break;
82            }
83        }
84
85        r <<= 1;
86        if g != 1 {
87            break;
88        }
89    }
90
91    if g == n {
92        while g == 1 {
93            ys = poly_eval(ys, subtrahend, n, inv);
94            g = partial_gcd(x.abs_diff(ys), n);
95        }
96    }
97
98    if g != 1 && g != n && machine_prime::is_prime_wc(g) {
99        return Some(g);
100    }
101    None
102}
103
104/// Returns some prime factor of an 64-bit integer
105///
106/// This function uses the Pollard-rho algorithm and mostly exists for FFI
107#[no_mangle]
108pub const extern "C" fn get_factor(n: u64) -> u64 {
109    let inv = machine_prime::mul_inv2(n);
110    let one = machine_prime::one_mont(n);
111    let base = machine_prime::two_mont(one, n);
112
113    match pollard_brent(base, inv, one, n) {
114        Some(factor) => return factor,
115        None => {
116            // if x^2 -1 failed try x^2+1
117            // No particular reason except to reuse some values
118            let coef = n.wrapping_sub(one); //machine_prime::to_mont(n-1,n);
119            match pollard_brent(base, inv, coef, n) {
120                Some(factor) => return factor,
121                None => {
122                    // Loop that has a roughly 0.5 probability of factoring each iteration
123                    let mut param = drbg(n);
124                    loop {
125                        let rand_base = param % (n - 3) + 3;
126                        match pollard_brent(rand_base, inv, one, n) {
127                            Some(factor) => return factor,
128                            None => param = drbg(param),
129                        }
130                    }
131                }
132            }
133        }
134    }
135}
136
137/// Factorisation of an integer
138///
139/// Representation of the factors in the form p^k p2^k
140#[repr(C)]
141pub struct Factorization {
142    pub factors: [u64; 15],
143    pub powers: [u8; 15],
144    pub len: usize,
145}
146
147impl Factorization {
148    const fn new() -> Self {
149        Factorization {
150            factors: [0u64; 15],
151            powers: [0u8; 15],
152            len: 0,
153        }
154    }
155}
156
157/// Complete factorization of N
158#[no_mangle]
159pub const extern "C" fn factorize(mut n: u64) -> Factorization {
160    let mut t = Factorization::new();
161
162    let mut idx = 0usize;
163
164    if n == 0 {
165        return t;
166    }
167    if n == 1 {
168        t.factors[0] = 1;
169        t.powers[1] = 1;
170        t.len = 1;
171        return t;
172    }
173
174    let twofactor = n.trailing_zeros();
175
176    if twofactor != 0 {
177        t.factors[0] = 2u64;
178        t.powers[0] = twofactor as u8;
179        n >>= twofactor;
180        idx += 1;
181    }
182
183    let mut i = 0usize;
184
185    while i < 101 {
186        let fctr = PRIMES_101[i] as u64;
187        // strips out small primes
188        if n % fctr == 0 {
189            t.factors[idx] = fctr;
190            let mut count = 0u8;
191            while n % fctr == 0 {
192                count += 1;
193                n /= fctr;
194            }
195            t.powers[idx] = count;
196            idx += 1;
197        }
198        i += 1;
199    }
200
201    if n == 1 {
202        t.len = idx;
203        return t;
204    }
205
206    if machine_prime::is_prime_wc(n) {
207        t.factors[idx] = n;
208        t.powers[idx] = 1;
209        idx += 1;
210        t.len = idx;
211        return t;
212    }
213    while n != 1 {
214        let k = get_factor(n);
215        t.factors[idx] = k;
216        let mut count = 0u8;
217        while n % k == 0 {
218            count += 1;
219            n /= k;
220        }
221        t.powers[idx] = count;
222        idx += 1;
223        if n == 1 {
224            t.len = idx;
225            return t;
226        }
227        if machine_prime::is_prime_wc(n) {
228            t.factors[idx] = n;
229            t.powers[idx] = 1;
230            idx += 1;
231            t.len = idx;
232            return t;
233        }
234    }
235    t
236}