2828
2929#include < cstdint>
3030
31+ #ifdef _MSC_VER
32+ #include < intrin.h> // _umul128 / _udiv128 -- MSVC has no __int128 keyword
33+ #endif
34+
3135namespace dgb ::coin {
3236
37+ // ---------------------------------------------------------------------------
38+ // Portable 128-bit primitives. GCC/Clang express the 64x64->128 multiply,
39+ // 128/64 divide and 64+64 add through unsigned __int128; MSVC has no such
40+ // type, so it uses the x64 intrinsics (_umul128 / _udiv128) that lower to the
41+ // SAME mul/div/add-with-carry instructions. Both branches are bit-identical,
42+ // so the DigiShield boundary vectors are unchanged. Mirrors the portable
43+ // mul128_shift precedent in dgb/share_tracker.hpp.
44+ // ---------------------------------------------------------------------------
45+ namespace detail {
46+
47+ // low 64 of (a*b + add); high 64 written to hi. a*b+add always fits 128 bits.
48+ inline uint64_t mul_add_u128 (uint64_t a, uint64_t b, uint64_t add, uint64_t & hi) {
49+ #ifdef _MSC_VER
50+ uint64_t lo = _umul128 (a, b, &hi);
51+ lo += add;
52+ hi += (lo < add) ? 1u : 0u ; // carry out of the low limb
53+ return lo;
54+ #else
55+ unsigned __int128 p = (unsigned __int128)a * b + add;
56+ hi = (uint64_t )(p >> 64 );
57+ return (uint64_t )p;
58+ #endif
59+ }
60+
61+ // quotient of (hi:lo)/d; remainder written to rem. Requires hi < d (holds for
62+ // schoolbook long division where hi is the running remainder), so the 64-bit
63+ // quotient never overflows.
64+ inline uint64_t div_u128 (uint64_t hi, uint64_t lo, uint64_t d, uint64_t & rem) {
65+ #ifdef _MSC_VER
66+ return _udiv128 (hi, lo, d, &rem);
67+ #else
68+ unsigned __int128 cur = ((unsigned __int128)hi << 64 ) | lo;
69+ rem = (uint64_t )(cur % d);
70+ return (uint64_t )(cur / d);
71+ #endif
72+ }
73+
74+ // low 64 of (a + b + carry_in); carry out (0/1) written to carry_out.
75+ inline uint64_t add_u128 (uint64_t a, uint64_t b, uint64_t carry_in, uint64_t & carry_out) {
76+ #ifdef _MSC_VER
77+ uint64_t s = a + b;
78+ uint64_t c = (s < a) ? 1u : 0u ;
79+ s += carry_in;
80+ c += (s < carry_in) ? 1u : 0u ;
81+ carry_out = c;
82+ return s;
83+ #else
84+ unsigned __int128 s = (unsigned __int128)a + b + carry_in;
85+ carry_out = (uint64_t )(s >> 64 );
86+ return (uint64_t )s;
87+ #endif
88+ }
89+
90+
91+ // ---------------------------------------------------------------------------
92+ // PORTABLE-FORCED reference primitives (the #690 native==portable KAT oracle).
93+ //
94+ // The MSVC branches above route through _umul128 / _udiv128 -- x64 hardware
95+ // instructions that CANNOT be compiled or run on the Linux/macOS CI, so the
96+ // "both branches bit-identical" claim can't be diffed directly there. These
97+ // twins reproduce the SAME two operations (64x64->128 multiply, 128/64 divide)
98+ // in pure 32-bit-limb software -- NO __int128, NO intrinsic -- a genuinely
99+ // INDEPENDENT computation. If the software path equals the native __int128
100+ // path across the DigiShield operand domain on Linux, and the x64
101+ // _umul128/_udiv128 are (by ISA definition) exactly the 64x64->128 product and
102+ // 128/64 quotient this software reproduces, then the MSVC path we cannot run
103+ // here is equal too. Compiled unconditionally on every platform; NEVER
104+ // referenced by the shipping u256 / mul_div_u256 (those stay byte-identical).
105+ // ---------------------------------------------------------------------------
106+
107+ // software 64x64 -> 128 multiply (what _umul128 does in hardware).
108+ inline uint64_t umul128_soft (uint64_t a, uint64_t b, uint64_t & hi) {
109+ const uint64_t a_lo = (uint32_t )a, a_hi = a >> 32 ;
110+ const uint64_t b_lo = (uint32_t )b, b_hi = b >> 32 ;
111+ const uint64_t p0 = a_lo * b_lo;
112+ const uint64_t p1 = a_lo * b_hi;
113+ const uint64_t p2 = a_hi * b_lo;
114+ const uint64_t p3 = a_hi * b_hi;
115+ const uint64_t mid = (p0 >> 32 ) + (uint32_t )p1 + (uint32_t )p2;
116+ hi = p3 + (p1 >> 32 ) + (p2 >> 32 ) + (mid >> 32 );
117+ return (p0 & 0xffffffffULL ) | (mid << 32 );
118+ }
119+
120+ // software 128/64 -> 64 divide (what _udiv128 does in hardware). Requires
121+ // hi < d so the 64-bit quotient never overflows -- the SAME precondition the
122+ // _udiv128 intrinsic imposes. Binary long division from the top bit down; the
123+ // running remainder r is kept < d, and (top:r) is the conceptual 65-bit value
124+ // so d up to 2^64-1 is handled without a wider type.
125+ inline uint64_t udiv128_soft (uint64_t hi, uint64_t lo, uint64_t d, uint64_t & rem) {
126+ uint64_t q = 0 , r = hi; // r < d on entry (precondition)
127+ for (int i = 63 ; i >= 0 ; --i) {
128+ const uint64_t top = r >> 63 ; // bit shifted out of the 64-bit r
129+ r = (r << 1 ) | ((lo >> i) & 1ULL ); // conceptual 65-bit value == (top:r)
130+ if (top || r >= d) { // (top:r) >= d -> subtract, set bit
131+ r -= d; // uint64 wrap yields the true low64
132+ q |= 1ULL << i;
133+ }
134+ }
135+ rem = r;
136+ return q;
137+ }
138+
139+ // Portable-forced twins of the three primitives the shipping u256 uses; each
140+ // mirrors the corresponding MSVC branch above with the intrinsic swapped for
141+ // the software op (add_u128's MSVC branch is already intrinsic-free).
142+ inline uint64_t mul_add_u128_portable (uint64_t a, uint64_t b, uint64_t add, uint64_t & hi) {
143+ uint64_t lo = umul128_soft (a, b, hi);
144+ lo += add;
145+ hi += (lo < add) ? 1u : 0u ;
146+ return lo;
147+ }
148+ inline uint64_t div_u128_portable (uint64_t hi, uint64_t lo, uint64_t d, uint64_t & rem) {
149+ return udiv128_soft (hi, lo, d, rem);
150+ }
151+ inline uint64_t add_u128_portable (uint64_t a, uint64_t b, uint64_t carry_in, uint64_t & carry_out) {
152+ uint64_t s = a + b;
153+ uint64_t c = (s < a) ? 1u : 0u ;
154+ s += carry_in;
155+ c += (s < carry_in) ? 1u : 0u ;
156+ carry_out = c;
157+ return s;
158+ }
159+
160+ } // namespace detail
161+
33162// 256-bit unsigned, little-endian limbs (limb[0] least significant). Only the
34163// operations the DigiShield damped multiply needs: scale-by-u64 (truncating at
35164// 256 bits exactly as arith_uint256::operator*=), divide-by-u64, and compare.
@@ -75,11 +204,11 @@ struct u256 {
75204 // does. This is the divergence point vs a 128/wider proxy.
76205 u256 mul_u64 (uint64_t m) const {
77206 u256 r;
78- unsigned __int128 carry = 0 ;
207+ uint64_t carry = 0 ;
79208 for (int i = 0 ; i < 4 ; ++i) {
80- unsigned __int128 prod = ( unsigned __int128)limb[i] * m + carry ;
81- r.limb [i] = ( uint64_t )prod ;
82- carry = prod >> 64 ;
209+ uint64_t hi ;
210+ r.limb [i] = detail::mul_add_u128 (limb[i], m, carry, hi) ;
211+ carry = hi ;
83212 }
84213 // carry beyond limb[3] dropped -> 256-bit truncation (consensus).
85214 return r;
@@ -89,11 +218,9 @@ struct u256 {
89218 // Schoolbook long division from the most-significant limb down.
90219 u256 div_u64 (uint64_t d) const {
91220 u256 r;
92- unsigned __int128 rem = 0 ;
221+ uint64_t rem = 0 ;
93222 for (int i = 3 ; i >= 0 ; --i) {
94- unsigned __int128 cur = (rem << 64 ) | limb[i];
95- r.limb [i] = (uint64_t )(cur / d);
96- rem = cur % d;
223+ r.limb [i] = detail::div_u128 (rem, limb[i], d, rem);
97224 }
98225 return r;
99226 }
@@ -102,11 +229,9 @@ struct u256 {
102229 // same width discipline as mul_u64). Accumulates the retarget window's
103230 // target sum before the divide-by-count average.
104231 u256& operator +=(const u256& o) {
105- unsigned __int128 carry = 0 ;
232+ uint64_t carry = 0 ;
106233 for (int i = 0 ; i < 4 ; ++i) {
107- unsigned __int128 s = (unsigned __int128)limb[i] + o.limb [i] + carry;
108- limb[i] = (uint64_t )s;
109- carry = s >> 64 ;
234+ limb[i] = detail::add_u128 (limb[i], o.limb [i], carry, carry);
110235 }
111236 return *this ;
112237 }
@@ -130,4 +255,52 @@ inline u256 mul_div_u256(const u256& avg, uint64_t mul, uint64_t div) {
130255 return avg.mul_u64 (mul).div_u64 (div);
131256}
132257
258+
259+ // ---------------------------------------------------------------------------
260+ // PORTABLE-FORCED twin of u256 -- the #690 KAT oracle. Same little-endian limb
261+ // layout and 256-bit truncation discipline, but mul_u64 / div_u64 / operator+=
262+ // route through the software detail::*_portable primitives instead of the
263+ // native __int128 (or MSVC intrinsic) ones. The native==portable guard diffs
264+ // this against u256 on Linux. NOT used by any shipping code path.
265+ // ---------------------------------------------------------------------------
266+ struct u256_portable {
267+ uint64_t limb[4 ] = {0 , 0 , 0 , 0 };
268+
269+ u256_portable () = default ;
270+ explicit u256_portable (const u256& s) { for (int i = 0 ; i < 4 ; ++i) limb[i] = s.limb [i]; }
271+
272+ u256_portable mul_u64 (uint64_t m) const {
273+ u256_portable r;
274+ uint64_t carry = 0 ;
275+ for (int i = 0 ; i < 4 ; ++i) {
276+ uint64_t hi;
277+ r.limb [i] = detail::mul_add_u128_portable (limb[i], m, carry, hi);
278+ carry = hi;
279+ }
280+ return r;
281+ }
282+ u256_portable div_u64 (uint64_t d) const {
283+ u256_portable r;
284+ uint64_t rem = 0 ;
285+ for (int i = 3 ; i >= 0 ; --i)
286+ r.limb [i] = detail::div_u128_portable (rem, limb[i], d, rem);
287+ return r;
288+ }
289+ u256_portable& operator +=(const u256_portable& o) {
290+ uint64_t carry = 0 ;
291+ for (int i = 0 ; i < 4 ; ++i)
292+ limb[i] = detail::add_u128_portable (limb[i], o.limb [i], carry, carry);
293+ return *this ;
294+ }
295+ // BIT-IDENTICAL check against a native u256 (all four limbs).
296+ bool equals (const u256& s) const {
297+ return limb[0 ] == s.limb [0 ] && limb[1 ] == s.limb [1 ]
298+ && limb[2 ] == s.limb [2 ] && limb[3 ] == s.limb [3 ];
299+ }
300+ };
301+
302+ inline u256_portable mul_div_u256_portable (const u256_portable& avg, uint64_t mul, uint64_t div) {
303+ return avg.mul_u64 (mul).div_u64 (div);
304+ }
305+
133306} // namespace dgb::coin
0 commit comments