large_primes/primality/
fermat.rs1use num_bigint::BigUint;
2use num_traits::One;
3use crate::operations::pow_mod;
4use crate::operations::gcd;
5
6pub fn fermat(num: &BigUint) -> bool {
39 if *num <= BigUint::one() {
42 return false;
43 }
44
45 let switnesses = vec![2, 3, 5, 7, 11, 13, 17, 19, 23, 29];
46 let witnesses: Vec<BigUint> = switnesses
47 .iter()
48 .map(|x| BigUint::from(*x as u32))
49 .collect();
50 for witness in witnesses {
51 if gcd(&witness, num) != BigUint::one() {
52 continue;
53 }
54 let mod_value = pow_mod(&witness, &num, num);
55 let rhs = pow_mod(&witness, &BigUint::one(), &num);
56 if mod_value != rhs {
57 return false;
58 }
59 }
60 return true;
61}
62
63#[cfg(test)]
64mod tests {
65 use num_traits::Zero;
66
67 use super::*;
68
69 #[test]
70 fn edge_cases() {
71 assert_eq!(fermat(&BigUint::zero()), false);
73
74 assert_eq!(fermat(&BigUint::one()), false);
76
77 assert_eq!(fermat(&BigUint::from(2u32)), true);
79
80 assert_eq!(fermat(&BigUint::from(3u32)), true);
82
83 assert_eq!(fermat(&BigUint::from(4u32)), false);
85 }
86
87 #[test]
88 fn large_primes() {
89 let primes = [
90 "871603259",
92 "98762051",
93 "1000000007",
94 "123575321",
95 "193818613",
96 "444444443",
97 "999999937",
98 "1000000000039",
99 "9999999929",
100 ];
101
102 for prime in primes {
103 let prime = BigUint::parse_bytes(prime.as_bytes(), 10).unwrap();
104 assert_eq!(fermat(&prime), true);
105 }
106 }
107
108 #[test]
109 fn large_composites() {
110 let primes = [
111 "871603259",
113 "98762051",
114 "1000000007",
115 "123575321",
116 "193818613",
117 "444444443",
118 "999999937",
119 "1000000000039",
120 "9999999929",
121 ];
122
123 for i in 0..primes.len() {
124 for j in 0..primes.len() {
125 if i == j {
126 continue;
127 }
128 let composite =
129 BigUint::parse_bytes(primes[i].as_bytes(), 10).unwrap() *
130 BigUint::parse_bytes(primes[j].as_bytes(), 10).unwrap();
131 assert_eq!(fermat(&composite), false);
132 }
133 }
134 }
135
136 #[test]
137 fn carmichael_number() {
138 let carmichaels: Vec<BigUint> = vec![
139 BigUint::parse_bytes(b"561", 10).unwrap(),
140 BigUint::parse_bytes(b"41041", 10).unwrap(),
141 BigUint::parse_bytes(b"825265", 10).unwrap(),
142 BigUint::parse_bytes(b"321197185", 10).unwrap(),
143 BigUint::parse_bytes(b"5394826801", 10).unwrap(),
144 BigUint::parse_bytes(b"232250619601", 10).unwrap(),
145 BigUint::parse_bytes(b"9746347772161", 10).unwrap(),
146 BigUint::parse_bytes(b"1436697831295441", 10).unwrap(),
147 BigUint::parse_bytes(b"60977817398996785", 10).unwrap(),
148 BigUint::parse_bytes(b"7156857700403137441", 10).unwrap()
149 ];
150
151 for carmichael in carmichaels {
152 assert_eq!(fermat(&carmichael), true);
153 }
154 }
155}