layer_crypto/
factorize.rs1fn gcd(mut a: u128, mut b: u128) -> u128 {
22 while b != 0 {
23 let t = b;
24 b = a % b;
25 a = t;
26 }
27 a
28}
29
30fn modpow(mut n: u128, mut e: u128, m: u128) -> u128 {
31 if m == 1 {
32 return 0;
33 }
34 let mut result = 1;
35 n %= m;
36 while e > 0 {
37 if e & 1 == 1 {
38 result = result * n % m;
39 }
40 e >>= 1;
41 n = n * n % m;
42 }
43 result
44}
45
46fn abs_sub(a: u128, b: u128) -> u128 {
47 a.max(b) - a.min(b)
48}
49
50fn factorize_with(pq: u128, c: u128) -> (u64, u64) {
51 if pq.is_multiple_of(2) {
52 return (2, (pq / 2) as u64);
53 }
54
55 let mut y = 3 * (pq / 7);
56 let m = 7 * (pq / 13);
57 let mut g = 1u128;
58 let mut r = 1u128;
59 let mut q = 1u128;
60 let mut x = 0u128;
61 let mut ys = 0u128;
62
63 while g == 1 {
64 x = y;
65 for _ in 0..r {
66 y = (modpow(y, 2, pq) + c) % pq;
67 }
68 let mut k = 0;
69 while k < r && g == 1 {
70 ys = y;
71 for _ in 0..m.min(r - k) {
72 y = (modpow(y, 2, pq) + c) % pq;
73 q = q * abs_sub(x, y) % pq;
74 }
75 g = gcd(q, pq);
76 k += m;
77 }
78 r *= 2;
79 }
80
81 if g == pq {
82 loop {
83 ys = (modpow(ys, 2, pq) + c) % pq;
84 g = gcd(abs_sub(x, ys), pq);
85 if g > 1 {
86 break;
87 }
88 }
89 }
90
91 let p = g as u64;
92 let q = (pq / g) as u64;
93 (p.min(q), p.max(q))
94}
95
96pub fn factorize(pq: u64) -> (u64, u64) {
98 let n = pq as u128;
99 for attempt in [43u128, 47, 53, 59, 61] {
100 let c = attempt * (n / 103);
101 let (p, q) = factorize_with(n, c);
102 if p != 1 {
103 return (p, q);
104 }
105 }
106 panic!("factorize failed after fixed attempts");
107}
108
109#[cfg(test)]
110mod tests {
111 use super::*;
112 #[test]
113 fn t1() {
114 assert_eq!(factorize(1470626929934143021), (1206429347, 1218991343));
115 }
116 #[test]
117 fn t2() {
118 assert_eq!(factorize(2363612107535801713), (1518968219, 1556064227));
119 }
120}