-
Notifications
You must be signed in to change notification settings - Fork 72
/
baby_step_giant_step.rs
72 lines (66 loc) · 2 KB
/
baby_step_giant_step.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
/// Baby-step Giant-step algorithm
///
/// Solving discrete logarithm problem:
/// a^x = b (mod n) , with respect to gcd(a, n) == 1
/// with O(sqrt(n)) time complexity.
///
/// Wikipedia reference: https://en.wikipedia.org/wiki/Baby-step_giant-step
/// When a is the primitive root modulo n, the answer is unique.
/// Otherwise it will return the smallest positive solution
use std::collections::HashMap;
pub fn baby_step_giant_step(a: usize, b: usize, n: usize) -> Option<usize> {
if b == 1 {
return Some(n);
}
let mut h_map = HashMap::new();
let m = (n as f64).sqrt().ceil() as usize;
// baby step
let mut step = 1;
for i in 0..m {
h_map.insert((step * b) % n, i);
step = (step * a) % n;
}
// Now step = a^m (mod n), giant step
let giant_step = step;
for i in (m..=n).step_by(m) {
if let Some(v) = h_map.get(&step) {
return Some(i - v);
}
step = (step * giant_step) % n;
}
None
}
#[cfg(test)]
mod tests {
use super::baby_step_giant_step;
#[test]
fn small_numbers() {
assert_eq!(baby_step_giant_step(5, 3, 11), Some(2));
assert_eq!(baby_step_giant_step(3, 83, 100), Some(9));
}
#[test]
fn primitive_root_tests() {
assert_eq!(
baby_step_giant_step(3, 311401496, 998244353),
Some(178105253)
);
assert_eq!(
baby_step_giant_step(5, 324637211, 1000000007),
Some(976653449)
);
}
#[test]
fn random_numbers() {
assert_eq!(baby_step_giant_step(174857, 48604, 150991), Some(177));
assert_eq!(baby_step_giant_step(912103, 53821, 75401), Some(2644));
assert_eq!(baby_step_giant_step(448447, 365819, 671851), Some(23242));
assert_eq!(
baby_step_giant_step(220757103, 92430653, 434948279),
Some(862704)
);
assert_eq!(
baby_step_giant_step(176908456, 23538399, 142357679),
Some(14215560)
);
}
}