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
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
// ---------------- [ File: bitcoin-bigint/src/from_u64.rs ]
crate::ix!();
#[macro_export]
macro_rules! define_baseuint_from_u64 {
($uint_type:ident, $bits:expr, $limbs:expr) => {
impl From<u64> for $uint_type {
fn from(value: u64) -> Self {
let mut ret = Self::default();
ret.pn[0] = (value & 0xffff_ffff) as u32;
if $limbs > 1 {
ret.pn[1] = ((value >> 32) & 0xffff_ffff) as u32;
}
ret
}
}
}
}
#[cfg(test)]
mod base_uint_from_u64_exhaustive_tests {
use super::*;
/// Exhaustive tests for `impl<const BITS: usize> From<u64> for BaseUInt<BITS>`.
/// We'll check 32-bit, 64-bit, and 256-bit variants, plus random coverage.
#[traced_test]
fn test_from_u64_32_bits_edge_cases() {
info!("Testing From<u64> for BaseUInt32 edge cases.");
type U32 = BaseUInt32; // single 32-bit limb
// 1) 0 => should store 0 in pn[0]
let x = U32::from(0u64);
assert_eq!(x.pn[0], 0, "Zero => all bits 0 in a 32-bit container");
// 2) small value => e.g. 0x1234_5678
let a = U32::from(0x1234_5678u64);
debug!("From<u64>: 0x12345678 => pn[0]=0x{:08X}", a.pn[0]);
assert_eq!(a.pn[0], 0x1234_5678);
// 3) large value => e.g. 0xFFFF_FFFF => still fits in 32 bits
let b = U32::from(0xFFFF_FFFFu64);
assert_eq!(b.pn[0], 0xFFFF_FFFF, "Should store the full 32 bits");
// 4) if value > 0xFFFF_FFFF, we only keep low 32 bits => e.g. 0x1_2345_6789AB_CDEF
// => 32 bits => 0xAB_CDEF (lowest 32 bits). That is 0x6789AB_CDEF => parted out => Actually let's pick a simpler example
let c = U32::from(0xAAAABBBB_CCCC_DDDD_u64);
// The 64-bit literal => 0xAAAABBBB_CCCC_DDDD
// Low 32 bits => 0xCCCC_DDDD
debug!("From<u64>: 0xAAAABBBBCCCCDDDD => in 32 bits => pn[0]=0x{:08X}", c.pn[0]);
assert_eq!(c.pn[0], 0xCCCC_DDDD);
info!("32-bit From<u64> edge-case tests passed.");
}
#[traced_test]
fn test_from_u64_64_bits_edge_cases() {
info!("Testing From<u64> for BaseUInt64 edge cases.");
type U64B = BaseUInt64;
// 1) 0 => => [0, 0]
let x = U64B::from(0u64);
assert_eq!(x.pn, [0, 0]);
// 2) small => e.g. 0x1234_5678 => goes to pn[0], pn[1]=0
let a = U64B::from(0x1234_5678u64);
assert_eq!(a.pn[0], 0x1234_5678);
assert_eq!(a.pn[1], 0);
// 3) large => e.g. 0xAAAA_BBBB_CCCC_DDDD => 64 bits
// => pn[0] = 0xCCCC_DDDD, pn[1] = 0xAAAA_BBBB
let b = U64B::from(0xAAAA_BBBB_CCCC_DDDD_u64);
debug!("From<u64>: 0xAAAABBBBCCCCDDDD => pn[0]=0x{:08X}, pn[1]=0x{:08X}", b.pn[0], b.pn[1]);
assert_eq!(b.pn[0], 0xCCCC_DDDD);
assert_eq!(b.pn[1], 0xAAAA_BBBB);
// 4) full 64-bit max => 0xFFFF_FFFF_FFFF_FFFF => => [0xFFFF_FFFF, 0xFFFF_FFFF]
let c = U64B::from(0xFFFF_FFFF_FFFF_FFFFu64);
assert_eq!(c.pn[0], 0xFFFF_FFFF);
assert_eq!(c.pn[1], 0xFFFF_FFFF);
info!("64-bit From<u64> edge-case tests passed.");
}
#[traced_test]
fn test_from_u64_256_bits_edge_cases() {
info!("Testing From<u64> for BaseUInt256 edge cases.");
type U256 = BaseUInt256;
// 1) 0 => all limbs 0
let x = U256::from(0u64);
assert!(x.pn.iter().all(|&limb| limb == 0), "All zero limbs from 0");
// 2) small => e.g. 0x1234_5678 => => pn[0]=0x1234_5678, rest=0
let a = U256::from(0x1234_5678u64);
assert_eq!(a.pn[0], 0x1234_5678);
for i in 1..8 {
assert_eq!(a.pn[i], 0);
}
// 3) large => e.g. 0xAAAABBBBCCCCDDDD => pn[0]=0xCCCCDDDD, pn[1]=0xAAAA_BBBB, rest=0
let b = U256::from(0xAAAABBBB_CCCC_DDDD_u64);
assert_eq!(b.pn[0], 0xCCCC_DDDD);
assert_eq!(b.pn[1], 0xAAAA_BBBB);
for i in 2..8 {
assert_eq!(b.pn[i], 0, "No other limbs should be set");
}
// 4) all bits => 0xFFFF_FFFF_FFFF_FFFF => => pn[0]=0xFFFF_FFFF, pn[1]=0xFFFF_FFFF, rest=0
let c = U256::from(0xFFFF_FFFF_FFFF_FFFFu64);
assert_eq!(c.pn[0], 0xFFFF_FFFF);
assert_eq!(c.pn[1], 0xFFFF_FFFF);
for i in 2..8 {
assert_eq!(c.pn[i], 0);
}
info!("256-bit From<u64> edge-case tests passed.");
}
/// Random coverage for 32, 64, and 256 bits. We'll compare the result's low64 to the original
/// if bits exceed the container, those are truncated for 32 bits but we can still verify partial.
#[traced_test]
fn test_from_u64_random() {
info!("Testing From<u64> random coverage for 32, 64, 256 bits.");
let mut rng = SimpleLCG::new(0xDEAD_BEEF_CAFE_BABE);
// We'll do 50 random 64-bit values, parse them into BaseUInt32, <64>, <256>, then check:
// - For 32 bits, only the low 32 bits match
// - For 64 bits, the entire value is matched
// - For 256 bits, entire value matched plus the rest of limbs=0
for _ in 0..50 {
let val = rng.next_u64();
// For 32 bits => only low 32 bits matter
let x32 = BaseUInt32::from(val);
let x32_low = x32.pn[0];
let expected_32 = (val & 0xFFFF_FFFF) as u32;
assert_eq!(x32_low, expected_32, "32-bit truncated from 0x{:016X}", val);
// For 64 bits => should store entire val
let x64 = BaseUInt64::from(val);
let re64 = ((x64.pn[1] as u64) << 32) | (x64.pn[0] as u64);
assert_eq!(re64, val, "64-bit exact parse mismatch for 0x{:016X}", val);
// For 256 bits => store the entire val in the first two limbs, rest = 0
let x256 = BaseUInt256::from(val);
let re256_low = ((x256.pn[1] as u64) << 32) | (x256.pn[0] as u64);
assert_eq!(re256_low, val, "256-bit parse mismatch for 0x{:016X}", val);
for i in 2..8 {
assert_eq!(x256.pn[i], 0, "Higher limbs should be zero in 256-bit parse from u64");
}
}
info!("Random coverage for From<u64> to 32,64,256 bits done.");
}
}