util.go raw

   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