1 package bits
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
23 // there really is not a need for a sign bit, but it is implemented here to stay consistent with bitcoind.
24 func CompactToBig(compact uint32) *big.Int {
25 // Extract the mantissa, sign bit, and exponent.
26 mantissa := compact & 0x007fffff
27 isNegative := compact&0x00800000 != 0
28 exponent := uint(compact >> 24)
29 // Since the base for the exponent is 256, the exponent can be treated as the number of bytes to represent the full
30 // 256-bit number. So, treat the exponent as the number of bytes and shift the mantissa right or left accordingly.
31 // This is equivalent to N = mantissa * 256^(exponent-3)
32 var bn *big.Int
33 if exponent <= 3 {
34 mantissa >>= 8 * (3 - exponent)
35 bn = big.NewInt(int64(mantissa))
36 } else {
37 bn = big.NewInt(int64(mantissa))
38 bn.Lsh(bn, 8*(exponent-3))
39 }
40 // Make it negative if the sign bit is set.
41 if isNegative {
42 bn = bn.Neg(bn)
43 }
44 return bn
45 }
46 47 // BigToCompact converts a whole number N to a compact representation using an unsigned 32-bit number. The compact
48 // representation only provides 23 bits of precision, so values larger than (2^23 - 1) only encode the most significant
49 // digits of the number. See CompactToBig for details.
50 func BigToCompact(n *big.Int) uint32 {
51 // No need to do any work if it's zero.
52 if n.Sign() == 0 {
53 return 0
54 }
55 // Since the base for the exponent is 256, the exponent can be treated as the number of bytes. So, shift the number
56 // right or left accordingly. This is equivalent to: mantissa = mantissa / 256^(exponent-3)
57 var mantissa uint32
58 exponent := uint(len(n.Bytes()))
59 if exponent <= 3 {
60 mantissa = uint32(n.Bits()[0])
61 mantissa <<= 8 * (3 - exponent)
62 } else {
63 // Use a copy to avoid modifying the caller's original number.
64 tn := new(big.Int).Set(n)
65 mantissa = uint32(tn.Rsh(tn, 8*(exponent-3)).Bits()[0])
66 }
67 // When the mantissa already has the sign bit set, the number is too large to fit into the available 23-bits, so
68 // divide the number by 256 and increment the exponent accordingly.
69 if mantissa&0x00800000 != 0 {
70 mantissa >>= 8
71 exponent++
72 }
73 // Pack the exponent, sign bit, and mantissa into an unsigned 32-bit int and return it.
74 compact := uint32(exponent<<24) | mantissa
75 if n.Sign() < 0 {
76 compact |= 0x00800000
77 }
78 return compact
79 }
80