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 }