crypto_bigint/modular/boxed_monty_form/
pow.rs1use super::{mul::MontyMultiplier, BoxedMontyForm};
4use crate::{BoxedUint, ConstantTimeSelect, Limb, PowBoundedExp, Word};
5use alloc::vec::Vec;
6use subtle::{ConstantTimeEq, ConstantTimeLess};
7
8impl BoxedMontyForm {
9 pub fn pow(&self, exponent: &BoxedUint) -> Self {
11 self.pow_bounded_exp(exponent, exponent.bits_precision())
12 }
13
14 pub fn pow_bounded_exp(&self, exponent: &BoxedUint, exponent_bits: u32) -> Self {
20 let ret = Self {
21 montgomery_form: pow_montgomery_form(
22 &self.montgomery_form,
23 exponent,
24 exponent_bits,
25 &self.params.modulus,
26 &self.params.one,
27 self.params.mod_neg_inv,
28 ),
29 params: self.params.clone(),
30 };
31
32 debug_assert!(ret.retrieve() < self.params.modulus);
33 ret
34 }
35}
36
37impl PowBoundedExp<BoxedUint> for BoxedMontyForm {
38 fn pow_bounded_exp(&self, exponent: &BoxedUint, exponent_bits: u32) -> Self {
39 self.pow_bounded_exp(exponent, exponent_bits)
40 }
41}
42
43fn pow_montgomery_form(
49 x: &BoxedUint,
50 exponent: &BoxedUint,
51 exponent_bits: u32,
52 modulus: &BoxedUint,
53 one: &BoxedUint,
54 mod_neg_inv: Limb,
55) -> BoxedUint {
56 if exponent_bits == 0 {
57 return one.clone(); }
59
60 const WINDOW: u32 = 4;
61 const WINDOW_MASK: Word = (1 << WINDOW) - 1;
62
63 let mut multiplier = MontyMultiplier::new(modulus, mod_neg_inv);
64
65 let mut powers = Vec::with_capacity(1 << WINDOW);
67 powers.push(one.clone()); powers.push(x.clone());
69
70 for i in 2..(1 << WINDOW) {
71 powers.push(multiplier.mul_amm(&powers[i - 1], x));
72 }
73
74 let starting_limb = ((exponent_bits - 1) / Limb::BITS) as usize;
75 let starting_bit_in_limb = (exponent_bits - 1) % Limb::BITS;
76 let starting_window = starting_bit_in_limb / WINDOW;
77 let starting_window_mask = (1 << (starting_bit_in_limb % WINDOW + 1)) - 1;
78
79 let mut z = one.clone(); let mut power = powers[0].clone();
81
82 for limb_num in (0..=starting_limb).rev() {
83 let w = exponent.as_limbs()[limb_num].0;
84
85 let mut window_num = if limb_num == starting_limb {
86 starting_window + 1
87 } else {
88 Limb::BITS / WINDOW
89 };
90
91 while window_num > 0 {
92 window_num -= 1;
93
94 let mut idx = (w >> (window_num * WINDOW)) & WINDOW_MASK;
95
96 if limb_num == starting_limb && window_num == starting_window {
97 idx &= starting_window_mask;
98 } else {
99 for _ in 1..=WINDOW {
100 multiplier.square_amm_assign(&mut z);
101 }
102 }
103
104 power.limbs.copy_from_slice(&powers[0].limbs);
106 for i in 1..(1 << WINDOW) {
107 power.ct_assign(&powers[i as usize], i.ct_eq(&idx));
108 }
109
110 multiplier.mul_amm_assign(&mut z, &power);
111 }
112 }
113
114 z.conditional_sbb_assign(modulus, !z.ct_lt(modulus));
117
118 z.conditional_sbb_assign(modulus, !z.ct_lt(modulus));
121 debug_assert!(&z < modulus);
122
123 z
124}