@@ -31,13 +31,31 @@ impl<const LIMBS: usize> MontyForm<LIMBS> {
3131 exponent_bits : u32 ,
3232 ) -> Self {
3333 Self {
34- montgomery_form : pow_montgomery_form (
34+ montgomery_form : pow_montgomery_form :: < LIMBS , RHS_LIMBS , false > (
3535 & self . montgomery_form ,
3636 exponent,
3737 exponent_bits,
38- & self . params . modulus ,
39- & self . params . one ,
40- self . params . mod_neg_inv ( ) ,
38+ & self . params ,
39+ ) ,
40+ params : self . params ,
41+ }
42+ }
43+
44+ /// Raises to the `exponent` power.
45+ ///
46+ /// This method is variable time in `exponent`.
47+ #[ must_use]
48+ pub const fn pow_vartime < const RHS_LIMBS : usize > (
49+ & self ,
50+ exponent : & Uint < RHS_LIMBS > ,
51+ ) -> MontyForm < LIMBS > {
52+ let exponent_bits = exponent. bits_vartime ( ) ;
53+ Self {
54+ montgomery_form : pow_montgomery_form :: < LIMBS , RHS_LIMBS , true > (
55+ & self . montgomery_form ,
56+ exponent,
57+ exponent_bits,
58+ & self . params ,
4159 ) ,
4260 params : self . params ,
4361 }
@@ -74,12 +92,10 @@ impl<const N: usize, const LIMBS: usize, const RHS_LIMBS: usize>
7492 }
7593
7694 Self {
77- montgomery_form : multi_exponentiate_montgomery_form_array (
95+ montgomery_form : multi_exponentiate_montgomery_form_array :: < LIMBS , RHS_LIMBS , N , false > (
7896 & bases_and_exponents_montgomery_form,
7997 exponent_bits,
80- & params. modulus ,
81- & params. one ,
82- params. mod_neg_inv ( ) ,
98+ & params,
8399 ) ,
84100 params,
85101 }
@@ -105,14 +121,148 @@ impl<const LIMBS: usize, const RHS_LIMBS: usize>
105121 . map ( |( base, exp) | ( base. montgomery_form , * exp) )
106122 . collect ( ) ;
107123 Self {
108- montgomery_form : multi_exponentiate_montgomery_form_slice (
124+ montgomery_form : multi_exponentiate_montgomery_form_slice :: < LIMBS , RHS_LIMBS , false > (
109125 & bases_and_exponents,
110126 exponent_bits,
111- & params. modulus ,
112- & params. one ,
113- params. mod_neg_inv ( ) ,
127+ & params,
114128 ) ,
115129 params,
116130 }
117131 }
118132}
133+
134+ #[ cfg( test) ]
135+ mod tests {
136+ use crate :: traits:: MultiExponentiate ;
137+ use crate :: {
138+ U256 ,
139+ modular:: { MontyForm , MontyParams } ,
140+ } ;
141+
142+ const PARAMS : MontyParams < { U256 :: LIMBS } > = MontyParams :: new_vartime (
143+ U256 :: from_be_hex ( "9CC24C5DF431A864188AB905AC751B727C9447A8E99E6366E1AD78A21E8D882B" )
144+ . to_odd ( )
145+ . expect_copied ( "ensured odd" ) ,
146+ ) ;
147+
148+ #[ test]
149+ fn test_powmod_zero ( ) {
150+ let base = U256 :: from ( 105u64 ) ;
151+ let base_mod = MontyForm :: new ( & base, & PARAMS ) ;
152+
153+ let res = base_mod. pow ( & U256 :: ZERO ) ;
154+ let res_vartime = base_mod. pow_vartime ( & U256 :: ZERO ) ;
155+
156+ assert_eq ! ( res. retrieve( ) , U256 :: ONE ) ;
157+ assert_eq ! ( res_vartime. retrieve( ) , U256 :: ONE ) ;
158+ }
159+
160+ #[ test]
161+ fn test_powmod_small_base ( ) {
162+ let base = U256 :: from ( 105u64 ) ;
163+ let base_mod = MontyForm :: new ( & base, & PARAMS ) ;
164+
165+ let exponent =
166+ U256 :: from_be_hex ( "77117F1273373C26C700D076B3F780074D03339F56DD0EFB60E7F58441FD3685" ) ;
167+
168+ let res = base_mod. pow ( & exponent) ;
169+ let res_vartime = base_mod. pow_vartime ( & exponent) ;
170+
171+ let expected =
172+ U256 :: from_be_hex ( "7B2CD7BDDD96C271E6F232F2F415BB03FE2A90BD6CCCEA5E94F1BFD064993766" ) ;
173+ assert_eq ! ( res. retrieve( ) , expected) ;
174+ assert_eq ! ( res_vartime. retrieve( ) , expected) ;
175+ }
176+
177+ #[ test]
178+ fn test_powmod_small_exponent ( ) {
179+ let base =
180+ U256 :: from_be_hex ( "3435D18AA8313EBBE4D20002922225B53F75DC4453BB3EEC0378646F79B524A4" ) ;
181+ let base_mod = MontyForm :: new ( & base, & PARAMS ) ;
182+
183+ let exponent = U256 :: from ( 105u64 ) ;
184+
185+ let res = base_mod. pow ( & exponent) ;
186+ let res_vartime = base_mod. pow_vartime ( & exponent) ;
187+
188+ let expected =
189+ U256 :: from_be_hex ( "89E2A4E99F649A5AE2C18068148C355CA927B34A3245C938178ED00D6EF218AA" ) ;
190+ assert_eq ! ( res. retrieve( ) , expected) ;
191+ assert_eq ! ( res_vartime. retrieve( ) , expected) ;
192+ }
193+
194+ #[ test]
195+ fn test_powmod ( ) {
196+ let base =
197+ U256 :: from_be_hex ( "3435D18AA8313EBBE4D20002922225B53F75DC4453BB3EEC0378646F79B524A4" ) ;
198+ let base_mod = MontyForm :: new ( & base, & PARAMS ) ;
199+
200+ let exponent =
201+ U256 :: from_be_hex ( "77117F1273373C26C700D076B3F780074D03339F56DD0EFB60E7F58441FD3685" ) ;
202+
203+ let res = base_mod. pow ( & exponent) ;
204+ let res_vartime = base_mod. pow ( & exponent) ;
205+
206+ let expected =
207+ U256 :: from_be_hex ( "3681BC0FEA2E5D394EB178155A127B0FD2EF405486D354251C385BDD51B9D421" ) ;
208+ assert_eq ! ( res. retrieve( ) , expected) ;
209+ assert_eq ! ( res_vartime. retrieve( ) , expected) ;
210+ }
211+
212+ #[ test]
213+ fn test_multi_exp_array ( ) {
214+ let base = U256 :: from ( 2u8 ) ;
215+ let base_mod = MontyForm :: new ( & base, & PARAMS ) ;
216+
217+ let exponent = U256 :: from ( 33u8 ) ;
218+ let bases_and_exponents = [ ( base_mod, exponent) ] ;
219+ let res = MontyForm :: < { U256 :: LIMBS } > :: multi_exponentiate ( & bases_and_exponents) ;
220+
221+ let expected =
222+ U256 :: from_be_hex ( "0000000000000000000000000000000000000000000000000000000200000000" ) ;
223+
224+ assert_eq ! ( res. retrieve( ) , expected) ;
225+
226+ let base2 =
227+ U256 :: from_be_hex ( "3435D18AA8313EBBE4D20002922225B53F75DC4453BB3EEC0378646F79B524A4" ) ;
228+ let base2_mod = MontyForm :: new ( & base2, & PARAMS ) ;
229+
230+ let exponent2 =
231+ U256 :: from_be_hex ( "77117F1273373C26C700D076B3F780074D03339F56DD0EFB60E7F58441FD3685" ) ;
232+
233+ let expected = base_mod. pow ( & exponent) * base2_mod. pow ( & exponent2) ;
234+ let bases_and_exponents = [ ( base_mod, exponent) , ( base2_mod, exponent2) ] ;
235+ let res = MontyForm :: < { U256 :: LIMBS } > :: multi_exponentiate ( & bases_and_exponents) ;
236+
237+ assert_eq ! ( res, expected) ;
238+ }
239+
240+ #[ cfg( feature = "alloc" ) ]
241+ #[ test]
242+ fn test_multi_exp_slice ( ) {
243+ let base = U256 :: from ( 2u8 ) ;
244+ let base_mod = MontyForm :: new ( & base, & PARAMS ) ;
245+
246+ let exponent = U256 :: from ( 33u8 ) ;
247+ let bases_and_exponents = vec ! [ ( base_mod, exponent) ] ;
248+ let res = MontyForm :: < { U256 :: LIMBS } > :: multi_exponentiate ( bases_and_exponents. as_slice ( ) ) ;
249+
250+ let expected =
251+ U256 :: from_be_hex ( "0000000000000000000000000000000000000000000000000000000200000000" ) ;
252+
253+ assert_eq ! ( res. retrieve( ) , expected) ;
254+
255+ let base2 =
256+ U256 :: from_be_hex ( "3435D18AA8313EBBE4D20002922225B53F75DC4453BB3EEC0378646F79B524A4" ) ;
257+ let base2_mod = MontyForm :: new ( & base2, & PARAMS ) ;
258+
259+ let exponent2 =
260+ U256 :: from_be_hex ( "77117F1273373C26C700D076B3F780074D03339F56DD0EFB60E7F58441FD3685" ) ;
261+
262+ let expected = base_mod. pow ( & exponent) * base2_mod. pow ( & exponent2) ;
263+ let bases_and_exponents = vec ! [ ( base_mod, exponent) , ( base2_mod, exponent2) ] ;
264+ let res = MontyForm :: < { U256 :: LIMBS } > :: multi_exponentiate ( bases_and_exponents. as_slice ( ) ) ;
265+
266+ assert_eq ! ( res, expected) ;
267+ }
268+ }
0 commit comments