crypto_bigint/modular/
boxed_monty_form.rs1mod add;
4mod inv;
5mod lincomb;
6mod mul;
7mod neg;
8mod pow;
9mod sub;
10
11use super::{
12 div_by_2,
13 reduction::{montgomery_reduction_boxed, montgomery_reduction_boxed_mut},
14 ConstMontyParams, Retrieve,
15};
16use crate::{BoxedUint, Limb, Monty, Odd, Word};
17use alloc::sync::Arc;
18use subtle::Choice;
19
20#[cfg(feature = "zeroize")]
21use zeroize::Zeroize;
22
23#[derive(Clone, Debug, Eq, PartialEq)]
26pub struct BoxedMontyParams {
27 modulus: Odd<BoxedUint>,
29 one: BoxedUint,
31 r2: BoxedUint,
33 r3: BoxedUint,
35 mod_neg_inv: Limb,
38 mod_leading_zeros: u32,
40}
41
42impl BoxedMontyParams {
43 pub fn new(modulus: Odd<BoxedUint>) -> Self {
49 let bits_precision = modulus.bits_precision();
50
51 let one = BoxedUint::max(bits_precision)
54 .rem(modulus.as_nz_ref())
55 .wrapping_add(&BoxedUint::one());
56
57 let r2 = one
59 .square()
60 .rem(&modulus.as_nz_ref().widen(bits_precision * 2))
61 .shorten(bits_precision);
62
63 Self::new_inner(modulus, one, r2)
64 }
65
66 pub fn new_vartime(modulus: Odd<BoxedUint>) -> Self {
72 let bits_precision = modulus.bits_precision();
73
74 let one = BoxedUint::max(bits_precision)
77 .rem_vartime(modulus.as_nz_ref())
78 .wrapping_add(&BoxedUint::one());
79
80 let r2 = one
82 .square()
83 .rem_vartime(&modulus.as_nz_ref().widen(bits_precision * 2))
84 .shorten(bits_precision);
85
86 Self::new_inner(modulus, one, r2)
87 }
88
89 fn new_inner(modulus: Odd<BoxedUint>, one: BoxedUint, r2: BoxedUint) -> Self {
91 debug_assert_eq!(one.bits_precision(), modulus.bits_precision());
92 debug_assert_eq!(r2.bits_precision(), modulus.bits_precision());
93
94 let (inv_mod_limb, modulus_is_odd) = modulus.inv_mod2k(Word::BITS);
96 debug_assert!(bool::from(modulus_is_odd));
97
98 let mod_neg_inv = Limb(Word::MIN.wrapping_sub(inv_mod_limb.limbs[0].0));
99
100 let mod_leading_zeros = modulus.as_ref().leading_zeros().min(Word::BITS - 1);
101
102 let r3 = montgomery_reduction_boxed(&mut r2.square(), &modulus, mod_neg_inv);
103
104 Self {
105 modulus,
106 one,
107 r2,
108 r3,
109 mod_neg_inv,
110 mod_leading_zeros,
111 }
112 }
113
114 pub fn modulus(&self) -> &Odd<BoxedUint> {
116 &self.modulus
117 }
118
119 pub fn bits_precision(&self) -> u32 {
121 self.modulus.bits_precision()
122 }
123
124 pub fn from_const_params<const LIMBS: usize, P: ConstMontyParams<LIMBS>>() -> Self {
126 Self {
127 modulus: P::MODULUS.into(),
128 one: P::ONE.into(),
129 r2: P::R2.into(),
130 r3: P::R3.into(),
131 mod_neg_inv: P::MOD_NEG_INV,
132 mod_leading_zeros: P::MOD_LEADING_ZEROS,
133 }
134 }
135}
136
137#[derive(Clone, Debug, Eq, PartialEq)]
139pub struct BoxedMontyForm {
140 montgomery_form: BoxedUint,
142
143 params: Arc<BoxedMontyParams>,
145}
146
147impl BoxedMontyForm {
148 pub fn new(mut integer: BoxedUint, params: BoxedMontyParams) -> Self {
150 debug_assert_eq!(integer.bits_precision(), params.bits_precision());
151 convert_to_montgomery(&mut integer, ¶ms);
152
153 #[allow(clippy::useless_conversion)]
154 Self {
155 montgomery_form: integer,
156 params: params.into(),
157 }
158 }
159
160 pub fn new_with_arc(mut integer: BoxedUint, params: Arc<BoxedMontyParams>) -> Self {
162 debug_assert_eq!(integer.bits_precision(), params.bits_precision());
163 convert_to_montgomery(&mut integer, ¶ms);
164 Self {
165 montgomery_form: integer,
166 params,
167 }
168 }
169
170 pub fn bits_precision(&self) -> u32 {
172 self.params.bits_precision()
173 }
174
175 pub fn retrieve(&self) -> BoxedUint {
177 let mut montgomery_form = self.montgomery_form.widen(self.bits_precision() * 2);
178
179 let ret = montgomery_reduction_boxed(
180 &mut montgomery_form,
181 &self.params.modulus,
182 self.params.mod_neg_inv,
183 );
184
185 #[cfg(feature = "zeroize")]
186 montgomery_form.zeroize();
187
188 debug_assert!(ret < self.params.modulus);
189 ret
190 }
191
192 pub fn zero(params: BoxedMontyParams) -> Self {
194 Self {
195 montgomery_form: BoxedUint::zero_with_precision(params.bits_precision()),
196 params: params.into(),
197 }
198 }
199
200 pub fn one(params: BoxedMontyParams) -> Self {
202 Self {
203 montgomery_form: params.one.clone(),
204 params: params.into(),
205 }
206 }
207
208 pub fn is_zero(&self) -> Choice {
214 self.montgomery_form.is_zero()
215 }
216
217 #[inline]
223 pub fn is_nonzero(&self) -> Choice {
224 !self.is_zero()
225 }
226
227 pub fn params(&self) -> &BoxedMontyParams {
229 &self.params
230 }
231
232 pub fn as_montgomery(&self) -> &BoxedUint {
234 debug_assert!(self.montgomery_form < self.params.modulus);
235 &self.montgomery_form
236 }
237
238 pub fn from_montgomery(integer: BoxedUint, params: BoxedMontyParams) -> Self {
240 debug_assert_eq!(integer.bits_precision(), params.bits_precision());
241 Self {
242 montgomery_form: integer,
243 params: params.into(),
244 }
245 }
246
247 pub fn to_montgomery(&self) -> BoxedUint {
249 debug_assert!(self.montgomery_form < self.params.modulus);
250 self.montgomery_form.clone()
251 }
252
253 pub fn div_by_2(&self) -> Self {
255 Self {
256 montgomery_form: div_by_2::div_by_2_boxed(&self.montgomery_form, &self.params.modulus),
257 params: self.params.clone(),
258 }
259 }
260}
261
262impl Retrieve for BoxedMontyForm {
263 type Output = BoxedUint;
264 fn retrieve(&self) -> BoxedUint {
265 self.retrieve()
266 }
267}
268
269impl Monty for BoxedMontyForm {
270 type Integer = BoxedUint;
271 type Params = BoxedMontyParams;
272
273 fn new_params_vartime(modulus: Odd<Self::Integer>) -> Self::Params {
274 BoxedMontyParams::new_vartime(modulus)
275 }
276
277 fn new(value: Self::Integer, params: Self::Params) -> Self {
278 BoxedMontyForm::new(value, params)
279 }
280
281 fn zero(params: Self::Params) -> Self {
282 BoxedMontyForm::zero(params)
283 }
284
285 fn one(params: Self::Params) -> Self {
286 BoxedMontyForm::one(params)
287 }
288
289 fn params(&self) -> &Self::Params {
290 &self.params
291 }
292
293 fn as_montgomery(&self) -> &Self::Integer {
294 &self.montgomery_form
295 }
296
297 fn double(&self) -> Self {
298 BoxedMontyForm::double(self)
299 }
300
301 fn div_by_2(&self) -> Self {
302 BoxedMontyForm::div_by_2(self)
303 }
304
305 fn lincomb_vartime(products: &[(&Self, &Self)]) -> Self {
306 BoxedMontyForm::lincomb_vartime(products)
307 }
308}
309
310#[cfg(feature = "zeroize")]
312impl Zeroize for BoxedMontyForm {
313 fn zeroize(&mut self) {
314 self.montgomery_form.zeroize();
315 }
316}
317
318#[inline]
320fn convert_to_montgomery(integer: &mut BoxedUint, params: &BoxedMontyParams) {
321 let mut product = integer.mul(¶ms.r2);
322 montgomery_reduction_boxed_mut(&mut product, ¶ms.modulus, params.mod_neg_inv, integer);
323
324 #[cfg(feature = "zeroize")]
325 product.zeroize();
326}
327
328#[cfg(test)]
329mod tests {
330 use super::{BoxedMontyForm, BoxedMontyParams, BoxedUint, Limb, Odd};
331
332 #[test]
333 fn new_params_with_valid_modulus() {
334 let modulus = Odd::new(BoxedUint::from(3u8)).unwrap();
335 let params = BoxedMontyParams::new(modulus);
336
337 assert_eq!(params.mod_leading_zeros, Limb::BITS - 2);
338 }
339
340 #[test]
341 fn div_by_2() {
342 let modulus = Odd::new(BoxedUint::from(9u8)).unwrap();
343 let params = BoxedMontyParams::new(modulus);
344 let zero = BoxedMontyForm::zero(params.clone());
345 let one = BoxedMontyForm::one(params.clone());
346 let two = one.add(&one);
347
348 assert_eq!(zero.div_by_2(), zero);
349 assert_eq!(one.div_by_2().mul(&two), one);
350 }
351}