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
//! Extraction of a 64-bit window at an arbitrary bit offset.
use super::U256;
impl U256 {
/// Extracts 64 bits starting at the given bit offset from the least
/// significant end.
///
/// Equivalent to `(self >> shift) as u64` but reads at most two
/// adjacent limbs instead of constructing a full shifted `U256`.
/// This makes it ideal for extracting windows from large values
/// without touching all four limbs.
///
/// # Examples
///
/// ```
/// use cnfy_uint::u256::U256;
///
/// let v = U256::from_be_limbs([0, 0, 0, 0xFF]);
/// assert_eq!(v.extract_u64(0), 0xFF);
/// assert_eq!(v.extract_u64(4), 0x0F);
/// ```
#[inline]
pub const fn extract_u64(&self, shift: u32) -> u64 {
let limb = (shift / 64) as usize;
let bit = shift % 64;
// little-endian: self.0[0] is the LSB limb, self.0[3] is the MSB limb
let lo = self.0[limb];
let hi = if limb < 3 { self.0[limb + 1] } else { 0 };
if bit == 0 {
lo
} else {
(lo >> bit) | (hi << (64 - bit))
}
}
}
#[cfg(test)]
mod ai_tests {
use super::*;
/// Zero shift returns the least significant limb.
#[test]
fn shift_zero() {
let v = U256::from_be_limbs([0xAA, 0xBB, 0xCC, 0xDD]);
assert_eq!(v.extract_u64(0), 0xDD);
}
/// Shift by 64 returns the second limb.
#[test]
fn shift_one_limb() {
let v = U256::from_be_limbs([0xAA, 0xBB, 0xCC, 0xDD]);
assert_eq!(v.extract_u64(64), 0xCC);
}
/// Shift by 192 returns the most significant limb.
#[test]
fn shift_three_limbs() {
let v = U256::from_be_limbs([0xAA, 0xBB, 0xCC, 0xDD]);
assert_eq!(v.extract_u64(192), 0xAA);
}
/// Sub-limb shift straddles two limbs.
#[test]
fn cross_limb_shift() {
let v = U256::from_be_limbs([0, 0, 1, 0]);
// bit 64 is set → shift by 32 gives bit 32 set in result
assert_eq!(v.extract_u64(32), 1u64 << 32);
}
/// Matches shr_bits for various shift amounts.
#[test]
fn matches_shr_bits() {
let val = U256::from_be_limbs([
0x123456789ABCDEF0,
0xFEDCBA9876543210,
0x1111222233334444,
0x5555666677778888,
]);
for shift in [1, 32, 63, 64, 65, 100, 127, 128, 129, 190, 192, 193] {
assert_eq!(
val.extract_u64(shift),
val.shr_bits(shift).0[0],
"mismatch at shift={shift}",
);
}
}
}