crypto_bigint/limb/
mul.rs1use crate::{
4 Checked, CheckedMul, CtOption, Limb, Mul, MulAssign, MulMod, NonZero, SquareMod, UintRef,
5 Wrapping, WrappingMul,
6 primitives::{carrying_mul_add, widening_mul},
7};
8
9impl Limb {
10 #[deprecated(
12 since = "0.7.0",
13 note = "please use `carrying_mul_add` instead (ordering of arguments changes)"
14 )]
15 #[must_use]
16 pub const fn mac(self, b: Limb, c: Limb, carry: Limb) -> (Limb, Limb) {
17 b.carrying_mul_add(c, self, carry)
18 }
19
20 #[inline(always)]
22 #[must_use]
23 pub const fn carrying_mul_add(self, rhs: Limb, addend: Limb, carry: Limb) -> (Limb, Limb) {
24 let (res, carry) = carrying_mul_add(self.0, rhs.0, addend.0, carry.0);
25 (Limb(res), Limb(carry))
26 }
27
28 #[inline(always)]
30 #[must_use]
31 pub const fn saturating_mul(self, rhs: Self) -> Self {
32 Limb(self.0.saturating_mul(rhs.0))
33 }
34
35 #[inline(always)]
37 #[must_use]
38 pub const fn wrapping_mul(self, rhs: Self) -> Self {
39 Limb(self.0.wrapping_mul(rhs.0))
40 }
41
42 pub(crate) const fn widening_mul(self, rhs: Self) -> (Self, Self) {
44 let (lo, hi) = widening_mul(self.0, rhs.0);
45 (Limb(lo), Limb(hi))
46 }
47
48 pub(crate) const fn widening_square(self) -> (Self, Self) {
50 let (lo, hi) = widening_mul(self.0, self.0);
51 (Limb(lo), Limb(hi))
52 }
53
54 pub(crate) const fn rem_wide(lo_hi: (Self, Self), p: NonZero<Self>) -> Self {
56 UintRef::new_mut(&mut [lo_hi.0, lo_hi.1]).div_rem_limb(p)
57 }
58}
59
60impl CheckedMul for Limb {
61 #[inline]
62 fn checked_mul(&self, rhs: &Self) -> CtOption<Self> {
63 let (lo, hi) = self.widening_mul(*rhs);
64 CtOption::new(lo, hi.is_zero())
65 }
66}
67
68impl Mul<Limb> for Limb {
69 type Output = Limb;
70
71 #[inline]
72 fn mul(self, rhs: Limb) -> Self {
73 self.checked_mul(&rhs)
74 .expect("attempted to multiply with overflow")
75 }
76}
77
78impl Mul<&Limb> for Limb {
79 type Output = Limb;
80
81 #[inline]
82 fn mul(self, rhs: &Limb) -> Self {
83 self * *rhs
84 }
85}
86
87impl Mul<Limb> for &Limb {
88 type Output = Limb;
89
90 #[inline]
91 fn mul(self, rhs: Limb) -> Self::Output {
92 *self * rhs
93 }
94}
95
96impl Mul<&Limb> for &Limb {
97 type Output = Limb;
98
99 #[inline]
100 fn mul(self, rhs: &Limb) -> Self::Output {
101 *self * *rhs
102 }
103}
104
105impl MulAssign for Limb {
106 #[inline]
107 fn mul_assign(&mut self, other: Self) {
108 *self = *self * other;
109 }
110}
111
112impl MulAssign<&Limb> for Limb {
113 #[inline]
114 fn mul_assign(&mut self, other: &Self) {
115 *self = *self * *other;
116 }
117}
118
119impl MulAssign for Wrapping<Limb> {
120 #[inline]
121 fn mul_assign(&mut self, other: Self) {
122 *self = *self * other;
123 }
124}
125
126impl MulAssign<&Wrapping<Limb>> for Wrapping<Limb> {
127 #[inline]
128 fn mul_assign(&mut self, other: &Self) {
129 *self = *self * other;
130 }
131}
132
133impl MulAssign for Checked<Limb> {
134 #[inline]
135 fn mul_assign(&mut self, other: Self) {
136 *self = *self * other;
137 }
138}
139
140impl MulAssign<&Checked<Limb>> for Checked<Limb> {
141 #[inline]
142 fn mul_assign(&mut self, other: &Self) {
143 *self = *self * other;
144 }
145}
146
147impl WrappingMul for Limb {
148 #[inline]
149 fn wrapping_mul(&self, v: &Self) -> Self {
150 Self::wrapping_mul(*self, *v)
151 }
152}
153
154impl MulMod for Limb {
155 type Output = Self;
156
157 fn mul_mod(&self, rhs: &Self, p: &NonZero<Self>) -> Self::Output {
158 let lo_hi = self.widening_mul(*rhs);
159 Self::rem_wide(lo_hi, *p)
160 }
161}
162
163impl SquareMod for Limb {
164 type Output = Self;
165
166 fn square_mod(&self, p: &NonZero<Self>) -> Self::Output {
167 let lo_hi = self.widening_square();
168 Self::rem_wide(lo_hi, *p)
169 }
170}
171
172#[cfg(test)]
173mod tests {
174 use super::{CheckedMul, Limb};
175
176 cpubits::cpubits! {
177 32 => {
178 #[test]
179 fn checked_mul_ok() {
180 let n = Limb::from_u16(0xffff);
181 assert_eq!(n.checked_mul(&n).unwrap(), Limb::from_u32(0xfffe_0001));
182 }
183 }
184 64 => {
185 #[test]
186 fn checked_mul_ok() {
187 let n = Limb::from_u32(0xffff_ffff);
188 assert_eq!(
189 n.checked_mul(&n).unwrap(),
190 Limb::from_u64(0xffff_fffe_0000_0001)
191 );
192 }
193 }
194 }
195
196 #[test]
197 fn checked_mul_overflow() {
198 let n = Limb::MAX;
199 assert!(bool::from(n.checked_mul(&n).is_none()));
200 }
201}