diff --git a/src/cryptonote_core/difficulty.cpp b/src/cryptonote_core/difficulty.cpp index 10652044..6486d812 100644 --- a/src/cryptonote_core/difficulty.cpp +++ b/src/cryptonote_core/difficulty.cpp @@ -56,10 +56,40 @@ namespace cryptonote { #else static inline void mul(uint64_t a, uint64_t b, uint64_t &low, uint64_t &high) { - typedef unsigned __int128 uint128_t; - uint128_t res = (uint128_t) a * (uint128_t) b; - low = (uint64_t) res; - high = (uint64_t) (res >> 64); + // __int128 isn't part of the standard, so the previous function wasn't portable. mul128() in Windows is fine, + // but this portable function should be used elsewhere. Credit for this function goes to latexi95. + + uint64_t aLow = a & 0xFFFFFFFF; + uint64_t aHigh = a >> 32; + uint64_t bLow = b & 0xFFFFFFFF; + uint64_t bHigh = b >> 32; + + uint64_t res = aLow * bLow; + uint64_t lowRes1 = res & 0xFFFFFFFF; + uint64_t carry = res >> 32; + + res = aHigh * bLow + carry; + uint64_t highResHigh1 = res >> 32; + uint64_t highResLow1 = res & 0xFFFFFFFF; + + res = aLow * bHigh; + uint64_t lowRes2 = res & 0xFFFFFFFF; + carry = res >> 32; + + res = aHigh * bHigh + carry; + uint64_t highResHigh2 = res >> 32; + uint64_t highResLow2 = res & 0xFFFFFFFF; + + //Addition + + uint64_t r = highResLow1 + lowRes2; + carry = r >> 32; + low = (r << 32) | lowRes1; + r = highResHigh1 + highResLow2 + carry; + uint64_t d3 = r & 0xFFFFFFFF; + carry = r >> 32; + r = highResHigh2 + carry; + high = d3 | (r << 32); } #endif