There are 3 representations of the same thing (with varying degrees of precision) in Bitcoin:
- bits - unsigned int 32-bit
- target - unsigned int 256-bit
- difficulty - double-precision float (64-bit)
and 6 methods are necessary to convert between any two of these:
- bits -> target (
SetCompact()
in bitcoin/src/arith_uint256.cpp
)
- bits -> difficulty (
GetDifficulty()
in bitcoin/src/rpc/blockchain.cpp
)
- target -> bits (
GetCompact()
in bitcoin/src/arith_uint256.cpp
)
- target -> difficulty (same as target -> bits -> difficulty)
- difficulty -> bits (not done in
bitcoin/src
)
- difficulty -> target (same as difficulty -> bits -> target)
The Bitcoin source code can do the conversion from bits -> difficulty as asked in the question, but cannot do the conversion from difficulty -> bits as also asked in the question.
I have written my own implementation of the difficulty -> bits conversion in vanilla Javascript by mimicking the target -> bits conversion where possible, plus some additional checks:
function difficulty2bits(difficulty) {
if (difficulty < 0) throw 'difficulty cannot be negative';
if (!isFinite(difficulty)) throw 'difficulty cannot be infinite';
for (var shiftBytes = 1; true; shiftBytes++) {
var word = (0x00ffff * Math.pow(0x100, shiftBytes)) / difficulty;
if (word >= 0xffff) break;
}
word &= 0xffffff; // convert to int < 0xffffff
var size = 0x1d - shiftBytes;
// the 0x00800000 bit denotes the sign, so if it is already set, divide the
// mantissa by 0x100 and increase the size by a byte
if (word & 0x800000) {
word >>= 8;
size++;
}
if ((word & ~0x007fffff) != 0) throw 'the \'bits\' \'word\' is out of bounds';
if (size > 0xff) throw 'the \'bits\' \'size\' is out of bounds';
var bits = (size << 24) | word;
return bits;
}
It is possible to validate that the above function gives correct answers by doing the following conversion:
bits -> difficulty -> bits
Where bits -> difficulty is done using Bitcoin's GetDifficulty()
and difficulty -> bits is done using difficulty2bits()
above. If we arrive back at the same bits value then the difficulty2bits()
function is correct. The only exception is when (bits & 0x00800000) != 0
, since this means that bits is a negative number, whereas difficulty is always a positive number in Bitcoin.
I have tested the above difficulty2bits()
function and it does return the same result as the original bits value. If you want to do the tests yourself then I have created a live conversion tool on my blog where you can do any of the 6 conversions listed above in real time (I have transcribed Bitcoin's SetCompact()
, GetDifficulty()
and GetCompact()
into Javascript): https://analysis.null.place/how-do-the-bitcoin-mining-algorithms-work/#form7
Note that numbers in Javascript are IEEE 754 double precision - the same precision as the difficulty in the Bitcoin source, so Javascript is as accurate as the Bitcoin source for all bits/difficulty/target conversions. However, to assuage scepticism I have also included the relevant unit tests from Bitcoin's bitcoin/src/test/blockchain_tests.cpp
and bitcoin/src/test/arith_uint256_tests.cpp
files on the blog just below the aforementioned tool - all tests pass.