large_primes/operations/
pow.rs1use num_bigint::BigUint;
2use num_traits::{ One, Zero };
3
4pub fn pow(base: &BigUint, exp: &BigUint) -> BigUint {
30 let mut result = BigUint::one();
32 let mut current_base = base.clone();
33
34 let zero = BigUint::zero();
35 let one = BigUint::one();
36
37 let two = BigUint::from(2u32);
38
39 let mut power = exp.clone();
40
41 while &power > &zero {
42 if &power % &two == one {
43 result = &result * ¤t_base;
44 }
45
46 let shifted_power: BigUint = &power >> 1;
47 power = shifted_power.clone();
48 current_base = ¤t_base * ¤t_base;
49 }
50
51 result
52}
53
54pub fn pow_mod(base: &BigUint, exp: &BigUint, modulus: &BigUint) -> BigUint {
82 let mut result = BigUint::one();
84 let mut base = base % modulus;
85
86 let zero = BigUint::zero();
87 let one = BigUint::one();
88
89 let two = BigUint::from(2u32);
90
91 let mut power = exp.clone();
92
93 while &power > &zero {
94 if &power % &two == one {
95 result = (&result * &base) % modulus;
96 }
97
98 let shifted_power: BigUint = &power >> 1;
99 power = shifted_power.clone();
100 base = (&base * &base) % modulus;
101 }
102
103 result
104}
105
106#[cfg(test)]
107mod tests {
108 use super::*;
109
110 #[test]
111 fn normal_power() {
112 let base = BigUint::from(2u32);
113 let exp = BigUint::zero();
114
115 assert_eq!(pow(&base, &exp), BigUint::from(1u32));
116
117 let base = BigUint::from(2u32);
118 let exp = BigUint::from(10u32);
119
120 assert_eq!(pow(&base, &exp), BigUint::from(1024u32));
121
122 let base = BigUint::from(2u32);
123 let exp = BigUint::from(100u32);
124
125 assert_eq!(
126 pow(&base, &exp),
127 BigUint::parse_bytes(b"1267650600228229401496703205376", 10).unwrap()
128 );
129 }
130
131 #[test]
132 fn base_cases() {
133 let base = BigUint::from(2u32);
134 let exp = BigUint::from(2u32);
135 let modulus = BigUint::from(3u32);
136
137 assert_eq!(pow_mod(&base, &exp, &modulus), BigUint::from(1u32));
138
139 let base = BigUint::from(2u32);
140 let exp = BigUint::zero();
141 let modulus = BigUint::from(3u32);
142
143 assert_eq!(pow_mod(&base, &exp, &modulus), BigUint::from(1u32));
144
145 let base = BigUint::from(2u32);
146 let exp = BigUint::from(1u32);
147 let modulus = BigUint::from(2u32);
148
149 assert_eq!(pow_mod(&base, &exp, &modulus), BigUint::from(0u32));
150 }
151
152 #[test]
153 fn big_cases() {
154 let base = BigUint::from(2u32);
155 let exp = BigUint::from(10u32);
156 let modulus = BigUint::from(100u32);
157
158 assert_eq!(pow_mod(&base, &exp, &modulus), BigUint::from(24u32));
159
160 let base = BigUint::from(2u32);
161 let exp = BigUint::from(100u32);
162 let modulus = BigUint::from(1000u32);
163
164 assert_eq!(pow_mod(&base, &exp, &modulus), BigUint::from(376u32));
165
166 let base = BigUint::from(2u32);
167 let exp = BigUint::from(1000u32);
168 let modulus = BigUint::from(10000u32);
169
170 assert_eq!(pow_mod(&base, &exp, &modulus), BigUint::from(9376u32));
171
172 let base = BigUint::from(2u32);
173 let exp = BigUint::from(10000u32);
174 let modulus = BigUint::from(100000u32);
175
176 assert_eq!(pow_mod(&base, &exp, &modulus), BigUint::from(9376u32));
177 }
178}