Coverage Report

Created: 2026-09-06 07:25

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/registry/src/index.crates.io-1949cf8c6b5b557f/num-bigint-0.2.6/src/monty.rs
Line
Count
Source
1
use integer::Integer;
2
use traits::Zero;
3
4
use biguint::BigUint;
5
6
struct MontyReducer<'a> {
7
    n: &'a BigUint,
8
    n0inv: u32,
9
}
10
11
// Calculate the modular inverse of `num`, using Extended GCD.
12
//
13
// Reference:
14
// Brent & Zimmermann, Modern Computer Arithmetic, v0.5.9, Algorithm 1.20
15
0
fn inv_mod_u32(num: u32) -> u32 {
16
    // num needs to be relatively prime to 2**32 -- i.e. it must be odd.
17
0
    assert!(num % 2 != 0);
18
19
0
    let mut a: i64 = i64::from(num);
20
0
    let mut b: i64 = i64::from(u32::max_value()) + 1;
21
22
    // ExtendedGcd
23
    // Input: positive integers a and b
24
    // Output: integers (g, u, v) such that g = gcd(a, b) = ua + vb
25
    // As we don't need v for modular inverse, we don't calculate it.
26
27
    // 1: (u, w) <- (1, 0)
28
0
    let mut u = 1;
29
0
    let mut w = 0;
30
    // 3: while b != 0
31
0
    while b != 0 {
32
0
        // 4: (q, r) <- DivRem(a, b)
33
0
        let q = a / b;
34
0
        let r = a % b;
35
0
        // 5: (a, b) <- (b, r)
36
0
        a = b;
37
0
        b = r;
38
0
        // 6: (u, w) <- (w, u - qw)
39
0
        let m = u - w * q;
40
0
        u = w;
41
0
        w = m;
42
0
    }
43
44
0
    assert!(a == 1);
45
    // Downcasting acts like a mod 2^32 too.
46
0
    u as u32
47
0
}
Unexecuted instantiation: num_bigint::biguint::monty::inv_mod_u32
Unexecuted instantiation: num_bigint::biguint::monty::inv_mod_u32
48
49
impl<'a> MontyReducer<'a> {
50
0
    fn new(n: &'a BigUint) -> Self {
51
0
        let n0inv = inv_mod_u32(n.data[0]);
52
0
        MontyReducer { n: n, n0inv: n0inv }
53
0
    }
Unexecuted instantiation: <num_bigint::biguint::monty::MontyReducer>::new
Unexecuted instantiation: <num_bigint::biguint::monty::MontyReducer>::new
54
}
55
56
// Montgomery Reduction
57
//
58
// Reference:
59
// Brent & Zimmermann, Modern Computer Arithmetic, v0.5.9, Algorithm 2.6
60
0
fn monty_redc(a: BigUint, mr: &MontyReducer) -> BigUint {
61
0
    let mut c = a.data;
62
0
    let n = &mr.n.data;
63
0
    let n_size = n.len();
64
65
    // Allocate sufficient work space
66
0
    c.resize(2 * n_size + 2, 0);
67
68
    // β is the size of a word, in this case 32 bits. So "a mod β" is
69
    // equivalent to masking a to 32 bits.
70
    // mu <- -N^(-1) mod β
71
0
    let mu = 0u32.wrapping_sub(mr.n0inv);
72
73
    // 1: for i = 0 to (n-1)
74
0
    for i in 0..n_size {
75
0
        // 2: q_i <- mu*c_i mod β
76
0
        let q_i = c[i].wrapping_mul(mu);
77
0
78
0
        // 3: C <- C + q_i * N * β^i
79
0
        super::algorithms::mac_digit(&mut c[i..], n, q_i);
80
0
    }
81
82
    // 4: R <- C * β^(-n)
83
    // This is an n-word bitshift, equivalent to skipping n words.
84
0
    let ret = BigUint::new(c[n_size..].to_vec());
85
86
    // 5: if R >= β^n then return R-N else return R.
87
0
    if ret < *mr.n {
88
0
        ret
89
    } else {
90
0
        ret - mr.n
91
    }
92
0
}
Unexecuted instantiation: num_bigint::biguint::monty::monty_redc
Unexecuted instantiation: num_bigint::biguint::monty::monty_redc
93
94
// Montgomery Multiplication
95
0
fn monty_mult(a: BigUint, b: &BigUint, mr: &MontyReducer) -> BigUint {
96
0
    monty_redc(a * b, mr)
97
0
}
Unexecuted instantiation: num_bigint::biguint::monty::monty_mult
Unexecuted instantiation: num_bigint::biguint::monty::monty_mult
98
99
// Montgomery Squaring
100
0
fn monty_sqr(a: BigUint, mr: &MontyReducer) -> BigUint {
101
    // TODO: Replace with an optimised squaring function
102
0
    monty_redc(&a * &a, mr)
103
0
}
Unexecuted instantiation: num_bigint::biguint::monty::monty_sqr
Unexecuted instantiation: num_bigint::biguint::monty::monty_sqr
104
105
0
pub fn monty_modpow(a: &BigUint, exp: &BigUint, modulus: &BigUint) -> BigUint {
106
0
    let mr = MontyReducer::new(modulus);
107
108
    // Calculate the Montgomery parameter
109
0
    let mut v = vec![0; modulus.data.len()];
110
0
    v.push(1);
111
0
    let r = BigUint::new(v);
112
113
    // Map the base to the Montgomery domain
114
0
    let mut apri = a * &r % modulus;
115
116
    // Binary exponentiation
117
0
    let mut ans = &r % modulus;
118
0
    let mut e = exp.clone();
119
0
    while !e.is_zero() {
120
0
        if e.is_odd() {
121
0
            ans = monty_mult(ans, &apri, &mr);
122
0
        }
123
0
        apri = monty_sqr(apri, &mr);
124
0
        e >>= 1;
125
    }
126
127
    // Map the result back to the residues domain
128
0
    monty_redc(ans, &mr)
129
0
}
Unexecuted instantiation: num_bigint::biguint::monty::monty_modpow
Unexecuted instantiation: num_bigint::biguint::monty::monty_modpow