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