/rust/registry/src/index.crates.io-1949cf8c6b5b557f/crypto-bigint-0.7.10/src/modular/reduction.rs
Line | Count | Source |
1 | | //! Modular reduction implementation. |
2 | | |
3 | | use crate::{Limb, Odd, Uint}; |
4 | | |
5 | | /// Algorithm 14.32 in Handbook of Applied Cryptography <https://cacr.uwaterloo.ca/hac/about/chap14.pdf> |
6 | | #[inline(always)] |
7 | 0 | const fn montgomery_reduction_inner( |
8 | 0 | upper: &mut [Limb], |
9 | 0 | lower: &mut [Limb], |
10 | 0 | modulus: &[Limb], |
11 | 0 | mod_neg_inv: Limb, |
12 | 0 | ) -> Limb { |
13 | 0 | let nlimbs = modulus.len(); |
14 | 0 | debug_assert!(nlimbs == upper.len()); |
15 | 0 | debug_assert!(nlimbs == lower.len()); |
16 | | |
17 | 0 | let mut meta_carry = Limb::ZERO; |
18 | | let mut new_sum; |
19 | | |
20 | 0 | let mut i = 0; |
21 | 0 | while i < nlimbs { |
22 | 0 | let u = lower[i].wrapping_mul(mod_neg_inv); |
23 | | |
24 | 0 | let (_, mut carry) = u.carrying_mul_add(modulus[0], lower[i], Limb::ZERO); |
25 | | let mut new_limb; |
26 | | |
27 | 0 | let mut j = 1; |
28 | 0 | while j < (nlimbs - i) { |
29 | 0 | (new_limb, carry) = u.carrying_mul_add(modulus[j], lower[i + j], carry); |
30 | 0 | lower[i + j] = new_limb; |
31 | 0 | j += 1; |
32 | 0 | } |
33 | 0 | while j < nlimbs { |
34 | 0 | (new_limb, carry) = u.carrying_mul_add(modulus[j], upper[i + j - nlimbs], carry); |
35 | 0 | upper[i + j - nlimbs] = new_limb; |
36 | 0 | j += 1; |
37 | 0 | } |
38 | | |
39 | 0 | (new_sum, meta_carry) = upper[i].carrying_add(carry, meta_carry); |
40 | 0 | upper[i] = new_sum; |
41 | | |
42 | 0 | i += 1; |
43 | | } |
44 | | |
45 | 0 | meta_carry |
46 | 0 | } |
47 | | |
48 | | /// Algorithm 14.32 in Handbook of Applied Cryptography <https://cacr.uwaterloo.ca/hac/about/chap14.pdf> |
49 | 0 | pub(crate) const fn montgomery_reduction<const LIMBS: usize>( |
50 | 0 | lower_upper: &(Uint<LIMBS>, Uint<LIMBS>), |
51 | 0 | modulus: &Odd<Uint<LIMBS>>, |
52 | 0 | mod_neg_inv: Limb, |
53 | 0 | ) -> Uint<LIMBS> { |
54 | 0 | let (mut lower, mut upper) = *lower_upper; |
55 | 0 | let meta_carry = montgomery_reduction_inner( |
56 | 0 | &mut upper.limbs, |
57 | 0 | &mut lower.limbs, |
58 | 0 | &modulus.as_ref().limbs, |
59 | 0 | mod_neg_inv, |
60 | | ); |
61 | | |
62 | | // Division is simply taking the upper half of the limbs |
63 | | // Final reduction (at this point, the value is at most 2 * modulus, |
64 | | // so `meta_carry` is either 0 or 1) |
65 | 0 | upper.try_sub_with_carry(meta_carry, modulus.as_ref()).0 |
66 | 0 | } Unexecuted instantiation: crypto_bigint::modular::reduction::montgomery_reduction::<4> Unexecuted instantiation: crypto_bigint::modular::reduction::montgomery_reduction::<_> |
67 | | |
68 | | /// This algorithm corresponds to a Montgomery reduction of the wide input `(x, 0)`, |
69 | | /// Algorithm 14.32 in Handbook of Applied Cryptography <https://cacr.uwaterloo.ca/hac/about/chap14.pdf> |
70 | | /// Or to a Montgomery multiplication of `x` by `1` (Algorithm 14.36). |
71 | | /// This version does not produce a carry and does not need further correction by |
72 | | /// subtracting the modulus as long as `x < modulus`. This is guaranteed because |
73 | | /// `x < modulus => u < modulus => ((x + u•modulus) << N) < modulus`. |
74 | | #[inline(always)] |
75 | 13.3k | pub const fn montgomery_retrieve_inner( |
76 | 13.3k | x: &[Limb], |
77 | 13.3k | out: &mut [Limb], |
78 | 13.3k | modulus: &[Limb], |
79 | 13.3k | mod_neg_inv: Limb, |
80 | 13.3k | ) { |
81 | 13.3k | let nlimbs = modulus.len(); |
82 | 13.3k | assert!(nlimbs == x.len() && nlimbs == out.len()); |
83 | | |
84 | 13.3k | let mut i = 0; |
85 | 66.5k | while i < nlimbs { |
86 | 53.2k | let xi = x[i]; |
87 | 53.2k | let u = out[0].wrapping_add(xi).wrapping_mul(mod_neg_inv); |
88 | | |
89 | 53.2k | out[0] = u.carrying_mul_add(modulus[0], xi, out[0]).1; |
90 | | |
91 | 53.2k | let mut j = 1; |
92 | 212k | while j < nlimbs { |
93 | 159k | (out[j - 1], out[j]) = u.carrying_mul_add(modulus[j], out[j], out[j - 1]); |
94 | 159k | j += 1; |
95 | 159k | } |
96 | | |
97 | 53.2k | i += 1; |
98 | | } |
99 | 13.3k | } |
100 | | |
101 | | /// For input `x < modulus` in Montgomery form, compute `x•R^-1 mod modulus`. |
102 | 13.3k | pub const fn montgomery_retrieve<const LIMBS: usize>( |
103 | 13.3k | montgomery_form: &Uint<LIMBS>, |
104 | 13.3k | modulus: &Odd<Uint<LIMBS>>, |
105 | 13.3k | mod_neg_inv: Limb, |
106 | 13.3k | ) -> Uint<LIMBS> { |
107 | 13.3k | debug_assert!(Uint::lt(montgomery_form, modulus.as_ref()).to_bool()); |
108 | 13.3k | let mut res = Uint::ZERO; |
109 | 13.3k | montgomery_retrieve_inner( |
110 | 13.3k | montgomery_form.as_limbs(), |
111 | 13.3k | res.as_mut_limbs(), |
112 | 13.3k | modulus.as_ref().as_limbs(), |
113 | 13.3k | mod_neg_inv, |
114 | | ); |
115 | 13.3k | res |
116 | 13.3k | } crypto_bigint::modular::reduction::montgomery_retrieve::<4> Line | Count | Source | 102 | 13.3k | pub const fn montgomery_retrieve<const LIMBS: usize>( | 103 | 13.3k | montgomery_form: &Uint<LIMBS>, | 104 | 13.3k | modulus: &Odd<Uint<LIMBS>>, | 105 | 13.3k | mod_neg_inv: Limb, | 106 | 13.3k | ) -> Uint<LIMBS> { | 107 | 13.3k | debug_assert!(Uint::lt(montgomery_form, modulus.as_ref()).to_bool()); | 108 | 13.3k | let mut res = Uint::ZERO; | 109 | 13.3k | montgomery_retrieve_inner( | 110 | 13.3k | montgomery_form.as_limbs(), | 111 | 13.3k | res.as_mut_limbs(), | 112 | 13.3k | modulus.as_ref().as_limbs(), | 113 | 13.3k | mod_neg_inv, | 114 | | ); | 115 | 13.3k | res | 116 | 13.3k | } |
Unexecuted instantiation: crypto_bigint::modular::reduction::montgomery_retrieve::<_> |