prysm-pulse/encoding/bytesutil/integers.go
terence 5a66807989
Update to V5 (#13622)
* First take at updating everything to v5

* Patch gRPC gateway to use prysm v5

Fix patch

* Update go ssz

---------

Co-authored-by: Preston Van Loon <pvanloon@offchainlabs.com>
2024-02-15 05:46:47 +00:00

169 lines
4.9 KiB
Go

package bytesutil
import (
"encoding/binary"
"errors"
"fmt"
"math/big"
"github.com/prysmaticlabs/prysm/v5/math"
)
// ToBytes returns integer x to bytes in little-endian format at the specified length.
// Spec defines similar method uint_to_bytes(n: uint) -> bytes, which is equivalent to ToBytes(n, 8).
func ToBytes(x uint64, length int) []byte {
if length < 0 {
length = 0
}
makeLength := length
if length < 8 {
makeLength = 8
}
bytes := make([]byte, makeLength)
binary.LittleEndian.PutUint64(bytes, x)
return bytes[:length]
}
// Bytes1 returns integer x to bytes in little-endian format, x.to_bytes(1, 'little').
func Bytes1(x uint64) []byte {
bytes := make([]byte, 8)
binary.LittleEndian.PutUint64(bytes, x)
return bytes[:1]
}
// Bytes2 returns integer x to bytes in little-endian format, x.to_bytes(2, 'little').
func Bytes2(x uint64) []byte {
bytes := make([]byte, 8)
binary.LittleEndian.PutUint64(bytes, x)
return bytes[:2]
}
// Bytes3 returns integer x to bytes in little-endian format, x.to_bytes(3, 'little').
func Bytes3(x uint64) []byte {
bytes := make([]byte, 8)
binary.LittleEndian.PutUint64(bytes, x)
return bytes[:3]
}
// Bytes4 returns integer x to bytes in little-endian format, x.to_bytes(4, 'little').
func Bytes4(x uint64) []byte {
bytes := make([]byte, 8)
binary.LittleEndian.PutUint64(bytes, x)
return bytes[:4]
}
// Bytes8 returns integer x to bytes in little-endian format, x.to_bytes(8, 'little').
func Bytes8(x uint64) []byte {
bytes := make([]byte, 8)
binary.LittleEndian.PutUint64(bytes, x)
return bytes
}
// Bytes32 returns integer x to bytes in little-endian format, x.to_bytes(32, 'little').
func Bytes32(x uint64) []byte {
bytes := make([]byte, 32)
binary.LittleEndian.PutUint64(bytes, x)
return bytes
}
// FromBytes2 returns an integer which is stored in the little-endian format(2, 'little')
// from a byte array.
func FromBytes2(x []byte) uint16 {
if len(x) < 2 {
return 0
}
return binary.LittleEndian.Uint16(x[:2])
}
// FromBytes4 returns an integer which is stored in the little-endian format(4, 'little')
// from a byte array.
func FromBytes4(x []byte) uint64 {
if len(x) < 4 {
return 0
}
empty4bytes := make([]byte, 4)
return binary.LittleEndian.Uint64(append(x[:4], empty4bytes...))
}
// FromBytes8 returns an integer which is stored in the little-endian format(8, 'little')
// from a byte array.
func FromBytes8(x []byte) uint64 {
if len(x) < 8 {
return 0
}
return binary.LittleEndian.Uint64(x)
}
// ToLowInt64 returns the lowest 8 bytes interpreted as little endian.
func ToLowInt64(x []byte) int64 {
if len(x) < 8 {
return 0
}
// Use the first 8 bytes.
x = x[:8]
return int64(binary.LittleEndian.Uint64(x)) // lint:ignore uintcast -- A negative number might be the expected result.
}
// Uint32ToBytes4 is a convenience method for converting uint32 to a fix
// sized 4 byte array in big endian order. Returns 4 byte array.
func Uint32ToBytes4(i uint32) [4]byte {
buf := make([]byte, 4)
binary.BigEndian.PutUint32(buf, i)
return ToBytes4(buf)
}
// Uint64ToBytesLittleEndian conversion.
func Uint64ToBytesLittleEndian(i uint64) []byte {
buf := make([]byte, 8)
binary.LittleEndian.PutUint64(buf, i)
return buf
}
// Uint64ToBytesLittleEndian32 conversion of a uint64 to a fix
// sized 32 byte array in little endian order. Returns 32 byte array.
func Uint64ToBytesLittleEndian32(i uint64) []byte {
buf := make([]byte, 32)
binary.LittleEndian.PutUint64(buf, i)
return buf
}
// Uint64ToBytesBigEndian conversion.
func Uint64ToBytesBigEndian(i uint64) []byte {
buf := make([]byte, 8)
binary.BigEndian.PutUint64(buf, i)
return buf
}
// BytesToUint64BigEndian conversion. Returns 0 if empty bytes or byte slice with length less
// than 8.
func BytesToUint64BigEndian(b []byte) uint64 {
if len(b) < 8 { // This will panic otherwise.
return 0
}
return binary.BigEndian.Uint64(b)
}
// LittleEndianBytesToBigInt takes bytes of a number stored as little-endian and returns a big integer
func LittleEndianBytesToBigInt(bytes []byte) *big.Int {
// Integers are stored as little-endian, but big.Int expects big-endian. So we need to reverse the byte order before decoding.
return new(big.Int).SetBytes(ReverseByteOrder(bytes))
}
// BigIntToLittleEndianBytes takes a big integer and returns its bytes stored as little-endian
func BigIntToLittleEndianBytes(bigInt *big.Int) []byte {
// big.Int.Bytes() returns bytes in big-endian order, so we need to reverse the byte order
return ReverseByteOrder(bigInt.Bytes())
}
// Uint256ToSSZBytes takes a string representation of uint256 and returns its bytes stored as little-endian
func Uint256ToSSZBytes(num string) ([]byte, error) {
uint256, ok := new(big.Int).SetString(num, 10)
if !ok {
return nil, errors.New("could not parse Uint256")
}
if !math.IsValidUint256(uint256) {
return nil, fmt.Errorf("%s is not a valid Uint256", num)
}
return PadTo(ReverseByteOrder(uint256.Bytes()), 32), nil
}