Coverage Report

Created: 2026-11-12 06:16

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/registry/src/index.crates.io-1949cf8c6b5b557f/crypto-bigint-0.7.10/src/int/mul.rs
Line
Count
Source
1
//! [`Int`] multiplication operations.
2
3
use crate::{
4
    Checked, CheckedMul, Choice, Concat, CtOption, Int, Mul, MulAssign, Uint, WrappingMul,
5
};
6
7
impl<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
0
    pub const fn split_mul<const RHS_LIMBS: usize>(
17
0
        &self,
18
0
        rhs: &Int<RHS_LIMBS>,
19
0
    ) -> (Uint<{ LIMBS }>, Uint<{ RHS_LIMBS }>, Choice) {
20
0
        self.widening_mul(rhs)
21
0
    }
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
0
    pub const fn widening_mul<const RHS_LIMBS: usize>(
32
0
        &self,
33
0
        rhs: &Int<RHS_LIMBS>,
34
0
    ) -> (Uint<{ LIMBS }>, Uint<{ RHS_LIMBS }>, Choice) {
35
        // Step 1: split operands into their signs and magnitudes.
36
0
        let (lhs_abs, lhs_sgn) = self.abs_sign();
37
0
        let (rhs_abs, rhs_sgn) = rhs.abs_sign();
38
39
        // Step 2: multiply the magnitudes
40
0
        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
0
        let negate = lhs_sgn.xor(rhs_sgn);
47
48
0
        (lo, hi, negate)
49
0
    }
50
51
    /// Multiply `self` by `rhs`, returning a concatenated "wide" result.
52
    #[inline]
53
    #[must_use]
54
0
    pub const fn concatenating_mul<const RHS_LIMBS: usize, const WIDE_LIMBS: usize>(
55
0
        &self,
56
0
        rhs: &Int<RHS_LIMBS>,
57
0
    ) -> Int<WIDE_LIMBS>
58
0
    where
59
0
        Uint<LIMBS>: Concat<RHS_LIMBS, Output = Uint<WIDE_LIMBS>>,
60
    {
61
0
        let (lhs_abs, lhs_sign) = self.abs_sign();
62
0
        let (rhs_abs, rhs_sign) = rhs.abs_sign();
63
0
        let product_abs = lhs_abs.concatenating_mul(&rhs_abs);
64
0
        let product_sign = lhs_sign.xor(rhs_sign);
65
66
        // always fits
67
0
        Int::from_bits(product_abs.wrapping_neg_if(product_sign))
68
0
    }
69
70
    /// Multiply `self` by `rhs`, returning a `CtOption` which is `is_some` only if
71
    /// overflow did not occur.
72
    #[must_use]
73
0
    pub const fn checked_mul<const RHS_LIMBS: usize>(
74
0
        &self,
75
0
        rhs: &Int<RHS_LIMBS>,
76
0
    ) -> CtOption<Self> {
77
0
        let (abs_lhs, lhs_sgn) = self.abs_sign();
78
0
        let (abs_rhs, rhs_sgn) = rhs.abs_sign();
79
0
        let maybe_res = abs_lhs.checked_mul(&abs_rhs);
80
0
        Self::new_from_abs_opt_sign(maybe_res, lhs_sgn.xor(rhs_sgn))
81
0
    }
82
83
    /// Multiply `self` by `rhs`, saturating at the numeric bounds instead of overflowing.
84
    #[must_use]
85
0
    pub const fn saturating_mul<const RHS_LIMBS: usize>(&self, rhs: &Int<RHS_LIMBS>) -> Self {
86
0
        let (abs_lhs, lhs_sgn) = self.abs_sign();
87
0
        let (abs_rhs, rhs_sgn) = rhs.abs_sign();
88
0
        let maybe_res = abs_lhs.checked_mul(&abs_rhs);
89
0
        let is_neg = lhs_sgn.xor(rhs_sgn);
90
0
        let bound = Self::select(&Self::MAX, &Self::MIN, is_neg);
91
0
        ctutils::unwrap_or!(
92
0
            Self::new_from_abs_opt_sign(maybe_res, is_neg),
93
            bound,
94
            Self::select
95
        )
96
0
    }
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
0
    pub const fn wrapping_mul<const RHS_LIMBS: usize>(&self, rhs: &Int<RHS_LIMBS>) -> Self {
103
0
        if RHS_LIMBS >= LIMBS {
104
0
            Self(self.0.wrapping_mul(&rhs.0))
105
        } else {
106
0
            let (abs_rhs, rhs_sgn) = rhs.abs_sign();
107
0
            Self(self.0.wrapping_mul(&abs_rhs).wrapping_neg_if(rhs_sgn))
108
        }
109
0
    }
