Skip to main content

crypto_bigint/int/
mul_unsigned.rs

1use crate::{CheckedMul, Choice, Concat, CtOption, Int, Uint};
2use core::ops::Mul;
3
4impl<const LIMBS: usize> Int<LIMBS> {
5    /// Compute "wide" multiplication between an [`Int`] and [`Uint`] as 3-tuple `(lo, hi, negate)`.
6    /// The `(lo, hi)` components contain the _magnitude of the product_, with sizes
7    /// corresponding to the sizes of the operands; `negate` indicates whether the result should be
8    /// negated when converted from [`Uint`] to [`Int`].
9    ///
10    /// Note: even if `negate` is truthy, the magnitude might be zero!
11    #[deprecated(since = "0.7.0", note = "please use `widening_mul_unsigned` instead")]
12    #[must_use]
13    pub const fn split_mul_unsigned<const RHS_LIMBS: usize>(
14        &self,
15        rhs: &Uint<RHS_LIMBS>,
16    ) -> (Uint<{ LIMBS }>, Uint<{ RHS_LIMBS }>, Choice) {
17        self.widening_mul_unsigned(rhs)
18    }
19
20    /// Compute "wide" multiplication between an [`Int`] and [`Uint`] as 3-tuple `(lo, hi, negate)`.
21    /// The `(lo, hi)` components contain the _magnitude of the product_, with sizes
22    /// corresponding to the sizes of the operands; `negate` indicates whether the result should be
23    /// negated when converted from [`Uint`] to [`Int`].
24    ///
25    /// Note: even if `negate` is truthy, the magnitude might be zero!
26    #[must_use]
27    pub const fn widening_mul_unsigned<const RHS_LIMBS: usize>(
28        &self,
29        rhs: &Uint<RHS_LIMBS>,
30    ) -> (Uint<{ LIMBS }>, Uint<{ RHS_LIMBS }>, Choice) {
31        // Step 1. split self into its sign and magnitude.
32        let (lhs_abs, lhs_sgn) = self.abs_sign();
33
34        // Step 2. Multiply the magnitudes
35        let (lo, hi) = lhs_abs.widening_mul(rhs);
36
37        // Step 3. negate if and only if self has a negative sign.
38        (lo, hi, lhs_sgn)
39    }
40
41    /// Compute "wide" multiplication between an [`Int`] and [`Uint`] as 3-tuple `(lo, hi, negate)`.
42    /// The `(lo, hi)` components contain the _magnitude of the product_, with sizes
43    /// corresponding to the sizes of the operands, in reversed order; `negate` indicates whether
44    /// the result should be negated when converted from [`Uint`] to [`Int`].
45    ///
46    /// Note: even if `negate` is truthy, the magnitude might be zero!
47    #[deprecated(
48        since = "0.7.0",
49        note = "please use `Uint::widening_mul_signed` instead"
50    )]
51    #[must_use]
52    pub const fn split_mul_unsigned_right<const RHS_LIMBS: usize>(
53        &self,
54        rhs: &Uint<RHS_LIMBS>,
55    ) -> (Uint<{ RHS_LIMBS }>, Uint<{ LIMBS }>, Choice) {
56        rhs.widening_mul_signed(self)
57    }
58
59    /// Compute "wide" multiplication between an [`Int`] and [`Uint`] as 3-tuple `(lo, hi, negate)`.
60    /// The `(lo, hi)` components contain the _magnitude of the product_, with sizes
61    /// corresponding to the sizes of the operands, in reversed order; `negate` indicates whether
62    /// the result should be negated when converted from [`Uint`] to [`Int`].
63    ///
64    /// Note: even if `negate` is truthy, the magnitude might be zero!
65    #[deprecated(
66        since = "0.7.0",
67        note = "please use `Uint::widening_mul_signed` instead"
68    )]
69    #[must_use]
70    pub const fn widening_mul_unsigned_right<const RHS_LIMBS: usize>(
71        &self,
72        rhs: &Uint<RHS_LIMBS>,
73    ) -> (Uint<{ RHS_LIMBS }>, Uint<{ LIMBS }>, Choice) {
74        rhs.widening_mul_signed(self)
75    }
76
77    /// Multiply `self` by [`Uint`] `rhs`, returning a concatenated "wide" result.
78    #[must_use]
79    pub const fn concatenating_mul_unsigned<const RHS_LIMBS: usize, const WIDE_LIMBS: usize>(
80        &self,
81        rhs: &Uint<RHS_LIMBS>,
82    ) -> Int<WIDE_LIMBS>
83    where
84        Uint<LIMBS>: Concat<RHS_LIMBS, Output = Uint<WIDE_LIMBS>>,
85    {
86        let (lhs_abs, lhs_sign) = self.abs_sign();
87        let product_abs = lhs_abs.concatenating_mul(rhs);
88
89        // always fits
90        *product_abs.wrapping_neg_if(lhs_sign).as_int()
91    }
92
93    /// Checked multiplication of self with an [`Uint<RHS_LIMBS>`], where the result is to be stored
94    /// in an [`Int<RHS_LIMBS>`].
95    #[deprecated(since = "0.7.0", note = "please use `Uint::checked_mul(_int)` instead")]
96    #[must_use]
97    pub fn checked_mul_unsigned_right<const RHS_LIMBS: usize>(
98        &self,
99        rhs: &Uint<RHS_LIMBS>,
100    ) -> CtOption<Int<RHS_LIMBS>> {
101        rhs.checked_mul_signed(self)
102    }
103
104    /// Checked multiplication with a [`Uint`].
105    #[must_use]
106    pub fn checked_mul_unsigned<const RHS_LIMBS: usize>(
107        &self,
108        rhs: &Uint<RHS_LIMBS>,
109    ) -> CtOption<Int<LIMBS>> {
110        let (abs_lhs, lhs_sgn) = self.abs_sign();
111        Self::new_from_abs_opt_sign(abs_lhs.checked_mul(rhs), lhs_sgn)
112    }
113}
114
115impl<const LIMBS: usize, const RHS_LIMBS: usize> CheckedMul<Uint<RHS_LIMBS>> for Int<LIMBS> {
116    #[inline]
117    fn checked_mul(&self, rhs: &Uint<RHS_LIMBS>) -> CtOption<Self> {
118        self.checked_mul_unsigned(rhs)
119    }
120}
121
122impl<const LIMBS: usize, const RHS_LIMBS: usize> Mul<Uint<RHS_LIMBS>> for Int<LIMBS> {
123    type Output = Int<LIMBS>;
124
125    fn mul(self, rhs: Uint<RHS_LIMBS>) -> Self {
126        self.mul(&rhs)
127    }
128}
129
130impl<const LIMBS: usize, const RHS_LIMBS: usize> Mul<&Uint<RHS_LIMBS>> for Int<LIMBS> {
131    type Output = Int<LIMBS>;
132
133    fn mul(self, rhs: &Uint<RHS_LIMBS>) -> Self {
134        (&self).mul(rhs)
135    }
136}
137
138impl<const LIMBS: usize, const RHS_LIMBS: usize> Mul<Uint<RHS_LIMBS>> for &Int<LIMBS> {
139    type Output = Int<LIMBS>;
140
141    fn mul(self, rhs: Uint<RHS_LIMBS>) -> Self::Output {
142        self.mul(&rhs)
143    }
144}
145
146impl<const LIMBS: usize, const RHS_LIMBS: usize> Mul<&Uint<RHS_LIMBS>> for &Int<LIMBS> {
147    type Output = Int<LIMBS>;
148
149    fn mul(self, rhs: &Uint<RHS_LIMBS>) -> Self::Output {
150        self.checked_mul_unsigned(rhs)
151            .expect("attempted to multiply with overflow")
152    }
153}
154
155#[cfg(test)]
156mod tests {
157    use crate::{I128, I256, U128, U256};
158
159    #[test]
160    fn test_checked_mul_unsigned() {
161        // lhs = min
162
163        let result = I128::MIN.checked_mul_unsigned(&U128::ZERO);
164        assert_eq!(result.unwrap(), I128::ZERO);
165
166        let result = I128::MIN.checked_mul_unsigned(&U128::ONE);
167        assert_eq!(result.unwrap(), I128::MIN);
168
169        let result = I128::MIN.checked_mul_unsigned(&U128::MAX);
170        assert!(bool::from(result.is_none()));
171
172        // lhs = -1
173
174        let result = I128::MINUS_ONE.checked_mul_unsigned(&U128::ZERO);
175        assert_eq!(result.unwrap(), I128::ZERO);
176
177        let result = I128::MINUS_ONE.checked_mul_unsigned(&U128::ONE);
178        assert_eq!(result.unwrap(), I128::MINUS_ONE);
179
180        let result = I128::MINUS_ONE.checked_mul_unsigned(&U128::MAX);
181        assert!(bool::from(result.is_none()));
182
183        // lhs = 0
184
185        let result = I128::ZERO.checked_mul_unsigned(&U128::ZERO);
186        assert_eq!(result.unwrap(), I128::ZERO);
187
188        let result = I128::ZERO.checked_mul_unsigned(&U128::ONE);
189        assert_eq!(result.unwrap(), I128::ZERO);
190
191        let result = I128::ZERO.checked_mul_unsigned(&U128::MAX);
192        assert_eq!(result.unwrap(), I128::ZERO);
193
194        // lhs = 1
195
196        let result = I128::ONE.checked_mul_unsigned(&U128::ZERO);
197        assert_eq!(result.unwrap(), I128::ZERO);
198
199        let result = I128::ONE.checked_mul_unsigned(&U128::ONE);
200        assert_eq!(result.unwrap(), I128::ONE);
201
202        let result = I128::ONE.checked_mul_unsigned(&U128::MAX);
203        assert!(bool::from(result.is_none()));
204
205        // lhs = max
206
207        let result = I128::MAX.checked_mul_unsigned(&U128::ZERO);
208        assert_eq!(result.unwrap(), I128::ZERO);
209
210        let result = I128::MAX.checked_mul_unsigned(&U128::ONE);
211        assert_eq!(result.unwrap(), I128::MAX);
212
213        let result = I128::MAX.checked_mul_unsigned(&U128::MAX);
214        assert!(bool::from(result.is_none()));
215    }
216
217    #[test]
218    #[allow(deprecated)]
219    fn test_checked_mul_unsigned_right() {
220        // rhs = 0
221        let result = I256::MIN.checked_mul_unsigned_right(&U128::ZERO);
222        assert!(bool::from(result.is_some()));
223        assert_eq!(result.unwrap(), I128::ZERO);
224
225        let result = I128::MIN.checked_mul_unsigned_right(&U256::ZERO);
226        assert!(bool::from(result.is_some()));
227        assert_eq!(result.unwrap(), I256::ZERO);
228
229        // rhs = 1
230        let result = I256::MIN.checked_mul_unsigned_right(&U128::ONE);
231        assert!(bool::from(result.is_none()));
232
233        let result = I128::MIN.checked_mul_unsigned_right(&U256::ONE);
234        assert!(bool::from(result.is_some()));
235        assert_eq!(result.unwrap(), I128::MIN.resize());
236
237        // rhs > 1
238        let result = I256::ONE.checked_mul_unsigned_right(I128::MAX.as_uint());
239        assert!(bool::from(result.is_some()));
240        assert_eq!(result.unwrap(), I128::MAX.resize());
241
242        let result = I128::ONE.checked_mul_unsigned_right(I256::MAX.as_uint());
243        assert!(bool::from(result.is_some()));
244        assert_eq!(result.unwrap(), I256::MAX);
245
246        // rhs = MAX
247        let result = I256::ONE.checked_mul_unsigned_right(&U128::MAX);
248        assert!(bool::from(result.is_none()));
249
250        let result = I128::MIN.checked_mul_unsigned_right(&U256::MAX);
251        assert!(bool::from(result.is_none()));
252    }
253
254    #[test]
255    fn test_concatenating_mul_unsigned() {
256        assert_eq!(
257            I128::MIN.concatenating_mul_unsigned(&U128::ZERO),
258            I256::ZERO
259        );
260        assert_eq!(
261            I128::MIN.concatenating_mul_unsigned(&U128::ONE),
262            I256::from_be_hex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF80000000000000000000000000000000")
263        );
264        assert_eq!(
265            I128::MIN.concatenating_mul_unsigned(&U128::MAX),
266            I256::from_be_hex("8000000000000000000000000000000080000000000000000000000000000000")
267        );
268
269        assert_eq!(
270            I128::MINUS_ONE.concatenating_mul_unsigned(&U128::ZERO),
271            I256::ZERO
272        );
273        assert_eq!(
274            I128::MINUS_ONE.concatenating_mul_unsigned(&U128::ONE),
275            I256::MINUS_ONE
276        );
277        assert_eq!(
278            I128::MINUS_ONE.concatenating_mul_unsigned(&U128::MAX),
279            I256::from_be_hex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000000000000000000000000001")
280        );
281
282        assert_eq!(
283            I128::ZERO.concatenating_mul_unsigned(&U128::ZERO),
284            I256::ZERO
285        );
286        assert_eq!(
287            I128::ZERO.concatenating_mul_unsigned(&U128::ONE),
288            I256::ZERO
289        );
290        assert_eq!(
291            I128::ZERO.concatenating_mul_unsigned(&U128::MAX),
292            I256::ZERO
293        );
294
295        assert_eq!(
296            I128::ONE.concatenating_mul_unsigned(&U128::ZERO),
297            I256::ZERO
298        );
299        assert_eq!(I128::ONE.concatenating_mul_unsigned(&U128::ONE), I256::ONE);
300        assert_eq!(
301            I128::ONE.concatenating_mul_unsigned(&U128::MAX),
302            I256::from_be_hex("00000000000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF")
303        );
304
305        assert_eq!(
306            I128::MAX.concatenating_mul_unsigned(&U128::ZERO),
307            I256::ZERO
308        );
309        assert_eq!(
310            I128::MAX.concatenating_mul_unsigned(&U128::ONE),
311            I256::from_be_hex("000000000000000000000000000000007FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF")
312        );
313        assert_eq!(
314            I128::MAX.concatenating_mul_unsigned(&U128::MAX),
315            I256::from_be_hex("7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE80000000000000000000000000000001")
316        );
317    }
318}