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
//! Population count (Hamming weight) for [`U256`].
use super::U256;
impl U256 {
/// Returns the number of ones in the binary representation.
///
/// Delegates to hardware `u64::count_ones` (POPCNT instruction) on each
/// limb. Useful for Hamming weight/distance in cryptographic analysis.
///
/// # Examples
///
/// ```
/// use cnfy_uint::u256::U256;
///
/// assert_eq!(U256::ZERO.count_ones(), 0);
/// assert_eq!(U256::ONE.count_ones(), 1);
/// assert_eq!(U256::MAX.count_ones(), 256);
/// ```
#[inline]
pub const fn count_ones(&self) -> u32 {
self.0[0].count_ones()
+ self.0[1].count_ones()
+ self.0[2].count_ones()
+ self.0[3].count_ones()
}
}
#[cfg(test)]
mod ai_tests {
use super::*;
/// Zero has no bits set.
#[test]
fn zero() {
assert_eq!(U256::ZERO.count_ones(), 0);
}
/// One has exactly one bit set.
#[test]
fn one() {
assert_eq!(U256::ONE.count_ones(), 1);
}
/// MAX has all 256 bits set.
#[test]
fn max() {
assert_eq!(U256::MAX.count_ones(), 256);
}
/// Each limb contributes independently.
#[test]
fn per_limb() {
let val = U256::from_be_limbs([0b111, 0b11, 0b1, 0b0]);
assert_eq!(val.count_ones(), 3 + 2 + 1 + 0);
}
/// Powers of two have exactly one bit.
#[test]
fn powers_of_two() {
for shift in 0..64 {
let val = U256::from_be_limbs([0, 0, 0, 1u64 << shift]);
assert_eq!(val.count_ones(), 1);
}
}
/// Known bit pattern across multiple limbs.
#[test]
fn mixed_pattern() {
let val = U256::from_be_limbs([u64::MAX, 0, u64::MAX, 0]);
assert_eq!(val.count_ones(), 128);
}
}