Coverage Report

Created: 2026-11-12 06:16

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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::<_>