Coverage Report

Created: 2026-07-10 07:13

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/registry/src/index.crates.io-1949cf8c6b5b557f/crypto-bigint-0.5.5/src/limb/mul.rs
Line
Count
Source
1
//! Limb multiplication
2
3
use crate::{Checked, CheckedMul, Limb, WideWord, Word, Wrapping, Zero};
4
use core::ops::{Mul, MulAssign};
5
use subtle::CtOption;
6
7
impl Limb {
8
    /// Computes `self + (b * c) + carry`, returning the result along with the new carry.
9
    #[inline(always)]
10
25.0M
    pub const fn mac(self, b: Limb, c: Limb, carry: Limb) -> (Limb, Limb) {
11
25.0M
        let a = self.0 as WideWord;
12
25.0M
        let b = b.0 as WideWord;
13
25.0M
        let c = c.0 as WideWord;
14
25.0M
        let carry = carry.0 as WideWord;
15
25.0M
        let ret = a + (b * c) + carry;
16
25.0M
        (Limb(ret as Word), Limb((ret >> Self::BITS) as Word))
17
25.0M
    }
18
19
    /// Perform saturating multiplication.
20
    #[inline]
21
0
    pub const fn saturating_mul(&self, rhs: Self) -> Self {
22
0
        Limb(self.0.saturating_mul(rhs.0))
23
0
    }
24
25
    /// Perform wrapping multiplication, discarding overflow.
26
    #[inline(always)]
27
0
    pub const fn wrapping_mul(&self, rhs: Self) -> Self {
28
0
        Limb(self.0.wrapping_mul(rhs.0))
29
0
    }
30
31
    /// Compute "wide" multiplication, with a product twice the size of the input.
32
0
    pub(crate) const fn mul_wide(&self, rhs: Self) -> WideWord {
33
0
        (self.0 as WideWord) * (rhs.0 as WideWord)
34
0
    }
35
}
36
37
impl CheckedMul for Limb {
38
    type Output = Self;
39
40
    #[inline]
41
0
    fn checked_mul(&self, rhs: Self) -> CtOption<Self> {
42
0
        let result = self.mul_wide(rhs);
43
0
        let overflow = Limb((result >> Self::BITS) as Word);
44
0
        CtOption::new(Limb(result as Word), overflow.is_zero())
45
0
    }
46
}
47
48
impl Mul for Wrapping<Limb> {
49
    type Output = Self;
50
51
0
    fn mul(self, rhs: Self) -> Wrapping<Limb> {
52
0
        Wrapping(self.0.wrapping_mul(rhs.0))
53
0
    }
54
}
55
56
impl Mul<&Wrapping<Limb>> for Wrapping<Limb> {
57
    type Output = Wrapping<Limb>;
58
59
0
    fn mul(self, rhs: &Wrapping<Limb>) -> Wrapping<Limb> {
60
0
        Wrapping(self.0.wrapping_mul(rhs.0))
61
0
    }
62
}
63
64
impl Mul<Wrapping<Limb>> for &Wrapping<Limb> {
65
    type Output = Wrapping<Limb>;
66
67
0
    fn mul(self, rhs: Wrapping<Limb>) -> Wrapping<Limb> {
68
0
        Wrapping(self.0.wrapping_mul(rhs.0))
69
0
    }
70
}
71
72
impl Mul<&Wrapping<Limb>> for &Wrapping<Limb> {
73
    type Output = Wrapping<Limb>;
74
75
0
    fn mul(self, rhs: &Wrapping<Limb>) -> Wrapping<Limb> {
76
0
        Wrapping(self.0.wrapping_mul(rhs.0))
77
0
    }
78
}
79
80
impl MulAssign for Wrapping<Limb> {
81
0
    fn mul_assign(&mut self, other: Self) {
82
0
        *self = *self * other;
83
0
    }
84
}
85
86
impl MulAssign<&Wrapping<Limb>> for Wrapping<Limb> {
87
0
    fn mul_assign(&mut self, other: &Self) {
88
0
        *self = *self * other;
89
0
    }
90
}
91
92
impl Mul for Checked<Limb> {
93
    type Output = Self;
94
95
0
    fn mul(self, rhs: Self) -> Checked<Limb> {
96
        Checked(
97
0
            self.0
98
0
                .and_then(|lhs| rhs.0.and_then(|rhs| lhs.checked_mul(rhs))),
99
        )
100
0
    }
101
}
102
103
impl Mul<&Checked<Limb>> for Checked<Limb> {
104
    type Output = Checked<Limb>;
105
106
0
    fn mul(self, rhs: &Checked<Limb>) -> Checked<Limb> {
107
        Checked(
108
0
            self.0
109
0
                .and_then(|lhs| rhs.0.and_then(|rhs| lhs.checked_mul(rhs))),
110
        )
111
0
    }
112
}
113
114
impl Mul<Checked<Limb>> for &Checked<Limb> {
115
    type Output = Checked<Limb>;
116
117
0
    fn mul(self, rhs: Checked<Limb>) -> Checked<Limb> {
118
        Checked(
119
0
            self.0
120
0
                .and_then(|lhs| rhs.0.and_then(|rhs| lhs.checked_mul(rhs))),
121
        )
122
0
    }
123
}
124
125
impl Mul<&Checked<Limb>> for &Checked<Limb> {
126
    type Output = Checked<Limb>;
127
128
0
    fn mul(self, rhs: &Checked<Limb>) -> Checked<Limb> {
129
        Checked(
130
0
            self.0
131
0
                .and_then(|lhs| rhs.0.and_then(|rhs| lhs.checked_mul(rhs))),
132
        )
133
0
    }
134
}
135
136
impl MulAssign for Checked<Limb> {
137
0
    fn mul_assign(&mut self, other: Self) {
138
0
        *self = *self * other;
139
0
    }
140
}
141
142
impl MulAssign<&Checked<Limb>> for Checked<Limb> {
143
0
    fn mul_assign(&mut self, other: &Self) {
144
0
        *self = *self * other;
145
0
    }
146
}
147
148
#[cfg(test)]
149
mod tests {
150
    use super::{CheckedMul, Limb, WideWord};
151
152
    #[test]
153
    fn mul_wide_zero_and_one() {
154
        assert_eq!(Limb::ZERO.mul_wide(Limb::ZERO), 0);
155
        assert_eq!(Limb::ZERO.mul_wide(Limb::ONE), 0);
156
        assert_eq!(Limb::ONE.mul_wide(Limb::ZERO), 0);
157
        assert_eq!(Limb::ONE.mul_wide(Limb::ONE), 1);
158
    }
159
160
    #[test]
161
    fn mul_wide() {
162
        let primes: &[u32] = &[3, 5, 17, 257, 65537];
163
164
        for &a_int in primes {
165
            for &b_int in primes {
166
                let actual = Limb::from_u32(a_int).mul_wide(Limb::from_u32(b_int));
167
                let expected = a_int as WideWord * b_int as WideWord;
168
                assert_eq!(actual, expected);
169
            }
170
        }
171
    }
172
173
    #[test]
174
    #[cfg(target_pointer_width = "32")]
175
    fn checked_mul_ok() {
176
        let n = Limb::from_u16(0xffff);
177
        assert_eq!(n.checked_mul(n).unwrap(), Limb::from_u32(0xfffe_0001));
178
    }
179
180
    #[test]
181
    #[cfg(target_pointer_width = "64")]
182
    fn checked_mul_ok() {
183
        let n = Limb::from_u32(0xffff_ffff);
184
        assert_eq!(
185
            n.checked_mul(n).unwrap(),
186
            Limb::from_u64(0xffff_fffe_0000_0001)
187
        );
188
    }
189
190
    #[test]
191
    fn checked_mul_overflow() {
192
        let n = Limb::MAX;
193
        assert!(bool::from(n.checked_mul(n).is_none()));
194
    }
195
}