crypto_bigint/modular/boxed_monty_form/
mul.rs1use super::{BoxedMontyForm, BoxedMontyParams};
9use crate::{
10 modular::reduction::montgomery_reduction_boxed_mut, uint::mul::mul_limbs, BoxedUint, Limb,
11 Square, SquareAssign, Word, Zero,
12};
13use core::{
14 borrow::Borrow,
15 ops::{Mul, MulAssign},
16};
17use subtle::{ConditionallySelectable, ConstantTimeLess};
18
19#[cfg(feature = "zeroize")]
20use zeroize::Zeroize;
21
22impl BoxedMontyForm {
23 pub fn mul(&self, rhs: &Self) -> Self {
25 debug_assert_eq!(&self.params, &rhs.params);
26 let montgomery_form = MontyMultiplier::from(self.params.borrow())
27 .mul(&self.montgomery_form, &rhs.montgomery_form);
28
29 Self {
30 montgomery_form,
31 params: self.params.clone(),
32 }
33 }
34
35 pub fn square(&self) -> Self {
37 let montgomery_form =
38 MontyMultiplier::from(self.params.borrow()).square(&self.montgomery_form);
39
40 Self {
41 montgomery_form,
42 params: self.params.clone(),
43 }
44 }
45}
46
47impl Mul<&BoxedMontyForm> for &BoxedMontyForm {
48 type Output = BoxedMontyForm;
49 fn mul(self, rhs: &BoxedMontyForm) -> BoxedMontyForm {
50 self.mul(rhs)
51 }
52}
53
54impl Mul<BoxedMontyForm> for &BoxedMontyForm {
55 type Output = BoxedMontyForm;
56 #[allow(clippy::op_ref)]
57 fn mul(self, rhs: BoxedMontyForm) -> BoxedMontyForm {
58 self * &rhs
59 }
60}
61
62impl Mul<&BoxedMontyForm> for BoxedMontyForm {
63 type Output = BoxedMontyForm;
64 #[allow(clippy::op_ref)]
65 fn mul(self, rhs: &BoxedMontyForm) -> BoxedMontyForm {
66 &self * rhs
67 }
68}
69
70impl Mul<BoxedMontyForm> for BoxedMontyForm {
71 type Output = BoxedMontyForm;
72 fn mul(self, rhs: BoxedMontyForm) -> BoxedMontyForm {
73 &self * &rhs
74 }
75}
76
77impl MulAssign<BoxedMontyForm> for BoxedMontyForm {
78 fn mul_assign(&mut self, rhs: BoxedMontyForm) {
79 Self::mul_assign(self, &rhs)
80 }
81}
82
83impl MulAssign<&BoxedMontyForm> for BoxedMontyForm {
84 fn mul_assign(&mut self, rhs: &BoxedMontyForm) {
85 debug_assert_eq!(&self.params, &rhs.params);
86 MontyMultiplier::from(self.params.borrow())
87 .mul_assign(&mut self.montgomery_form, &rhs.montgomery_form);
88 }
89}
90
91impl Square for BoxedMontyForm {
92 fn square(&self) -> Self {
93 BoxedMontyForm::square(self)
94 }
95}
96
97impl SquareAssign for BoxedMontyForm {
98 fn square_assign(&mut self) {
99 MontyMultiplier::from(self.params.borrow()).square_assign(&mut self.montgomery_form);
100 }
101}
102
103impl<'a> From<&'a BoxedMontyParams> for MontyMultiplier<'a> {
104 fn from(params: &'a BoxedMontyParams) -> MontyMultiplier<'a> {
105 MontyMultiplier::new(¶ms.modulus, params.mod_neg_inv)
106 }
107}
108
109pub(super) struct MontyMultiplier<'a> {
111 product: BoxedUint,
112 modulus: &'a BoxedUint,
113 mod_neg_inv: Limb,
114}
115
116impl<'a> MontyMultiplier<'a> {
117 pub(super) fn new(modulus: &'a BoxedUint, mod_neg_inv: Limb) -> Self {
119 Self {
120 product: BoxedUint::zero_with_precision(modulus.bits_precision() * 2),
121 modulus,
122 mod_neg_inv,
123 }
124 }
125
126 pub(super) fn mul(&mut self, a: &BoxedUint, b: &BoxedUint) -> BoxedUint {
128 let mut ret = a.clone();
129 self.mul_assign(&mut ret, b);
130 ret
131 }
132
133 pub(super) fn mul_assign(&mut self, a: &mut BoxedUint, b: &BoxedUint) {
135 debug_assert_eq!(a.bits_precision(), self.modulus.bits_precision());
136 debug_assert_eq!(b.bits_precision(), self.modulus.bits_precision());
137
138 mul_limbs(&a.limbs, &b.limbs, &mut self.product.limbs);
139 montgomery_reduction_boxed_mut(&mut self.product, self.modulus, self.mod_neg_inv, a);
140
141 debug_assert!(&*a < self.modulus);
142 }
143
144 pub(super) fn square(&mut self, a: &BoxedUint) -> BoxedUint {
146 let mut ret = a.clone();
147 self.square_assign(&mut ret);
148 ret
149 }
150
151 pub(super) fn square_assign(&mut self, a: &mut BoxedUint) {
153 debug_assert_eq!(a.bits_precision(), self.modulus.bits_precision());
154
155 mul_limbs(&a.limbs, &a.limbs, &mut self.product.limbs);
157 montgomery_reduction_boxed_mut(&mut self.product, self.modulus, self.mod_neg_inv, a);
158
159 debug_assert!(&*a < self.modulus);
160 }
161
162 pub(super) fn mul_amm(&mut self, a: &BoxedUint, b: &BoxedUint) -> BoxedUint {
168 let mut ret = a.clone();
169 self.mul_amm_assign(&mut ret, b);
170 ret
171 }
172
173 pub(super) fn mul_amm_assign(&mut self, a: &mut BoxedUint, b: &BoxedUint) {
179 debug_assert_eq!(a.bits_precision(), self.modulus.bits_precision());
180 debug_assert_eq!(b.bits_precision(), self.modulus.bits_precision());
181
182 self.clear_product();
183 almost_montgomery_mul(
184 self.product.as_limbs_mut(),
185 a.as_limbs(),
186 b.as_limbs(),
187 self.modulus.as_limbs(),
188 self.mod_neg_inv,
189 );
190 a.limbs
191 .copy_from_slice(&self.product.limbs[..a.limbs.len()]);
192 }
193
194 #[allow(dead_code)] pub(super) fn square_amm(&mut self, a: &BoxedUint) -> BoxedUint {
201 let mut ret = a.clone();
202 self.square_amm_assign(&mut ret);
203 ret
204 }
205
206 pub(super) fn square_amm_assign(&mut self, a: &mut BoxedUint) {
212 debug_assert_eq!(a.bits_precision(), self.modulus.bits_precision());
213
214 self.clear_product();
215 almost_montgomery_mul(
216 self.product.as_limbs_mut(),
217 a.as_limbs(),
218 a.as_limbs(),
219 self.modulus.as_limbs(),
220 self.mod_neg_inv,
221 );
222 a.limbs
223 .copy_from_slice(&self.product.limbs[..a.limbs.len()]);
224 }
225
226 fn clear_product(&mut self) {
228 self.product
229 .limbs
230 .iter_mut()
231 .for_each(|limb| *limb = Limb::ZERO);
232 }
233}
234
235#[cfg(feature = "zeroize")]
236impl Drop for MontyMultiplier<'_> {
237 fn drop(&mut self) {
238 self.product.zeroize();
239 }
240}
241
242fn almost_montgomery_mul(z: &mut [Limb], x: &[Limb], y: &[Limb], m: &[Limb], k: Limb) {
256 let n = m.len();
260
261 let pre_cond = z.len() > n && z[n..].len() == n && x.len() == n && y.len() == n && m.len() == n;
265 if !pre_cond {
266 panic!("Failed preconditions in montgomery_mul");
267 }
268
269 let mut c = Limb::ZERO;
270
271 for i in 0..n {
272 let c2 = add_mul_vvw(&mut z[i..n + i], x, y[i]);
273 let t = z[i].wrapping_mul(k);
274 let c3 = add_mul_vvw(&mut z[i..n + i], m, t);
275 let cx = c.wrapping_add(c2);
276 let cy = cx.wrapping_add(c3);
277 z[n + i] = cy;
278 c = Limb((cx.ct_lt(&c2) | cy.ct_lt(&c3)).unwrap_u8() as Word);
279 }
280
281 let (lower, upper) = z.split_at_mut(n);
282 sub_vv(lower, upper, m);
283
284 let is_zero = c.is_zero();
285 for (a, b) in lower.iter_mut().zip(upper.iter()) {
286 a.conditional_assign(b, is_zero);
287 }
288}
289
290#[inline]
291fn add_mul_vvw(z: &mut [Limb], x: &[Limb], y: Limb) -> Limb {
292 let mut c = Limb::ZERO;
293 for (zi, xi) in z.iter_mut().zip(x.iter()) {
294 let (z0, z1) = zi.mac(*xi, y, Limb::ZERO);
295 let (zi_, c_) = z0.overflowing_add(c);
296 *zi = zi_;
297 c = c_.wrapping_add(z1);
298 }
299
300 c
301}
302
303#[inline(always)]
304fn sub_vv(z: &mut [Limb], x: &[Limb], y: &[Limb]) {
305 let mut borrow = Limb::ZERO;
306 for (i, (&xi, &yi)) in x.iter().zip(y.iter()).enumerate().take(z.len()) {
307 let (zi, new_borrow) = xi.sbb(yi, borrow);
308 z[i] = zi;
309 borrow = new_borrow;
310 }
311}
312
313#[cfg(test)]
314mod tests {
315 use super::{BoxedMontyForm, BoxedMontyParams, BoxedUint};
316
317 #[test]
319 fn square() {
320 let x = 0x20u128;
321 let modulus = 0xB44677037A7DBDE04814256570DCBD8Du128;
322
323 let boxed_modulus = BoxedUint::from(modulus);
324 let boxed_params = BoxedMontyParams::new(boxed_modulus.to_odd().unwrap());
325 let boxed_monty = BoxedMontyForm::new(BoxedUint::from(x), boxed_params);
326 let boxed_square = boxed_monty.square();
327
328 assert!(boxed_square.as_montgomery() < boxed_square.params().modulus());
330 }
331}