machine_factor/
mfactor.rs

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