1use core::ops::{Mul, MulAssign};
4
5use subtle::CtOption;
6
7use crate::{Checked, CheckedMul, ConcatMixed, ConstChoice, ConstCtOption, Int, Uint, Zero};
8
9impl<const LIMBS: usize> Int<LIMBS> {
10 pub const fn split_mul<const RHS_LIMBS: usize>(
17 &self,
18 rhs: &Int<RHS_LIMBS>,
19 ) -> (Uint<{ LIMBS }>, Uint<{ RHS_LIMBS }>, ConstChoice) {
20 let (lhs_abs, lhs_sgn) = self.abs_sign();
22 let (rhs_abs, rhs_sgn) = rhs.abs_sign();
23
24 let (lo, hi) = lhs_abs.split_mul(&rhs_abs);
26
27 let negate = lhs_sgn.xor(rhs_sgn);
32
33 (lo, hi, negate)
34 }
35
36 pub const fn widening_mul<const RHS_LIMBS: usize, const WIDE_LIMBS: usize>(
38 &self,
39 rhs: &Int<RHS_LIMBS>,
40 ) -> Int<WIDE_LIMBS>
41 where
42 Uint<LIMBS>: ConcatMixed<Uint<RHS_LIMBS>, MixedOutput = Uint<WIDE_LIMBS>>,
43 {
44 let (lhs_abs, lhs_sign) = self.abs_sign();
45 let (rhs_abs, rhs_sign) = rhs.abs_sign();
46 let product_abs = lhs_abs.widening_mul(&rhs_abs);
47 let product_sign = lhs_sign.xor(rhs_sign);
48
49 Int::from_bits(product_abs.wrapping_neg_if(product_sign))
51 }
52}
53
54impl<const LIMBS: usize> Int<LIMBS> {
56 pub fn widening_square<const WIDE_LIMBS: usize>(&self) -> Uint<WIDE_LIMBS>
58 where
59 Uint<LIMBS>: ConcatMixed<Uint<LIMBS>, MixedOutput = Uint<WIDE_LIMBS>>,
60 {
61 self.abs().widening_square()
62 }
63
64 pub fn checked_square(&self) -> ConstCtOption<Uint<LIMBS>> {
66 self.abs().checked_square()
67 }
68
69 pub const fn wrapping_square(&self) -> Uint<LIMBS> {
71 self.abs().wrapping_square()
72 }
73
74 pub const fn saturating_square(&self) -> Uint<LIMBS> {
76 self.abs().saturating_square()
77 }
78}
79
80impl<const LIMBS: usize, const RHS_LIMBS: usize> CheckedMul<Int<RHS_LIMBS>> for Int<LIMBS> {
81 #[inline]
82 fn checked_mul(&self, rhs: &Int<RHS_LIMBS>) -> CtOption<Self> {
83 let (lo, hi, is_negative) = self.split_mul(rhs);
84 let val = Self::new_from_abs_sign(lo, is_negative);
85 CtOption::from(val).and_then(|int| CtOption::new(int, hi.is_zero()))
86 }
87}
88
89impl<const LIMBS: usize, const RHS_LIMBS: usize> Mul<Int<RHS_LIMBS>> for Int<LIMBS> {
90 type Output = Int<LIMBS>;
91
92 fn mul(self, rhs: Int<RHS_LIMBS>) -> Self {
93 self.mul(&rhs)
94 }
95}
96
97impl<const LIMBS: usize, const RHS_LIMBS: usize> Mul<&Int<RHS_LIMBS>> for Int<LIMBS> {
98 type Output = Int<LIMBS>;
99
100 fn mul(self, rhs: &Int<RHS_LIMBS>) -> Self {
101 (&self).mul(rhs)
102 }
103}
104
105impl<const LIMBS: usize, const RHS_LIMBS: usize> Mul<Int<RHS_LIMBS>> for &Int<LIMBS> {
106 type Output = Int<LIMBS>;
107
108 fn mul(self, rhs: Int<RHS_LIMBS>) -> Self::Output {
109 self.mul(&rhs)
110 }
111}
112
113impl<const LIMBS: usize, const RHS_LIMBS: usize> Mul<&Int<RHS_LIMBS>> for &Int<LIMBS> {
114 type Output = Int<LIMBS>;
115
116 fn mul(self, rhs: &Int<RHS_LIMBS>) -> Self::Output {
117 self.checked_mul(rhs)
118 .expect("attempted to multiply with overflow")
119 }
120}
121
122impl<const LIMBS: usize> MulAssign<Checked<Int<LIMBS>>> for Checked<Int<LIMBS>> {
123 fn mul_assign(&mut self, other: Checked<Int<LIMBS>>) {
124 *self = *self * other;
125 }
126}
127
128impl<const LIMBS: usize> MulAssign<&Checked<Int<LIMBS>>> for Checked<Int<LIMBS>> {
129 fn mul_assign(&mut self, other: &Checked<Int<LIMBS>>) {
130 *self = *self * other;
131 }
132}
133
134#[cfg(test)]
149mod tests {
150 use crate::{CheckedMul, ConstChoice, Int, I128, I256, U128, U256};
151
152 #[test]
153 fn test_checked_mul() {
154 let min_plus_one = Int {
155 0: I128::MIN.0.wrapping_add(&I128::ONE.0),
156 };
157
158 let result = I128::MIN.checked_mul(&I128::MIN);
161 assert!(bool::from(result.is_none()));
162
163 let result = I128::MIN.checked_mul(&I128::MINUS_ONE);
164 assert!(bool::from(result.is_none()));
165
166 let result = I128::MIN.checked_mul(&I128::ZERO);
167 assert_eq!(result.unwrap(), I128::ZERO);
168
169 let result = I128::MIN.checked_mul(&I128::ONE);
170 assert_eq!(result.unwrap(), I128::MIN);
171
172 let result = I128::MIN.checked_mul(&I128::MAX);
173 assert!(bool::from(result.is_none()));
174
175 let result = I128::MINUS_ONE.checked_mul(&I128::MIN);
178 assert!(bool::from(result.is_none()));
179
180 let result = I128::MINUS_ONE.checked_mul(&I128::MINUS_ONE);
181 assert_eq!(result.unwrap(), I128::ONE);
182
183 let result = I128::MINUS_ONE.checked_mul(&I128::ZERO);
184 assert_eq!(result.unwrap(), I128::ZERO);
185
186 let result = I128::MINUS_ONE.checked_mul(&I128::ONE);
187 assert_eq!(result.unwrap(), I128::MINUS_ONE);
188
189 let result = I128::MINUS_ONE.checked_mul(&I128::MAX);
190 assert_eq!(result.unwrap(), min_plus_one);
191
192 let result = I128::ZERO.checked_mul(&I128::MIN);
195 assert_eq!(result.unwrap(), I128::ZERO);
196
197 let result = I128::ZERO.checked_mul(&I128::MINUS_ONE);
198 assert_eq!(result.unwrap(), I128::ZERO);
199
200 let result = I128::ZERO.checked_mul(&I128::ZERO);
201 assert_eq!(result.unwrap(), I128::ZERO);
202
203 let result = I128::ZERO.checked_mul(&I128::ONE);
204 assert_eq!(result.unwrap(), I128::ZERO);
205
206 let result = I128::ZERO.checked_mul(&I128::MAX);
207 assert_eq!(result.unwrap(), I128::ZERO);
208
209 let result = I128::ONE.checked_mul(&I128::MIN);
212 assert_eq!(result.unwrap(), I128::MIN);
213
214 let result = I128::ONE.checked_mul(&I128::MINUS_ONE);
215 assert_eq!(result.unwrap(), I128::MINUS_ONE);
216
217 let result = I128::ONE.checked_mul(&I128::ZERO);
218 assert_eq!(result.unwrap(), I128::ZERO);
219
220 let result = I128::ONE.checked_mul(&I128::ONE);
221 assert_eq!(result.unwrap(), I128::ONE);
222
223 let result = I128::ONE.checked_mul(&I128::MAX);
224 assert_eq!(result.unwrap(), I128::MAX);
225
226 let result = I128::MAX.checked_mul(&I128::MIN);
229 assert!(bool::from(result.is_none()));
230
231 let result = I128::MAX.checked_mul(&I128::MINUS_ONE);
232 assert_eq!(result.unwrap(), min_plus_one);
233
234 let result = I128::MAX.checked_mul(&I128::ZERO);
235 assert_eq!(result.unwrap(), I128::ZERO);
236
237 let result = I128::MAX.checked_mul(&I128::ONE);
238 assert_eq!(result.unwrap(), I128::MAX);
239
240 let result = I128::MAX.checked_mul(&I128::MAX);
241 assert!(bool::from(result.is_none()));
242 }
243
244 #[test]
245 fn test_widening_mul() {
246 assert_eq!(
247 I128::MIN.widening_mul(&I128::MIN),
248 I256::from_be_hex("4000000000000000000000000000000000000000000000000000000000000000")
249 );
250 assert_eq!(
251 I128::MIN.widening_mul(&I128::MINUS_ONE),
252 I256::from_be_hex("0000000000000000000000000000000080000000000000000000000000000000")
253 );
254 assert_eq!(I128::MIN.widening_mul(&I128::ZERO), I256::ZERO);
255 assert_eq!(
256 I128::MIN.widening_mul(&I128::ONE),
257 I256::from_be_hex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF80000000000000000000000000000000")
258 );
259 assert_eq!(
260 I128::MIN.widening_mul(&I128::MAX),
261 I256::from_be_hex("C000000000000000000000000000000080000000000000000000000000000000")
262 );
263
264 assert_eq!(
265 I128::MINUS_ONE.widening_mul(&I128::MIN),
266 I256::from_be_hex("0000000000000000000000000000000080000000000000000000000000000000")
267 );
268 assert_eq!(I128::MINUS_ONE.widening_mul(&I128::MINUS_ONE), I256::ONE);
269 assert_eq!(I128::MINUS_ONE.widening_mul(&I128::ZERO), I256::ZERO);
270 assert_eq!(I128::MINUS_ONE.widening_mul(&I128::ONE), I256::MINUS_ONE);
271 assert_eq!(
272 I128::MINUS_ONE.widening_mul(&I128::MAX),
273 I256::from_be_hex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF80000000000000000000000000000001")
274 );
275
276 assert_eq!(I128::ZERO.widening_mul(&I128::MIN), I256::ZERO);
277 assert_eq!(I128::ZERO.widening_mul(&I128::MINUS_ONE), I256::ZERO);
278 assert_eq!(I128::ZERO.widening_mul(&I128::ZERO), I256::ZERO);
279 assert_eq!(I128::ZERO.widening_mul(&I128::ONE), I256::ZERO);
280 assert_eq!(I128::ZERO.widening_mul(&I128::MAX), I256::ZERO);
281
282 assert_eq!(
283 I128::ONE.widening_mul(&I128::MIN),
284 I256::from_be_hex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF80000000000000000000000000000000")
285 );
286 assert_eq!(I128::ONE.widening_mul(&I128::MINUS_ONE), I256::MINUS_ONE);
287 assert_eq!(I128::ONE.widening_mul(&I128::ZERO), I256::ZERO);
288 assert_eq!(I128::ONE.widening_mul(&I128::ONE), I256::ONE);
289 assert_eq!(
290 I128::ONE.widening_mul(&I128::MAX),
291 I256::from_be_hex("000000000000000000000000000000007FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF")
292 );
293
294 assert_eq!(
295 I128::MAX.widening_mul(&I128::MIN),
296 I256::from_be_hex("C000000000000000000000000000000080000000000000000000000000000000")
297 );
298 assert_eq!(
299 I128::MAX.widening_mul(&I128::MINUS_ONE),
300 I256::from_be_hex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF80000000000000000000000000000001")
301 );
302 assert_eq!(I128::MAX.widening_mul(&I128::ZERO), I256::ZERO);
303 assert_eq!(
304 I128::MAX.widening_mul(&I128::ONE),
305 I256::from_be_hex("000000000000000000000000000000007FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF")
306 );
307 assert_eq!(
308 I128::MAX.widening_mul(&I128::MAX),
309 I256::from_be_hex("3FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000000000000000000000000001")
310 );
311 }
312
313 #[test]
314 fn test_widening_square() {
315 let res = I128::from_i64(i64::MIN).widening_square();
316 assert_eq!(
317 res,
318 U256::from_be_hex("0000000000000000000000000000000040000000000000000000000000000000")
319 );
320
321 let x: I128 = I128::MINUS_ONE << 64;
322 let res = x.widening_square();
323 assert_eq!(
324 res,
325 U256::from_be_hex("0000000000000000000000000000000100000000000000000000000000000000")
326 )
327 }
328
329 #[test]
330 fn test_checked_square() {
331 let res = I128::from_i64(i64::MIN).checked_square();
332 assert_eq!(res.is_some(), ConstChoice::TRUE);
333 assert_eq!(
334 res.unwrap(),
335 U128::from_be_hex("40000000000000000000000000000000")
336 );
337
338 let x: I128 = I128::MINUS_ONE << 64;
339 let res = x.checked_square();
340 assert_eq!(res.is_none(), ConstChoice::TRUE)
341 }
342
343 #[test]
344 fn test_wrapping_square() {
345 let res = I128::from_i64(i64::MIN).wrapping_square();
346 assert_eq!(res, U128::from_be_hex("40000000000000000000000000000000"));
347
348 let x: I128 = I128::MINUS_ONE << 64;
349 let res = x.wrapping_square();
350 assert_eq!(res, U128::ZERO);
351
352 let x: I128 = I128::from_i64(i64::MAX);
353 let res = x.wrapping_square();
354 assert_eq!(res, U128::from_be_hex("3FFFFFFFFFFFFFFF0000000000000001"))
355 }
356
357 #[test]
358 fn test_saturating_square() {
359 assert_eq!(
360 I128::from_i64(i64::MIN).saturating_square(),
361 U128::from_be_hex("40000000000000000000000000000000")
362 );
363 let x: I128 = I128::MINUS_ONE << 64;
364 assert_eq!(x.saturating_square(), U128::MAX);
365 }
366}