github.com/hyperledger/burrow@v0.34.5-0.20220512172541-77f09336001d/binary/integer.go (about)

     1  // Copyright Monax Industries Limited
     2  // SPDX-License-Identifier: Apache-2.0
     3  
     4  package binary
     5  
     6  import (
     7  	"math"
     8  	"math/big"
     9  )
    10  
    11  var big1 = big.NewInt(1)
    12  var Big256 = big.NewInt(256)
    13  
    14  // Returns whether a + b would be a uint64 overflow
    15  func IsUint64SumOverflow(a, b uint64) bool {
    16  	return math.MaxUint64-a < b
    17  }
    18  
    19  // Converts a possibly negative big int x into a positive big int encoding a twos complement representation of x
    20  // truncated to 32 bytes
    21  func U256(x *big.Int) *big.Int {
    22  	return ToTwosComplement(x, Word256Bits)
    23  }
    24  
    25  // Interprets a positive big.Int as a 256-bit two's complement signed integer
    26  func S256(x *big.Int) *big.Int {
    27  	return FromTwosComplement(x, Word256Bits)
    28  }
    29  
    30  // Convert a possibly negative big.Int x to a positive big.Int encoded in two's complement
    31  func ToTwosComplement(x *big.Int, n uint) *big.Int {
    32  	// And treats negative arguments a if they were twos complement encoded so we end up with a positive number here
    33  	// with the twos complement bit pattern
    34  	return new(big.Int).And(x, andMask(n))
    35  }
    36  
    37  // Interprets a positive big.Int as a n-bit two's complement signed integer
    38  func FromTwosComplement(x *big.Int, n uint) *big.Int {
    39  	signBit := int(n) - 1
    40  	if x.Bit(signBit) == 0 {
    41  		// Sign bit not set => value (v) is positive
    42  		// x = |v| = v
    43  		return x
    44  	} else {
    45  		// Sign bit set => value (v) is negative
    46  		// x = 2^n - |v|
    47  		b := new(big.Int).Lsh(big1, n)
    48  		// v = -|v| = x - 2^n
    49  		return new(big.Int).Sub(x, b)
    50  	}
    51  }
    52  
    53  // Treats the positive big int x as if it contains an embedded n bit signed integer in its least significant
    54  // bits and extends that sign
    55  func SignExtend(x *big.Int, n uint) *big.Int {
    56  	signBit := n - 1
    57  	// single bit set at sign bit position
    58  	mask := new(big.Int).Lsh(big1, signBit)
    59  	// all bits below sign bit set to 1 all above (including sign bit) set to 0
    60  	mask.Sub(mask, big1)
    61  	if x.Bit(int(signBit)) == 1 {
    62  		// Number represented is negative - set all bits above sign bit (including sign bit)
    63  		return x.Or(x, mask.Not(mask))
    64  	} else {
    65  		// Number represented is positive - clear all bits above sign bit (including sign bit)
    66  		return x.And(x, mask)
    67  	}
    68  }
    69  
    70  // Reverse bytes in-place
    71  func reverse(bs []byte) []byte {
    72  	n := len(bs) - 1
    73  	for i := 0; i < len(bs)/2; i++ {
    74  		bs[i], bs[n-i] = bs[n-i], bs[i]
    75  	}
    76  	return bs
    77  }
    78  
    79  // Note: this function destructively reverses its input slice - pass a copy if the original is used elsewhere
    80  func BigIntFromLittleEndianBytes(bs []byte) *big.Int {
    81  	return new(big.Int).SetBytes(reverse(bs))
    82  }
    83  
    84  func BigIntToLittleEndianBytes(x *big.Int) []byte {
    85  	return reverse(x.Bytes())
    86  }
    87  
    88  func andMask(n uint) *big.Int {
    89  	x := new(big.Int)
    90  	return x.Sub(x.Lsh(big1, n), big1)
    91  }