crypto_bigint/uint/modular/constant_mod/
const_pow.rs1use crate::{modular::pow::pow_montgomery_form, MultiExponentiateBoundedExp, PowBoundedExp, Uint};
2
3use super::{Residue, ResidueParams};
4use crate::modular::pow::multi_exponentiate_montgomery_form_array;
5#[cfg(feature = "alloc")]
6use crate::modular::pow::multi_exponentiate_montgomery_form_slice;
7#[cfg(feature = "alloc")]
8use alloc::vec::Vec;
9
10impl<MOD: ResidueParams<LIMBS>, const LIMBS: usize> Residue<MOD, LIMBS> {
11 pub const fn pow<const RHS_LIMBS: usize>(
13 &self,
14 exponent: &Uint<RHS_LIMBS>,
15 ) -> Residue<MOD, LIMBS> {
16 self.pow_bounded_exp(exponent, Uint::<RHS_LIMBS>::BITS)
17 }
18
19 pub const fn pow_bounded_exp<const RHS_LIMBS: usize>(
25 &self,
26 exponent: &Uint<RHS_LIMBS>,
27 exponent_bits: usize,
28 ) -> Residue<MOD, LIMBS> {
29 Self {
30 montgomery_form: pow_montgomery_form(
31 &self.montgomery_form,
32 exponent,
33 exponent_bits,
34 &MOD::MODULUS,
35 &MOD::R,
36 MOD::MOD_NEG_INV,
37 ),
38 phantom: core::marker::PhantomData,
39 }
40 }
41}
42
43impl<MOD: ResidueParams<LIMBS>, const LIMBS: usize, const RHS_LIMBS: usize>
44 PowBoundedExp<Uint<RHS_LIMBS>> for Residue<MOD, LIMBS>
45{
46 fn pow_bounded_exp(&self, exponent: &Uint<RHS_LIMBS>, exponent_bits: usize) -> Self {
47 self.pow_bounded_exp(exponent, exponent_bits)
48 }
49}
50
51impl<const N: usize, MOD: ResidueParams<LIMBS>, const LIMBS: usize, const RHS_LIMBS: usize>
52 MultiExponentiateBoundedExp<Uint<RHS_LIMBS>, [(Self, Uint<RHS_LIMBS>); N]>
53 for Residue<MOD, LIMBS>
54{
55 fn multi_exponentiate_bounded_exp(
56 bases_and_exponents: &[(Self, Uint<RHS_LIMBS>); N],
57 exponent_bits: usize,
58 ) -> Self {
59 let mut bases_and_exponents_montgomery_form =
60 [(Uint::<LIMBS>::ZERO, Uint::<RHS_LIMBS>::ZERO); N];
61
62 let mut i = 0;
63 while i < N {
64 let (base, exponent) = bases_and_exponents[i];
65 bases_and_exponents_montgomery_form[i] = (base.montgomery_form, exponent);
66 i += 1;
67 }
68
69 Self {
70 montgomery_form: multi_exponentiate_montgomery_form_array(
71 &bases_and_exponents_montgomery_form,
72 exponent_bits,
73 &MOD::MODULUS,
74 &MOD::R,
75 MOD::MOD_NEG_INV,
76 ),
77 phantom: core::marker::PhantomData,
78 }
79 }
80}
81
82#[cfg(feature = "alloc")]
83impl<MOD: ResidueParams<LIMBS>, const LIMBS: usize, const RHS_LIMBS: usize>
84 MultiExponentiateBoundedExp<Uint<RHS_LIMBS>, [(Self, Uint<RHS_LIMBS>)]>
85 for Residue<MOD, LIMBS>
86{
87 fn multi_exponentiate_bounded_exp(
88 bases_and_exponents: &[(Self, Uint<RHS_LIMBS>)],
89 exponent_bits: usize,
90 ) -> Self {
91 let bases_and_exponents: Vec<(Uint<LIMBS>, Uint<RHS_LIMBS>)> = bases_and_exponents
92 .iter()
93 .map(|(base, exp)| (base.montgomery_form, *exp))
94 .collect();
95 Self {
96 montgomery_form: multi_exponentiate_montgomery_form_slice(
97 &bases_and_exponents,
98 exponent_bits,
99 &MOD::MODULUS,
100 &MOD::R,
101 MOD::MOD_NEG_INV,
102 ),
103 phantom: core::marker::PhantomData,
104 }
105 }
106}
107
108#[cfg(test)]
109mod tests {
110 use crate::traits::MultiExponentiate;
111 use crate::{const_residue, impl_modulus, modular::constant_mod::ResidueParams, U256};
112
113 impl_modulus!(
114 Modulus,
115 U256,
116 "9CC24C5DF431A864188AB905AC751B727C9447A8E99E6366E1AD78A21E8D882B"
117 );
118
119 #[test]
120 fn test_powmod_small_base() {
121 let base = U256::from(105u64);
122 let base_mod = const_residue!(base, Modulus);
123
124 let exponent =
125 U256::from_be_hex("77117F1273373C26C700D076B3F780074D03339F56DD0EFB60E7F58441FD3685");
126
127 let res = base_mod.pow(&exponent);
128
129 let expected =
130 U256::from_be_hex("7B2CD7BDDD96C271E6F232F2F415BB03FE2A90BD6CCCEA5E94F1BFD064993766");
131 assert_eq!(res.retrieve(), expected);
132 }
133
134 #[test]
135 fn test_powmod_small_exponent() {
136 let base =
137 U256::from_be_hex("3435D18AA8313EBBE4D20002922225B53F75DC4453BB3EEC0378646F79B524A4");
138 let base_mod = const_residue!(base, Modulus);
139
140 let exponent = U256::from(105u64);
141
142 let res = base_mod.pow(&exponent);
143
144 let expected =
145 U256::from_be_hex("89E2A4E99F649A5AE2C18068148C355CA927B34A3245C938178ED00D6EF218AA");
146 assert_eq!(res.retrieve(), expected);
147 }
148
149 #[test]
150 fn test_powmod() {
151 let base =
152 U256::from_be_hex("3435D18AA8313EBBE4D20002922225B53F75DC4453BB3EEC0378646F79B524A4");
153 let base_mod = const_residue!(base, Modulus);
154
155 let exponent =
156 U256::from_be_hex("77117F1273373C26C700D076B3F780074D03339F56DD0EFB60E7F58441FD3685");
157
158 let res = base_mod.pow(&exponent);
159
160 let expected =
161 U256::from_be_hex("3681BC0FEA2E5D394EB178155A127B0FD2EF405486D354251C385BDD51B9D421");
162 assert_eq!(res.retrieve(), expected);
163 }
164
165 #[test]
166 fn test_multi_exp_array() {
167 let base = U256::from(2u8);
168 let base_mod = const_residue!(base, Modulus);
169
170 let exponent = U256::from(33u8);
171 let bases_and_exponents = [(base_mod, exponent)];
172 let res =
173 crate::modular::constant_mod::Residue::<Modulus, { U256::LIMBS }>::multi_exponentiate(
174 &bases_and_exponents,
175 );
176
177 let expected =
178 U256::from_be_hex("0000000000000000000000000000000000000000000000000000000200000000");
179
180 assert_eq!(res.retrieve(), expected);
181
182 let base2 =
183 U256::from_be_hex("3435D18AA8313EBBE4D20002922225B53F75DC4453BB3EEC0378646F79B524A4");
184 let base2_mod = const_residue!(base2, Modulus);
185
186 let exponent2 =
187 U256::from_be_hex("77117F1273373C26C700D076B3F780074D03339F56DD0EFB60E7F58441FD3685");
188
189 let expected = base_mod.pow(&exponent) * base2_mod.pow(&exponent2);
190 let bases_and_exponents = [(base_mod, exponent), (base2_mod, exponent2)];
191 let res =
192 crate::modular::constant_mod::Residue::<Modulus, { U256::LIMBS }>::multi_exponentiate(
193 &bases_and_exponents,
194 );
195
196 assert_eq!(res, expected);
197 }
198
199 #[cfg(feature = "alloc")]
200 #[test]
201 fn test_multi_exp_slice() {
202 let base = U256::from(2u8);
203 let base_mod = const_residue!(base, Modulus);
204
205 let exponent = U256::from(33u8);
206 let bases_and_exponents = vec![(base_mod, exponent)];
207 let res =
208 crate::modular::constant_mod::Residue::<Modulus, { U256::LIMBS }>::multi_exponentiate(
209 bases_and_exponents.as_slice(),
210 );
211
212 let expected =
213 U256::from_be_hex("0000000000000000000000000000000000000000000000000000000200000000");
214
215 assert_eq!(res.retrieve(), expected);
216
217 let base2 =
218 U256::from_be_hex("3435D18AA8313EBBE4D20002922225B53F75DC4453BB3EEC0378646F79B524A4");
219 let base2_mod = const_residue!(base2, Modulus);
220
221 let exponent2 =
222 U256::from_be_hex("77117F1273373C26C700D076B3F780074D03339F56DD0EFB60E7F58441FD3685");
223
224 let expected = base_mod.pow(&exponent) * base2_mod.pow(&exponent2);
225 let bases_and_exponents = vec![(base_mod, exponent), (base2_mod, exponent2)];
226 let res =
227 crate::modular::constant_mod::Residue::<Modulus, { U256::LIMBS }>::multi_exponentiate(
228 bases_and_exponents.as_slice(),
229 );
230
231 assert_eq!(res, expected);
232 }
233}