dsif/
lib.rs

1#[macro_use]
2extern crate log;
3
4use traceidr::TraceId;
5use std::fmt;
6
7fn u64_sqrt(n: u64) -> u64 {
8    if n == 0 || n == 1 {
9        return n;
10    }
11
12    let mut i = 0;
13    let mut result = 0;
14
15    while result <= n {
16        i += 1;
17        result = i * i;
18    }
19
20    return i - 1;
21}
22
23#[derive(Copy, Clone, PartialEq, PartialOrd, Ord, Eq, Debug)]
24struct U128 {
25    hi: u64,
26    lo: u64,
27}
28
29fn modulo(mut a: U128, m: u64) -> u64 {
30    if a.hi >= m {
31        a.hi -= (a.hi / m) * m;
32    }
33    let mut x = a.hi;
34    let mut y = a.lo;
35    for _ in 0..64 {
36        let t = (x as i64 >> 63) as u64;
37        x = (x << 1) | (y >> 63);
38        y <<= 1;
39        if (x | t) >= m {
40            x = x.wrapping_sub(m);
41            y += 1;
42        }
43    }
44    x
45}
46fn mul128(u: u64, v: u64) -> U128 {
47    let u1 = u >> 32;
48    let u0 = u & (!0 >> 32);
49    let v1 = v >> 32;
50    let v0 = v & (!0 >> 32);
51
52    let t = u0 * v0;
53    let w0 = t & (!0 >> 32);
54    let k = t >> 32;
55
56    let t = u1 * v0 + k;
57    let w1 = t & (!0 >> 32);
58    let w2 = t >> 32;
59
60    let t = u0 * v1 + w1;
61    let k = t >> 32;
62    U128 {
63        lo: (t << 32) + w0,
64        hi: u1 * v1 + w2 + k,
65    }
66}
67fn mod_mul_(a: u64, b: u64, m: u64) -> u64 {
68    modulo(mul128(a, b), m)
69}
70
71fn mod_mul(a: u64, b: u64, m: u64) -> u64 {
72    match a.checked_mul(b) {
73        Some(r) => {
74            if r >= m {
75                r % m
76            } else {
77                r
78            }
79        }
80        None => mod_mul_(a, b, m),
81    }
82}
83
84fn mod_sqr(a: u64, m: u64) -> u64 {
85    if a < (1 << 32) {
86        let r = a * a;
87        if r >= m {
88            r % m
89        } else {
90            r
91        }
92    } else {
93        mod_mul_(a, a, m)
94    }
95}
96
97fn mod_exp(mut x: u64, mut d: u64, n: u64) -> u64 {
98    let mut ret: u64 = 1;
99    while d != 0 {
100        if d % 2 == 1 {
101            ret = mod_mul(ret, x, n)
102        }
103        d /= 2;
104        x = mod_sqr(x, n);
105    }
106    ret
107}
108
109fn miller_rabin(n: u64) -> bool {
110    const HINT: &'static [u64] = &[2];
111
112    // we have a strict upper bound, so we can just use the witness
113    // table of Pomerance, Selfridge & Wagstaff and Jeaschke to be as
114    // efficient as possible, without having to fall back to
115    // randomness.
116    const WITNESSES: &'static [(u64, &'static [u64])] = &[
117        (2_046, HINT),
118        (1_373_652, &[2, 3]),
119        (9_080_190, &[31, 73]),
120        (25_326_000, &[2, 3, 5]),
121        (4_759_123_140, &[2, 7, 61]),
122        (1_112_004_669_632, &[2, 13, 23, 1662803]),
123        (2_152_302_898_746, &[2, 3, 5, 7, 11]),
124        (3_474_749_660_382, &[2, 3, 5, 7, 11, 13]),
125        (341_550_071_728_320, &[2, 3, 5, 7, 11, 13, 17]),
126        (0xFFFF_FFFF_FFFF_FFFF, &[2, 3, 5, 7, 11, 13, 17, 19, 23]),
127    ];
128
129    let trace = TraceId::new();
130    debug!(
131        "Running Miller-Rabin test for the number {} with TraceId {}. This is an expensive task.",
132        n, trace
133    );
134
135    if n % 2 == 0 {
136        return n == 2;
137    }
138    if n == 1 {
139        return false;
140    }
141
142    let mut d = n - 1;
143    let mut s = 0;
144    while d % 2 == 0 {
145        d /= 2;
146        s += 1
147    }
148
149    let witnesses = WITNESSES
150        .iter()
151        .find(|&&(hi, _)| hi >= n)
152        .map(|&(_, wtnss)| wtnss)
153        .unwrap();
154    'next_witness: for &a in witnesses.iter() {
155        let mut power = mod_exp(a, d, n);
156        assert!(power < n);
157        if power == 1 || power == n - 1 {
158            continue 'next_witness;
159        }
160
161        for _r in 0..s {
162            power = mod_sqr(power, n);
163            assert!(power < n);
164            if power == 1 {
165                return false;
166            }
167            if power == n - 1 {
168                continue 'next_witness;
169            }
170        }
171        debug!(
172            "Miller-Rabin test completed for number {} with TraceId {} with a result of false.",
173            n, trace
174        );
175        return false;
176    }
177
178    debug!(
179        "Miller-Rabin test completed for number {} with TraceId {} with a result of true.",
180        n, trace
181    );
182    true
183}
184
185fn is_prime(num: u64) -> bool {
186    let trace = TraceId::new();
187    debug!(
188        "Running primality tests for {} with TraceId {}.",
189        num, trace
190    );
191    let is_prime = miller_rabin(num);
192    debug!(
193        "Primality test for number {} with TraceId {} produced result {}.",
194        num, trace, is_prime
195    );
196    is_prime
197}
198
199pub struct Factors {
200    inner: Vec<u64>,
201}
202
203impl Factors {
204    fn new() -> Self {
205        Self {
206            inner: Vec::new(),
207        }
208    }
209
210    fn add(&mut self, f: u64) {
211        self.inner.push(f);
212    }
213}
214
215impl fmt::Display for Factors {
216    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
217        let mut flag = false;
218        for (i, factor) in self.inner.iter().enumerate() {
219            if flag {
220                write!(f, "* {}", factor)?;
221            } else {
222                flag = true;
223                write!(f, "{}", factor)?;
224            }
225            if i != self.inner.len() - 1 {
226                write!(f, " ")?;
227            }
228        }
229        Ok(())
230    }
231}
232
233pub fn factorize_to_primes(mut num: u64) -> Factors {
234    let trace = TraceId::new();
235    debug!("Factorizing number {} with TraceId {}.", num, trace);
236    let mut factors = Factors::new();
237
238    if is_prime(num) {
239        debug!(
240            "Number passed primality test. Returning as is. TraceId {}.",
241            trace
242        );
243        factors.add(num);
244        return factors;
245    } else {
246        debug!(
247            "Number did not pass primality test. Continuing. TraceId {}.",
248            trace
249        );
250    }
251
252    while num % 2 == 0 {
253        factors.add(2);
254        num /= 2;
255    }
256
257    let mut i = 3;
258    let e = u64_sqrt(num);
259    while i <= e {
260        while num % i == 0 {
261            factors.add(i);
262            num /= i;
263        }
264
265        i += 2;
266    }
267
268    if num > 2 {
269        factors.add(num);
270    }
271
272    debug!(
273        "Finished factorization of number {} with TraceId {}.",
274        num, trace
275    );
276
277    factors
278}