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