Skip to main content

crypto_bigint/int/
mul.rs

1//! [`Int`] multiplication operations.
2
3use crate::{
4    Checked, CheckedMul, Choice, Concat, CtOption, Int, Mul, MulAssign, Uint, WrappingMul,
5};
6
7impl<const LIMBS: usize> Int<LIMBS> {
8    /// Compute "wide" multiplication as a 3-tuple `(lo, hi, negate)`.
9    /// The `(lo, hi)` components contain the _magnitude of the product_, with sizes
10    /// corresponding to the sizes of the operands; `negate` indicates whether the result should be
11    /// negated when converted from [`Uint`] to [`Int`].
12    ///
13    /// Note: even if `negate` is truthy, the magnitude might be zero!
14    #[deprecated(since = "0.7.0", note = "please use `widening_mul` instead")]
15    #[must_use]
16    pub const fn split_mul<const RHS_LIMBS: usize>(
17        &self,
18        rhs: &Int<RHS_LIMBS>,
19    ) -> (Uint<{ LIMBS }>, Uint<{ RHS_LIMBS }>, Choice) {
20        self.widening_mul(rhs)
21    }
22
23    /// Compute "wide" multiplication as a 3-tuple `(lo, hi, negate)`.
24    /// The `(lo, hi)` components contain the _magnitude of the product_, with sizes
25    /// corresponding to the sizes of the operands; `negate` indicates whether the result should be
26    /// negated when converted from [`Uint`] to [`Int`].
27    ///
28    /// Note: even if `negate` is truthy, the magnitude might be zero!
29    #[inline]
30    #[must_use]
31    pub const fn widening_mul<const RHS_LIMBS: usize>(
32        &self,
33        rhs: &Int<RHS_LIMBS>,
34    ) -> (Uint<{ LIMBS }>, Uint<{ RHS_LIMBS }>, Choice) {
35        // Step 1: split operands into their signs and magnitudes.
36        let (lhs_abs, lhs_sgn) = self.abs_sign();
37        let (rhs_abs, rhs_sgn) = rhs.abs_sign();
38
39        // Step 2: multiply the magnitudes
40        let (lo, hi) = lhs_abs.widening_mul(&rhs_abs);
41
42        // Step 3. Determine if the result should be negated.
43        // This should be done if and only if lhs and rhs have opposing signs.
44        // Note: if either operand is zero, the resulting magnitude will also be zero. Negating
45        // zero, however, still yields zero, so having a truthy `negate` in that scenario is OK.
46        let negate = lhs_sgn.xor(rhs_sgn);
47
48        (lo, hi, negate)
49    }
50
51    /// Multiply `self` by `rhs`, returning a concatenated "wide" result.
52    #[inline]
53    #[must_use]
54    pub const fn concatenating_mul<const RHS_LIMBS: usize, const WIDE_LIMBS: usize>(
55        &self,
56        rhs: &Int<RHS_LIMBS>,
57    ) -> Int<WIDE_LIMBS>
58    where
59        Uint<LIMBS>: Concat<RHS_LIMBS, Output = Uint<WIDE_LIMBS>>,
60    {
61        let (lhs_abs, lhs_sign) = self.abs_sign();
62        let (rhs_abs, rhs_sign) = rhs.abs_sign();
63        let product_abs = lhs_abs.concatenating_mul(&rhs_abs);
64        let product_sign = lhs_sign.xor(rhs_sign);
65
66        // always fits
67        Int::from_bits(product_abs.wrapping_neg_if(product_sign))
68    }
69
70    /// Multiply `self` by `rhs`, returning a `CtOption` which is `is_some` only if
71    /// overflow did not occur.
72    #[must_use]
73    pub const fn checked_mul<const RHS_LIMBS: usize>(
74        &self,
75        rhs: &Int<RHS_LIMBS>,
76    ) -> CtOption<Self> {
77        let (abs_lhs, lhs_sgn) = self.abs_sign();
78        let (abs_rhs, rhs_sgn) = rhs.abs_sign();
79        let maybe_res = abs_lhs.checked_mul(&abs_rhs);
80        Self::new_from_abs_opt_sign(maybe_res, lhs_sgn.xor(rhs_sgn))
81    }
82
83    /// Multiply `self` by `rhs`, saturating at the numeric bounds instead of overflowing.
84    #[must_use]
85    pub const fn saturating_mul<const RHS_LIMBS: usize>(&self, rhs: &Int<RHS_LIMBS>) -> Self {
86        let (abs_lhs, lhs_sgn) = self.abs_sign();
87        let (abs_rhs, rhs_sgn) = rhs.abs_sign();
88        let maybe_res = abs_lhs.checked_mul(&abs_rhs);
89        let is_neg = lhs_sgn.xor(rhs_sgn);
90        let bound = Self::select(&Self::MAX, &Self::MIN, is_neg);
91        ctutils::unwrap_or!(
92            Self::new_from_abs_opt_sign(maybe_res, is_neg),
93            bound,
94            Self::select
95        )
96    }
97
98    /// Multiply `self` by `rhs`, wrapping the result in case of overflow.
99    /// This is equivalent to `(self * rhs) % (Uint::<LIMBS>::MAX + 1)`.
100    #[inline]
101    #[must_use]
102    pub const fn wrapping_mul<const RHS_LIMBS: usize>(&self, rhs: &Int<RHS_LIMBS>) -> Self {
103        if RHS_LIMBS >= LIMBS {
104            Self(self.0.wrapping_mul(&rhs.0))
105        } else {
106            let (abs_rhs, rhs_sgn) = rhs.abs_sign();
107            Self(self.0.wrapping_mul(&abs_rhs).wrapping_neg_if(rhs_sgn))
108        }
109    }
110}
111
112/// Squaring operations.
113impl<const LIMBS: usize> Int<LIMBS> {
114    /// Square self, returning a concatenated "wide" result.
115    #[must_use]
116    pub fn concatenating_square<const WIDE_LIMBS: usize>(&self) -> Uint<WIDE_LIMBS>
117    where
118        Uint<LIMBS>: Concat<LIMBS, Output = Uint<WIDE_LIMBS>>,
119    {
120        self.abs().concatenating_square()
121    }
122
123    /// Square self, checking that the result fits in the original [`Uint`] size.
124    #[must_use]
125    pub fn checked_square(&self) -> CtOption<Uint<LIMBS>> {
126        self.abs().checked_square()
127    }
128
129    /// Perform wrapping square, discarding overflow.
130    #[must_use]
131    pub const fn wrapping_square(&self) -> Uint<LIMBS> {
132        self.abs().wrapping_square()
133    }
134
135    /// Perform saturating squaring, returning `MAX` on overflow.
136    #[must_use]
137    pub const fn saturating_square(&self) -> Uint<LIMBS> {
138        self.abs().saturating_square()
139    }
140}
141
142impl<const LIMBS: usize, const RHS_LIMBS: usize> CheckedMul<Int<RHS_LIMBS>> for Int<LIMBS> {
143    #[inline]
144    fn checked_mul(&self, rhs: &Int<RHS_LIMBS>) -> CtOption<Self> {
145        self.checked_mul(rhs)
146    }
147}
148
149impl<const LIMBS: usize> WrappingMul for Int<LIMBS> {
150    fn wrapping_mul(&self, v: &Self) -> Self {
151        self.wrapping_mul(v)
152    }
153}
154
155impl<const LIMBS: usize, const RHS_LIMBS: usize> Mul<Int<RHS_LIMBS>> for Int<LIMBS> {
156    type Output = Int<LIMBS>;
157
158    fn mul(self, rhs: Int<RHS_LIMBS>) -> Self {
159        self.mul(&rhs)
160    }
161}
162
163impl<const LIMBS: usize, const RHS_LIMBS: usize> Mul<&Int<RHS_LIMBS>> for Int<LIMBS> {
164    type Output = Int<LIMBS>;
165
166    fn mul(self, rhs: &Int<RHS_LIMBS>) -> Self {
167        (&self).mul(rhs)
168    }
169}
170
171impl<const LIMBS: usize, const RHS_LIMBS: usize> Mul<Int<RHS_LIMBS>> for &Int<LIMBS> {
172    type Output = Int<LIMBS>;
173
174    fn mul(self, rhs: Int<RHS_LIMBS>) -> Self::Output {
175        self.mul(&rhs)
176    }
177}
178
179impl<const LIMBS: usize, const RHS_LIMBS: usize> Mul<&Int<RHS_LIMBS>> for &Int<LIMBS> {
180    type Output = Int<LIMBS>;
181
182    fn mul(self, rhs: &Int<RHS_LIMBS>) -> Self::Output {
183        self.checked_mul(rhs)
184            .expect("attempted to multiply with overflow")
185    }
186}
187
188impl<const LIMBS: usize, const RHS_LIMBS: usize> MulAssign<Int<RHS_LIMBS>> for Int<LIMBS> {
189    fn mul_assign(&mut self, rhs: Int<RHS_LIMBS>) {
190        *self = self.mul(&rhs);
191    }
192}
193
194impl<const LIMBS: usize, const RHS_LIMBS: usize> MulAssign<&Int<RHS_LIMBS>> for Int<LIMBS> {
195    fn mul_assign(&mut self, rhs: &Int<RHS_LIMBS>) {
196        *self = self.mul(rhs);
197    }
198}
199
200impl<const LIMBS: usize> MulAssign<Checked<Int<LIMBS>>> for Checked<Int<LIMBS>> {
201    fn mul_assign(&mut self, other: Checked<Int<LIMBS>>) {
202        *self = *self * other;
203    }
204}
205
206impl<const LIMBS: usize> MulAssign<&Checked<Int<LIMBS>>> for Checked<Int<LIMBS>> {
207    fn mul_assign(&mut self, other: &Checked<Int<LIMBS>>) {
208        *self = *self * other;
209    }
210}
211
212#[cfg(test)]
213#[allow(clippy::cast_possible_wrap)]
214mod tests {
215    use crate::{I64, I128, I256, Int, U64, U128, U256};
216
217    #[test]
218    #[allow(clippy::init_numbered_fields)]
219    fn test_checked_mul() {
220        let min_plus_one = Int {
221            0: I128::MIN.0.wrapping_add(&I128::ONE.0),
222        };
223
224        // lhs = min
225
226        let result = I128::MIN.checked_mul(&I128::MIN);
227        assert!(bool::from(result.is_none()));
228
229        let result = I128::MIN.checked_mul(&I128::MINUS_ONE);
230        assert!(bool::from(result.is_none()));
231
232        let result = I128::MIN.checked_mul(&I128::ZERO);
233        assert_eq!(result.unwrap(), I128::ZERO);
234
235        let result = I128::MIN.checked_mul(&I128::ONE);
236        assert_eq!(result.unwrap(), I128::MIN);
237
238        let result = I128::MIN.checked_mul(&I128::MAX);
239        assert!(bool::from(result.is_none()));
240
241        // lhs = -1
242
243        let result = I128::MINUS_ONE.checked_mul(&I128::MIN);
244        assert!(bool::from(result.is_none()));
245
246        let result = I128::MINUS_ONE.checked_mul(&I128::MINUS_ONE);
247        assert_eq!(result.unwrap(), I128::ONE);
248
249        let result = I128::MINUS_ONE.checked_mul(&I128::ZERO);
250        assert_eq!(result.unwrap(), I128::ZERO);
251
252        let result = I128::MINUS_ONE.checked_mul(&I128::ONE);
253        assert_eq!(result.unwrap(), I128::MINUS_ONE);
254
255        let result = I128::MINUS_ONE.checked_mul(&I128::MAX);
256        assert_eq!(result.unwrap(), min_plus_one);
257
258        // lhs = 0
259
260        let result = I128::ZERO.checked_mul(&I128::MIN);
261        assert_eq!(result.unwrap(), I128::ZERO);
262
263        let result = I128::ZERO.checked_mul(&I128::MINUS_ONE);
264        assert_eq!(result.unwrap(), I128::ZERO);
265
266        let result = I128::ZERO.checked_mul(&I128::ZERO);
267        assert_eq!(result.unwrap(), I128::ZERO);
268
269        let result = I128::ZERO.checked_mul(&I128::ONE);
270        assert_eq!(result.unwrap(), I128::ZERO);
271
272        let result = I128::ZERO.checked_mul(&I128::MAX);
273        assert_eq!(result.unwrap(), I128::ZERO);
274
275        // lhs = 1
276
277        let result = I128::ONE.checked_mul(&I128::MIN);
278        assert_eq!(result.unwrap(), I128::MIN);
279
280        let result = I128::ONE.checked_mul(&I128::MINUS_ONE);
281        assert_eq!(result.unwrap(), I128::MINUS_ONE);
282
283        let result = I128::ONE.checked_mul(&I128::ZERO);
284        assert_eq!(result.unwrap(), I128::ZERO);
285
286        let result = I128::ONE.checked_mul(&I128::ONE);
287        assert_eq!(result.unwrap(), I128::ONE);
288
289        let result = I128::ONE.checked_mul(&I128::MAX);
290        assert_eq!(result.unwrap(), I128::MAX);
291
292        // lhs = max
293
294        let result = I128::MAX.checked_mul(&I128::MIN);
295        assert!(bool::from(result.is_none()));
296
297        let result = I128::MAX.checked_mul(&I128::MINUS_ONE);
298        assert_eq!(result.unwrap(), min_plus_one);
299
300        let result = I128::MAX.checked_mul(&I128::ZERO);
301        assert_eq!(result.unwrap(), I128::ZERO);
302
303        let result = I128::MAX.checked_mul(&I128::ONE);
304        assert_eq!(result.unwrap(), I128::MAX);
305
306        let result = I128::MAX.checked_mul(&I128::MAX);
307        assert!(bool::from(result.is_none()));
308    }
309
310    #[test]
311    fn test_wrapping_mul() {
312        // wrapping
313        let a = 0xFFFFFFFB7B63198EF870DF1F90D9BD9Eu128 as i128;
314        let b = 0xF20C29FA87B356AA3B4C05C4F9C24B4Au128 as i128;
315        let z = 0xAA700D354D6CF4EE881F8FF8093A19ACu128 as i128;
316        assert_eq!(a.wrapping_mul(b), z);
317        assert_eq!(
318            I128::from_i128(a).wrapping_mul(&I128::from_i128(b)),
319            I128::from_i128(z)
320        );
321
322        // no wrapping
323        let c = -12345i64;
324        assert_eq!(
325            I128::from_i128(a).wrapping_mul(&I128::from_i64(c)),
326            I128::from_i128(a.wrapping_mul(i128::from(c)))
327        );
328
329        // overflow into MSB
330        let a = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFu128 as i128;
331        assert!(!a.is_negative() && a.wrapping_mul(a).is_negative());
332
333        // core case
334        assert_eq!(i8::MAX.wrapping_mul(2), -2);
335        assert_eq!(i64::MAX.wrapping_mul(2), -2);
336        assert_eq!(
337            I128::MAX.wrapping_mul(&I128::from_i64(2i64)),
338            I128::from_i64(-2i64)
339        );
340
341        let x = -197044252290277702i64;
342        let y = -2631691865753118366;
343        let z = -2988283350644101836;
344        assert_eq!(x.wrapping_mul(y), z);
345        assert_eq!(
346            I64::from_i64(x).wrapping_mul(&I64::from_i64(y)),
347            I64::from_i64(z)
348        );
349
350        let x = -86027672844719838068326470675019902915i128;
351        let y = -21188806580823612823777395451044967239i128;
352        let z = 11054120842379932838712398402517374997i128;
353        assert_eq!(x.wrapping_mul(y), z);
354        assert_eq!(
355            I128::from_i128(x).wrapping_mul(&I128::from_i128(y)),
356            I128::from_i128(z)
357        );
358    }
359
360    #[test]
361    fn test_wrapping_mul_mixed() {
362        let a = U64::from_u64(0x0011223344556677);
363        let b = U128::from_u128(0x8899aabbccddeeff_8899aabbccddeeff);
364        let expected = a.as_int().concatenating_mul(b.as_int());
365        assert_eq!(a.as_int().wrapping_mul(b.as_int()), expected.resize());
366        assert_eq!(b.as_int().wrapping_mul(a.as_int()), expected.resize());
367        assert_eq!(
368            a.as_int().wrapping_neg().wrapping_mul(b.as_int()),
369            expected.wrapping_neg().resize()
370        );
371        assert_eq!(
372            a.as_int().wrapping_mul(&b.as_int().wrapping_neg()),
373            expected.wrapping_neg().resize()
374        );
375        assert_eq!(
376            b.as_int().wrapping_neg().wrapping_mul(a.as_int()),
377            expected.wrapping_neg().resize()
378        );
379        assert_eq!(
380            b.as_int().wrapping_mul(&a.as_int().wrapping_neg()),
381            expected.wrapping_neg().resize()
382        );
383        assert_eq!(
384            a.as_int()
385                .wrapping_neg()
386                .wrapping_mul(&b.as_int().wrapping_neg()),
387            expected.resize()
388        );
389        assert_eq!(
390            b.as_int()
391                .wrapping_neg()
392                .wrapping_mul(&a.as_int().wrapping_neg()),
393            expected.resize()
394        );
395    }
396
397    #[test]
398    fn test_saturating_mul() {
399        // wrapping
400        let a = 0xFFFFFFFB7B63198EF870DF1F90D9BD9Eu128 as i128;
401        let b = 0xF20C29FA87B356AA3B4C05C4F9C24B4Au128 as i128;
402        assert_eq!(a.saturating_mul(b), i128::MAX);
403        assert_eq!(
404            I128::from_i128(a).saturating_mul(&I128::from_i128(b)),
405            I128::MAX
406        );
407
408        // no wrapping
409        let c = -12345i64;
410        assert_eq!(
411            I128::from_i128(a).saturating_mul(&I128::from_i64(c)),
412            I128::from_i128(a.saturating_mul(i128::from(c)))
413        );
414
415        // core case
416        assert_eq!(i8::MAX.saturating_mul(2), i8::MAX);
417        assert_eq!(i8::MAX.saturating_mul(-2), i8::MIN);
418        assert_eq!(i64::MAX.saturating_mul(2), i64::MAX);
419        assert_eq!(i64::MAX.saturating_mul(-2), i64::MIN);
420        assert_eq!(I128::MAX.saturating_mul(&I128::from_i64(2i64)), I128::MAX);
421        assert_eq!(I128::MAX.saturating_mul(&I128::from_i64(-2i64)), I128::MIN);
422
423        let x = -197044252290277702i64;
424        let y = -2631691865753118366;
425        assert_eq!(x.saturating_mul(y), i64::MAX);
426        assert_eq!(I64::from_i64(x).saturating_mul(&I64::from_i64(y)), I64::MAX);
427
428        let x = -86027672844719838068326470675019902915i128;
429        let y = 21188806580823612823777395451044967239i128;
430        assert_eq!(x.saturating_mul(y), i128::MIN);
431        assert_eq!(x.saturating_mul(-y), i128::MAX);
432        assert_eq!(
433            I128::from_i128(x).saturating_mul(&I128::from_i128(y)),
434            I128::MIN
435        );
436        assert_eq!(
437            I128::from_i128(x).saturating_mul(&I128::from_i128(-y)),
438            I128::MAX
439        );
440    }
441
442    #[test]
443    fn test_concatenating_mul() {
444        assert_eq!(
445            I128::MIN.concatenating_mul(&I128::MIN),
446            I256::from_be_hex("4000000000000000000000000000000000000000000000000000000000000000")
447        );
448        assert_eq!(
449            I128::MIN.concatenating_mul(&I128::MINUS_ONE),
450            I256::from_be_hex("0000000000000000000000000000000080000000000000000000000000000000")
451        );
452        assert_eq!(I128::MIN.concatenating_mul(&I128::ZERO), I256::ZERO);
453        assert_eq!(
454            I128::MIN.concatenating_mul(&I128::ONE),
455            I256::from_be_hex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF80000000000000000000000000000000")
456        );
457        assert_eq!(
458            I128::MIN.concatenating_mul(&I128::MAX),
459            I256::from_be_hex("C000000000000000000000000000000080000000000000000000000000000000")
460        );
461
462        assert_eq!(
463            I128::MINUS_ONE.concatenating_mul(&I128::MIN),
464            I256::from_be_hex("0000000000000000000000000000000080000000000000000000000000000000")
465        );
466        assert_eq!(
467            I128::MINUS_ONE.concatenating_mul(&I128::MINUS_ONE),
468            I256::ONE
469        );
470        assert_eq!(I128::MINUS_ONE.concatenating_mul(&I128::ZERO), I256::ZERO);
471        assert_eq!(
472            I128::MINUS_ONE.concatenating_mul(&I128::ONE),
473            I256::MINUS_ONE
474        );
475        assert_eq!(
476            I128::MINUS_ONE.concatenating_mul(&I128::MAX),
477            I256::from_be_hex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF80000000000000000000000000000001")
478        );
479
480        assert_eq!(I128::ZERO.concatenating_mul(&I128::MIN), I256::ZERO);
481        assert_eq!(I128::ZERO.concatenating_mul(&I128::MINUS_ONE), I256::ZERO);
482        assert_eq!(I128::ZERO.concatenating_mul(&I128::ZERO), I256::ZERO);
483        assert_eq!(I128::ZERO.concatenating_mul(&I128::ONE), I256::ZERO);
484        assert_eq!(I128::ZERO.concatenating_mul(&I128::MAX), I256::ZERO);
485
486        assert_eq!(
487            I128::ONE.concatenating_mul(&I128::MIN),
488            I256::from_be_hex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF80000000000000000000000000000000")
489        );
490        assert_eq!(
491            I128::ONE.concatenating_mul(&I128::MINUS_ONE),
492            I256::MINUS_ONE
493        );
494        assert_eq!(I128::ONE.concatenating_mul(&I128::ZERO), I256::ZERO);
495        assert_eq!(I128::ONE.concatenating_mul(&I128::ONE), I256::ONE);
496        assert_eq!(
497            I128::ONE.concatenating_mul(&I128::MAX),
498            I256::from_be_hex("000000000000000000000000000000007FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF")
499        );
500
501        assert_eq!(
502            I128::MAX.concatenating_mul(&I128::MIN),
503            I256::from_be_hex("C000000000000000000000000000000080000000000000000000000000000000")
504        );
505        assert_eq!(
506            I128::MAX.concatenating_mul(&I128::MINUS_ONE),
507            I256::from_be_hex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF80000000000000000000000000000001")
508        );
509        assert_eq!(I128::MAX.concatenating_mul(&I128::ZERO), I256::ZERO);
510        assert_eq!(
511            I128::MAX.concatenating_mul(&I128::ONE),
512            I256::from_be_hex("000000000000000000000000000000007FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF")
513        );
514        assert_eq!(
515            I128::MAX.concatenating_mul(&I128::MAX),
516            I256::from_be_hex("3FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000000000000000000000000001")
517        );
518    }
519
520    #[test]
521    fn test_concatenating_square() {
522        let res = I128::from_i64(i64::MIN).concatenating_square();
523        assert_eq!(
524            res,
525            U256::from_be_hex("0000000000000000000000000000000040000000000000000000000000000000")
526        );
527
528        let x: I128 = I128::MINUS_ONE << 64;
529        let res = x.concatenating_square();
530        assert_eq!(
531            res,
532            U256::from_be_hex("0000000000000000000000000000000100000000000000000000000000000000")
533        );
534    }
535
536    #[test]
537    fn test_checked_square() {
538        let res = I128::from_i64(i64::MIN).checked_square();
539        assert!(res.is_some().to_bool());
540        assert_eq!(
541            res.unwrap(),
542            U128::from_be_hex("40000000000000000000000000000000")
543        );
544
545        let x: I128 = I128::MINUS_ONE << 64;
546        let res = x.checked_square();
547        assert!(res.is_none().to_bool());
548    }
549
550    #[test]
551    fn test_wrapping_square() {
552        let res = I128::from_i64(i64::MIN).wrapping_square();
553        assert_eq!(res, U128::from_be_hex("40000000000000000000000000000000"));
554
555        let x: I128 = I128::MINUS_ONE << 64;
556        let res = x.wrapping_square();
557        assert_eq!(res, U128::ZERO);
558
559        let x: I128 = I128::from_i64(i64::MAX);
560        let res = x.wrapping_square();
561        assert_eq!(res, U128::from_be_hex("3FFFFFFFFFFFFFFF0000000000000001"));
562    }
563
564    #[test]
565    fn test_saturating_square() {
566        assert_eq!(
567            I128::from_i64(i64::MIN).saturating_square(),
568            U128::from_be_hex("40000000000000000000000000000000")
569        );
570        let x: I128 = I128::MINUS_ONE << 64;
571        assert_eq!(x.saturating_square(), U128::MAX);
572    }
573}