1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
//! Widening multiplication of [`U256`] by a `u64` scalar into a [`U320`].
use super::U256;
use crate::u320::U320;
use core::ops::Mul;
/// Widening multiplication of a 256-bit integer by a `u64` scalar,
/// producing a 320-bit result.
///
/// Each of the four `u64` limbs of `self` is multiplied by `rhs` into a
/// `u128` intermediate, then accumulated with carry propagation across
/// five result limbs. The carry from the most significant limb becomes
/// the fifth (highest) limb of the [`U320`] output.
///
/// This operation cannot overflow: `(2^256 − 1) × (2^64 − 1) < 2^320`.
///
/// # Examples
///
/// ```
/// use cnfy_uint::u256::U256;
/// use cnfy_uint::u320::U320;
///
/// let a = U256::from_be_limbs([0, 0, 0, 7]);
/// let result = a * 6u64;
/// assert_eq!(result, U320::from_be_limbs([0, 0, 0, 0, 42]));
/// ```
impl Mul<u64> for U256 {
type Output = U320;
#[inline]
fn mul(self, rhs: u64) -> U320 {
let rhs = rhs as u128;
let p0 = (self.0[0] as u128) * rhs;
let p1 = (self.0[1] as u128) * rhs + (p0 >> 64);
let p2 = (self.0[2] as u128) * rhs + (p1 >> 64);
let p3 = (self.0[3] as u128) * rhs + (p2 >> 64);
U320([
p0 as u64,
p1 as u64,
p2 as u64,
p3 as u64,
(p3 >> 64) as u64,
])
}
}
#[cfg(test)]
mod ai_tests {
use super::*;
/// 7 × 6 = 42.
#[test]
fn small_product() {
let a = U256::from_be_limbs([0, 0, 0, 7]);
assert_eq!(a * 6u64, U320::from_be_limbs([0, 0, 0, 0, 42]));
}
/// Anything times zero is zero.
#[test]
fn mul_by_zero() {
let a = U256::from_be_limbs([0x1234, 0x5678, 0x9ABC, 0xDEF0]);
assert_eq!(a * 0u64, U320::from_be_limbs([0; 5]));
}
/// Multiplicative identity: x × 1 = x in the lower 256 bits.
#[test]
fn mul_by_one() {
let a = U256::from_be_limbs([0x1234, 0x5678, 0x9ABC, 0xDEF0]);
assert_eq!(
a * 1u64,
U320::from_be_limbs([0, 0x1234, 0x5678, 0x9ABC, 0xDEF0])
);
}
/// MAX × MAX_u64 produces correct 320-bit result.
#[test]
fn max_times_max_u64() {
// (2^256 - 1) * (2^64 - 1) = 2^320 - 2^256 - 2^64 + 1
let result = U256::MAX * u64::MAX;
assert_eq!(
result,
U320::from_be_limbs([u64::MAX - 1, u64::MAX, u64::MAX, u64::MAX, 1]),
);
}
/// Single limb × scalar that carries across limb boundaries.
#[test]
fn carry_propagation() {
// 0xFFFFFFFFFFFFFFFF * 2 = 0x1_FFFFFFFFFFFFFFFE
let a = U256::from_be_limbs([0, 0, 0, u64::MAX]);
let result = a * 2u64;
assert_eq!(result, U320::from_be_limbs([0, 0, 0, 1, u64::MAX - 1]));
}
/// Multi-limb value × scalar with cascading carries.
#[test]
fn full_width_carry() {
let a = U256::from_be_limbs([u64::MAX, u64::MAX, u64::MAX, u64::MAX]);
let result = a * 2u64;
// (2^256 - 1) * 2 = 2^257 - 2
// = [1, 0xFFFF...FFFF, 0xFFFF...FFFF, 0xFFFF...FFFF, 0xFFFF...FFFE]
assert_eq!(
result,
U320::from_be_limbs([1, u64::MAX, u64::MAX, u64::MAX, u64::MAX - 1]),
);
}
}