machine_factor/
wfactor.rs

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