110
}
111
112
/// Squaring operations.
113
impl<const LIMBS: usize> Int<LIMBS> {
114
    /// Square self, returning a concatenated "wide" result.
115
    #[must_use]
116
0
    pub fn concatenating_square<const WIDE_LIMBS: usize>(&self) -> Uint<WIDE_LIMBS>
117
0
    where
118
0
        Uint<LIMBS>: Concat<LIMBS, Output = Uint<WIDE_LIMBS>>,
119
    {
120
0
        self.abs().concatenating_square()
121
0
    }
122
123
    /// Square self, checking that the result fits in the original [`Uint`] size.
124
    #[must_use]
125
0
    pub fn checked_square(&self) -> CtOption<Uint<LIMBS>> {
126
0
        self.abs().checked_square()
127
0
    }
128
129
    /// Perform wrapping square, discarding overflow.
130
    #[must_use]
131
0
    pub const fn wrapping_square(&self) -> Uint<LIMBS> {
132
0
        self.abs().wrapping_square()
133
0
    }
134
135
    /// Perform saturating squaring, returning `MAX` on overflow.
136
    #[must_use]
137
0
    pub const fn saturating_square(&self) -> Uint<LIMBS> {
138
0
        self.abs().saturating_square()
139
0
    }
140
}
141
142
impl<const LIMBS: usize, const RHS_LIMBS: usize> CheckedMul<Int<RHS_LIMBS>> for Int<LIMBS> {
143
    #[inline]
144
0
    fn checked_mul(&self, rhs: &Int<RHS_LIMBS>) -> CtOption<Self> {
145
0
        self.checked_mul(rhs)
146
0
    }
147
}
148
149
impl<const LIMBS: usize> WrappingMul for Int<LIMBS> {
150
0
    fn wrapping_mul(&self, v: &Self) -> Self {
151
0
        self.wrapping_mul(v)
152
0
    }
153
}
154
155
impl<const LIMBS: usize, const RHS_LIMBS: usize> Mul<Int<RHS_LIMBS>> for Int<LIMBS> {
156
    type Output = Int<LIMBS>;
157
158
0
    fn mul(self, rhs: Int<RHS_LIMBS>) -> Self {
159
0
        self.mul(&rhs)
160
0
    }
161
}
162
163
impl<const LIMBS: usize, const RHS_LIMBS: usize> Mul<&Int<RHS_LIMBS>> for Int<LIMBS> {
164
    type Output = Int<LIMBS>;
165
166
0
    fn mul(self, rhs: &Int<RHS_LIMBS>) -> Self {
167
0
        (&self).mul(rhs)
168
0
    }
169
}
170
171
impl<const LIMBS: usize, const RHS_LIMBS: usize> Mul<Int<RHS_LIMBS>> for &Int<LIMBS> {
172
    type Output = Int<LIMBS>;
173
174
0
    fn mul(self, rhs: Int<RHS_LIMBS>) -> Self::Output {
175
0
        self.mul(&rhs)
176
0
    }
177
}
178
179
impl<const LIMBS: usize, const RHS_LIMBS: usize> Mul<&Int<RHS_LIMBS>> for &Int<LIMBS> {
180
    type Output = Int<LIMBS>;
181
182
0
    fn mul(self, rhs: &Int<RHS_LIMBS>) -> Self::Output {
183
0
        self.checked_mul(rhs)
184
0
            .expect("attempted to multiply with overflow")
185
0
    }
186
}
187
188
impl<const LIMBS: usize, const RHS_LIMBS: usize> MulAssign<Int<RHS_LIMBS>> for Int<LIMBS> {
189
0
    fn mul_assign(&mut self, rhs: Int<RHS_LIMBS>) {
190
0
        *self = self.mul(&rhs);
191
0
    }
192
}
193
194
impl<const LIMBS: usize, const RHS_LIMBS: usize> MulAssign<&Int<RHS_LIMBS>> for Int<LIMBS> {
195
0
    fn mul_assign(&mut self, rhs: &Int<RHS_LIMBS>) {
196
0
        *self = self.mul(rhs);
197
0
    }
198
}
199
200
impl<const LIMBS: usize> MulAssign<Checked<Int<LIMBS>>> for Checked<Int<LIMBS>> {
201
0
    fn mul_assign(&mut self, other: Checked<Int<LIMBS>>) {
202
0
        *self = *self * other;
203
0
    }
204
}
205
206
impl<const LIMBS: usize> MulAssign<&Checked<Int<LIMBS>>> for Checked<Int<LIMBS>> {
207
0
    fn mul_assign(&mut self, other: &Checked<Int<LIMBS>>) {
208
0
        *self = *self * other;
209
0
    }
210
}
211
212
#[cfg(test)]
213
#[allow(clippy::cast_possible_wrap)]
214
mod 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
}