crypto_bigint/limb/
mul.rs

1//! Limb multiplication
2
3use crate::{
4    primitives::{mac, mul_wide},
5    Checked, CheckedMul, Limb, Wrapping, Zero,
6};
7use core::ops::{Mul, MulAssign};
8use num_traits::WrappingMul;
9use subtle::CtOption;
10
11impl Limb {
12    /// Computes `self + (b * c) + carry`, returning the result along with the new carry.
13    #[inline(always)]
14    pub const fn mac(self, b: Limb, c: Limb, carry: Limb) -> (Limb, Limb) {
15        let (res, carry) = mac(self.0, b.0, c.0, carry.0);
16        (Limb(res), Limb(carry))
17    }
18
19    /// Perform saturating multiplication.
20    #[inline(always)]
21    pub const fn saturating_mul(&self, rhs: Self) -> Self {
22        Limb(self.0.saturating_mul(rhs.0))
23    }
24
25    /// Perform wrapping multiplication, discarding overflow.
26    #[inline(always)]
27    pub const fn wrapping_mul(&self, rhs: Self) -> Self {
28        Limb(self.0.wrapping_mul(rhs.0))
29    }
30
31    /// Compute "wide" multiplication, with a product twice the size of the input.
32    pub(crate) const fn mul_wide(&self, rhs: Self) -> (Self, Self) {
33        let (lo, hi) = mul_wide(self.0, rhs.0);
34        (Limb(lo), Limb(hi))
35    }
36}
37
38impl CheckedMul for Limb {
39    #[inline]
40    fn checked_mul(&self, rhs: &Self) -> CtOption<Self> {
41        let (lo, hi) = self.mul_wide(*rhs);
42        CtOption::new(lo, hi.is_zero())
43    }
44}
45
46impl Mul<Limb> for Limb {
47    type Output = Limb;
48
49    #[inline]
50    fn mul(self, rhs: Limb) -> Self {
51        self.checked_mul(&rhs)
52            .expect("attempted to multiply with overflow")
53    }
54}
55
56impl Mul<&Limb> for Limb {
57    type Output = Limb;
58
59    #[inline]
60    fn mul(self, rhs: &Limb) -> Self {
61        self * *rhs
62    }
63}
64
65impl Mul<Limb> for &Limb {
66    type Output = Limb;
67
68    #[inline]
69    fn mul(self, rhs: Limb) -> Self::Output {
70        *self * rhs
71    }
72}
73
74impl Mul<&Limb> for &Limb {
75    type Output = Limb;
76
77    #[inline]
78    fn mul(self, rhs: &Limb) -> Self::Output {
79        *self * *rhs
80    }
81}
82
83impl MulAssign for Wrapping<Limb> {
84    #[inline]
85    fn mul_assign(&mut self, other: Self) {
86        *self = *self * other;
87    }
88}
89
90impl MulAssign<&Wrapping<Limb>> for Wrapping<Limb> {
91    #[inline]
92    fn mul_assign(&mut self, other: &Self) {
93        *self = *self * other;
94    }
95}
96
97impl MulAssign for Checked<Limb> {
98    #[inline]
99    fn mul_assign(&mut self, other: Self) {
100        *self = *self * other;
101    }
102}
103
104impl MulAssign<&Checked<Limb>> for Checked<Limb> {
105    #[inline]
106    fn mul_assign(&mut self, other: &Self) {
107        *self = *self * other;
108    }
109}
110
111impl WrappingMul for Limb {
112    #[inline]
113    fn wrapping_mul(&self, v: &Self) -> Self {
114        self.wrapping_mul(*v)
115    }
116}
117
118#[cfg(test)]
119mod tests {
120    use super::{CheckedMul, Limb};
121
122    #[test]
123    #[cfg(target_pointer_width = "32")]
124    fn checked_mul_ok() {
125        let n = Limb::from_u16(0xffff);
126        assert_eq!(n.checked_mul(&n).unwrap(), Limb::from_u32(0xfffe_0001));
127    }
128
129    #[test]
130    #[cfg(target_pointer_width = "64")]
131    fn checked_mul_ok() {
132        let n = Limb::from_u32(0xffff_ffff);
133        assert_eq!(
134            n.checked_mul(&n).unwrap(),
135            Limb::from_u64(0xffff_fffe_0000_0001)
136        );
137    }
138
139    #[test]
140    fn checked_mul_overflow() {
141        let n = Limb::MAX;
142        assert!(bool::from(n.checked_mul(&n).is_none()));
143    }
144}