1 package chaincfg
2 3 import "math/big"
4 5 // CompactToBig converts a compact representation of a whole number N to an unsigned 32-bit number. The representation
6 // is similar to IEEE754 floating point numbers. Like IEEE754 floating point, there are three basic components: the
7 // sign, the exponent, and the mantissa. They are broken out as follows:
8 //
9 // * the most significant 8 bits represent the unsigned base 256 exponent
10 // * bit 23 (the 24th bit) represents the sign bit
11 // * the least significant 23 bits represent the mantissa
12 // -------------------------------------------------
13 // | Exponent | Sign | Mantissa |
14 // -------------------------------------------------
15 // | 8 bits [31-24] | 1 bit [23] | 23 bits [22-00] |
16 // -------------------------------------------------
17 //
18 // The formula to calculate N is:
19 //
20 // N = (-1^sign) * mantissa * 256^(exponent-3)
21 //
22 // This compact form is only used in bitcoin to encode unsigned 256-bit numbers which represent difficulty targets, thus there really is not a need for a sign bit, but it is implemented here to stay consistent with bitcoind.
23 func CompactToBig(compact uint32) *big.Int {
24 // Extract the mantissa, sign bit, and exponent.
25 mantissa := compact & 0x007fffff
26 isNegative := compact&0x00800000 != 0
27 exponent := uint(compact >> 24)
28 // Since the base for the exponent is 256, the exponent can be treated as the number of bytes to represent the full 256-bit number. So, treat the exponent as the number of bytes and shift the mantissa right or left accordingly. This is equivalent to: N = mantissa * 256^(exponent-3)
29 var bn *big.Int
30 if exponent <= 3 {
31 mantissa >>= 8 * (3 - exponent)
32 bn = big.NewInt(int64(mantissa))
33 } else {
34 bn = big.NewInt(int64(mantissa))
35 bn.Lsh(bn, 8*(exponent-3))
36 }
37 // Make it negative if the sign bit is set.
38 if isNegative {
39 bn = bn.Neg(bn)
40 }
41 return bn
42 }
43 44 // BigToCompact converts a whole number N to a compact representation using an unsigned 32-bit number. The compact
45 // representation only provides 23 bits of precision, so values larger than (2^23 - 1) only encode the most significant
46 // digits of the number. See CompactToBig for details.
47 func BigToCompact(n *big.Int) uint32 {
48 // No need to do any work if it's zero.
49 if n.Sign() == 0 {
50 return 0
51 }
52 // Since the base for the exponent is 256, the exponent can be treated as the number of bytes. So, shift the number
53 // right or left accordingly. This is equivalent to: mantissa = mantissa / 256^(exponent-3)
54 var mantissa uint32
55 exponent := uint(len(n.Bytes()))
56 if exponent <= 3 {
57 mantissa = uint32(n.Bits()[0])
58 mantissa <<= 8 * (3 - exponent)
59 } else {
60 // Use a copy to avoid modifying the caller's original number.
61 tn := new(big.Int).Set(n)
62 mantissa = uint32(tn.Rsh(tn, 8*(exponent-3)).Bits()[0])
63 }
64 // When the mantissa already has the sign bit set, the number is too large to fit into the available 23-bits, so
65 // divide the number by 256 and increment the exponent accordingly.
66 if mantissa&0x00800000 != 0 {
67 mantissa >>= 8
68 exponent++
69 }
70 // Pack the exponent, sign bit, and mantissa into an unsigned 32-bit int and return it.
71 compact := uint32(exponent<<24) | mantissa
72 if n.Sign() < 0 {
73 compact |= 0x00800000
74 }
75 return compact
76 }
77