Skip to main content

crypto_bigint/modular/const_monty_form/
mul.rs

1//! Multiplications between integers in Montgomery form with a constant modulus.
2
3use core::{
4    marker::PhantomData,
5    ops::{Mul, MulAssign},
6};
7
8use crate::{
9    modular::mul::{mul_montgomery_form, square_montgomery_form, square_repeat_montgomery_form},
10    traits::Square,
11};
12
13use super::{ConstMontyForm, ConstMontyParams};
14
15impl<MOD: ConstMontyParams<LIMBS>, const LIMBS: usize> ConstMontyForm<MOD, LIMBS> {
16    /// Multiplies by `rhs`.
17    #[must_use]
18    pub const fn mul(&self, rhs: &Self) -> Self {
19        Self {
20            montgomery_form: mul_montgomery_form(
21                &self.montgomery_form,
22                &rhs.montgomery_form,
23                &MOD::PARAMS.modulus,
24                MOD::PARAMS.mod_neg_inv(),
25            ),
26            phantom: PhantomData,
27        }
28    }
29
30    /// Computes the (reduced) square.
31    #[must_use]
32    pub const fn square(&self) -> Self {
33        Self {
34            montgomery_form: square_montgomery_form(
35                &self.montgomery_form,
36                &MOD::PARAMS.modulus,
37                MOD::PARAMS.mod_neg_inv(),
38            ),
39            phantom: PhantomData,
40        }
41    }
42
43    /// Computes the reduced product `self^2n`.
44    ///
45    /// This method is variable time in `n` only.
46    #[must_use]
47    pub const fn square_repeat_vartime(&self, n: u32) -> Self {
48        Self {
49            montgomery_form: square_repeat_montgomery_form::<LIMBS>(
50                &self.montgomery_form,
51                n,
52                &MOD::PARAMS.modulus,
53                MOD::PARAMS.mod_neg_inv(),
54            ),
55            phantom: PhantomData,
56        }
57    }
58}
59
60impl<MOD: ConstMontyParams<LIMBS>, const LIMBS: usize> Mul<&ConstMontyForm<MOD, LIMBS>>
61    for &ConstMontyForm<MOD, LIMBS>
62{
63    type Output = ConstMontyForm<MOD, LIMBS>;
64    fn mul(self, rhs: &ConstMontyForm<MOD, LIMBS>) -> ConstMontyForm<MOD, LIMBS> {
65        self.mul(rhs)
66    }
67}
68
69impl<MOD: ConstMontyParams<LIMBS>, const LIMBS: usize> Mul<ConstMontyForm<MOD, LIMBS>>
70    for &ConstMontyForm<MOD, LIMBS>
71{
72    type Output = ConstMontyForm<MOD, LIMBS>;
73    #[allow(clippy::op_ref)]
74    fn mul(self, rhs: ConstMontyForm<MOD, LIMBS>) -> ConstMontyForm<MOD, LIMBS> {
75        self * &rhs
76    }
77}
78
79impl<MOD: ConstMontyParams<LIMBS>, const LIMBS: usize> Mul<&ConstMontyForm<MOD, LIMBS>>
80    for ConstMontyForm<MOD, LIMBS>
81{
82    type Output = ConstMontyForm<MOD, LIMBS>;
83    #[allow(clippy::op_ref)]
84    fn mul(self, rhs: &ConstMontyForm<MOD, LIMBS>) -> ConstMontyForm<MOD, LIMBS> {
85        &self * rhs
86    }
87}
88
89impl<MOD: ConstMontyParams<LIMBS>, const LIMBS: usize> Mul<ConstMontyForm<MOD, LIMBS>>
90    for ConstMontyForm<MOD, LIMBS>
91{
92    type Output = ConstMontyForm<MOD, LIMBS>;
93    fn mul(self, rhs: ConstMontyForm<MOD, LIMBS>) -> ConstMontyForm<MOD, LIMBS> {
94        &self * &rhs
95    }
96}
97
98impl<MOD: ConstMontyParams<LIMBS>, const LIMBS: usize> MulAssign<&Self>
99    for ConstMontyForm<MOD, LIMBS>
100{
101    fn mul_assign(&mut self, rhs: &ConstMontyForm<MOD, LIMBS>) {
102        *self = *self * rhs;
103    }
104}
105
106impl<MOD: ConstMontyParams<LIMBS>, const LIMBS: usize> MulAssign<Self>
107    for ConstMontyForm<MOD, LIMBS>
108{
109    fn mul_assign(&mut self, rhs: Self) {
110        *self *= &rhs;
111    }
112}
113
114impl<MOD: ConstMontyParams<LIMBS>, const LIMBS: usize> Square for ConstMontyForm<MOD, LIMBS> {
115    fn square(&self) -> Self {
116        ConstMontyForm::square(self)
117    }
118}
119
120#[cfg(test)]
121mod tests {
122    use crate::{
123        U256, const_monty_form, const_monty_params,
124        modular::const_monty_form::{ConstMontyForm, ConstMontyParams},
125    };
126
127    const_monty_params!(
128        Modulus,
129        U256,
130        "15477BCCEFE197328255BFA79A1217899016D927EF460F4FF404029D24FA4409"
131    );
132
133    const_monty_form!(Fe, Modulus);
134
135    const N: U256 =
136        U256::from_be_hex("14117F1273373C26C700D076B3F780074D03339F56DD0EFB60E7F58441FD3685");
137    const N_MOD: ConstMontyForm<Modulus, { U256::LIMBS }> = ConstMontyForm::new(&N);
138
139    #[test]
140    fn test_mul_zero() {
141        let res = N_MOD.mul(&Fe::ZERO);
142        let expected = U256::ZERO;
143        assert_eq!(res.retrieve(), expected);
144    }
145
146    #[test]
147    fn test_mul_one() {
148        let res = N_MOD.mul(&Fe::ONE);
149        assert_eq!(res.retrieve(), N);
150    }
151
152    #[test]
153    fn test_mul_eq_add() {
154        let res = N_MOD.mul(&Fe::new(&U256::from(2u8)));
155        assert_eq!(res, N_MOD.add(&N_MOD));
156    }
157
158    #[test]
159    fn test_square_eq_mul() {
160        let res = N_MOD.square();
161        let expected = N_MOD.mul(&N_MOD);
162        assert_eq!(res, expected);
163    }
164
165    #[test]
166    fn test_square_repeat() {
167        let res = N_MOD.square_repeat_vartime(0);
168        assert_eq!(res, N_MOD);
169
170        let res = N_MOD.square_repeat_vartime(1);
171        assert_eq!(res, N_MOD.square());
172
173        let res = N_MOD.square_repeat_vartime(5);
174        let expected = N_MOD.square().square().square().square().square();
175        assert_eq!(res, expected);
176    }
177}