github.com/prysmaticlabs/prysm@v1.4.4/shared/bytesutil/bytes.go (about) 1 // Package bytesutil defines helper methods for converting integers to byte slices. 2 package bytesutil 3 4 import ( 5 "encoding/binary" 6 "errors" 7 "math/bits" 8 "regexp" 9 10 types "github.com/prysmaticlabs/eth2-types" 11 ) 12 13 // ToBytes returns integer x to bytes in little-endian format at the specified length. 14 // Spec defines similar method uint_to_bytes(n: uint) -> bytes, which is equivalent to ToBytes(n, 8). 15 func ToBytes(x uint64, length int) []byte { 16 makeLength := length 17 if length < 8 { 18 makeLength = 8 19 } 20 bytes := make([]byte, makeLength) 21 binary.LittleEndian.PutUint64(bytes, x) 22 return bytes[:length] 23 } 24 25 // Bytes1 returns integer x to bytes in little-endian format, x.to_bytes(1, 'little'). 26 func Bytes1(x uint64) []byte { 27 bytes := make([]byte, 8) 28 binary.LittleEndian.PutUint64(bytes, x) 29 return bytes[:1] 30 } 31 32 // Bytes2 returns integer x to bytes in little-endian format, x.to_bytes(2, 'little'). 33 func Bytes2(x uint64) []byte { 34 bytes := make([]byte, 8) 35 binary.LittleEndian.PutUint64(bytes, x) 36 return bytes[:2] 37 } 38 39 // Bytes3 returns integer x to bytes in little-endian format, x.to_bytes(3, 'little'). 40 func Bytes3(x uint64) []byte { 41 bytes := make([]byte, 8) 42 binary.LittleEndian.PutUint64(bytes, x) 43 return bytes[:3] 44 } 45 46 // Bytes4 returns integer x to bytes in little-endian format, x.to_bytes(4, 'little'). 47 func Bytes4(x uint64) []byte { 48 bytes := make([]byte, 8) 49 binary.LittleEndian.PutUint64(bytes, x) 50 return bytes[:4] 51 } 52 53 // Bytes8 returns integer x to bytes in little-endian format, x.to_bytes(8, 'little'). 54 func Bytes8(x uint64) []byte { 55 bytes := make([]byte, 8) 56 binary.LittleEndian.PutUint64(bytes, x) 57 return bytes 58 } 59 60 // Bytes32 returns integer x to bytes in little-endian format, x.to_bytes(32, 'little'). 61 func Bytes32(x uint64) []byte { 62 bytes := make([]byte, 32) 63 binary.LittleEndian.PutUint64(bytes, x) 64 return bytes 65 } 66 67 // FromBytes4 returns an integer which is stored in the little-endian format(4, 'little') 68 // from a byte array. 69 func FromBytes4(x []byte) uint64 { 70 empty4bytes := make([]byte, 4) 71 return binary.LittleEndian.Uint64(append(x[:4], empty4bytes...)) 72 } 73 74 // FromBytes8 returns an integer which is stored in the little-endian format(8, 'little') 75 // from a byte array. 76 func FromBytes8(x []byte) uint64 { 77 return binary.LittleEndian.Uint64(x) 78 } 79 80 // ToBytes4 is a convenience method for converting a byte slice to a fix 81 // sized 4 byte array. This method will truncate the input if it is larger 82 // than 4 bytes. 83 func ToBytes4(x []byte) [4]byte { 84 var y [4]byte 85 copy(y[:], x) 86 return y 87 } 88 89 // ToBytes32 is a convenience method for converting a byte slice to a fix 90 // sized 32 byte array. This method will truncate the input if it is larger 91 // than 32 bytes. 92 func ToBytes32(x []byte) [32]byte { 93 var y [32]byte 94 copy(y[:], x) 95 return y 96 } 97 98 // ToBytes48 is a convenience method for converting a byte slice to a fix 99 // sized 48 byte array. This method will truncate the input if it is larger 100 // than 48 bytes. 101 func ToBytes48(x []byte) [48]byte { 102 var y [48]byte 103 copy(y[:], x) 104 return y 105 } 106 107 // ToBytes64 is a convenience method for converting a byte slice to a fix 108 // sized 64 byte array. This method will truncate the input if it is larger 109 // than 64 bytes. 110 func ToBytes64(x []byte) [64]byte { 111 var y [64]byte 112 copy(y[:], x) 113 return y 114 } 115 116 // ToBool is a convenience method for converting a byte to a bool. 117 // This method will use the first bit of the 0 byte to generate the returned value. 118 func ToBool(x byte) bool { 119 return x&1 == 1 120 } 121 122 // FromBytes2 returns an integer which is stored in the little-endian format(2, 'little') 123 // from a byte array. 124 func FromBytes2(x []byte) uint16 { 125 return binary.LittleEndian.Uint16(x[:2]) 126 } 127 128 // FromBool is a convenience method for converting a bool to a byte. 129 // This method will use the first bit to generate the returned value. 130 func FromBool(x bool) byte { 131 if x { 132 return 1 133 } 134 return 0 135 } 136 137 // FromBytes48 is a convenience method for converting a fixed-size byte array 138 // to a byte slice. 139 func FromBytes48(x [48]byte) []byte { 140 return x[:] 141 } 142 143 // FromBytes48Array is a convenience method for converting an array of 144 // fixed-size byte arrays to an array of byte slices. 145 func FromBytes48Array(x [][48]byte) [][]byte { 146 y := make([][]byte, len(x)) 147 for i := range x { 148 y[i] = x[i][:] 149 } 150 return y 151 } 152 153 // Trunc truncates the byte slices to 6 bytes. 154 func Trunc(x []byte) []byte { 155 if len(x) > 6 { 156 return x[:6] 157 } 158 return x 159 } 160 161 // ToLowInt64 returns the lowest 8 bytes interpreted as little endian. 162 func ToLowInt64(x []byte) int64 { 163 if len(x) > 8 { 164 x = x[:8] 165 } 166 return int64(binary.LittleEndian.Uint64(x)) 167 } 168 169 // SafeCopyBytes will copy and return a non-nil byte array, otherwise it returns nil. 170 func SafeCopyBytes(cp []byte) []byte { 171 if cp != nil { 172 copied := make([]byte, len(cp)) 173 copy(copied, cp) 174 return copied 175 } 176 return nil 177 } 178 179 // Copy2dBytes will copy and return a non-nil 2d byte array, otherwise it returns nil. 180 func Copy2dBytes(ary [][]byte) [][]byte { 181 if ary != nil { 182 copied := make([][]byte, len(ary)) 183 for i, a := range ary { 184 copied[i] = SafeCopyBytes(a) 185 } 186 return copied 187 } 188 return nil 189 } 190 191 // ReverseBytes32Slice will reverse the provided slice's order. 192 func ReverseBytes32Slice(arr [][32]byte) [][32]byte { 193 for i, j := 0, len(arr)-1; i < j; i, j = i+1, j-1 { 194 arr[i], arr[j] = arr[j], arr[i] 195 } 196 return arr 197 } 198 199 // PadTo pads a byte slice to the given size. If the byte slice is larger than the given size, the 200 // original slice is returned. 201 func PadTo(b []byte, size int) []byte { 202 if len(b) > size { 203 return b 204 } 205 return append(b, make([]byte, size-len(b))...) 206 } 207 208 // SetBit sets the index `i` of bitlist `b` to 1. 209 // It grows and returns a longer bitlist with 1 set 210 // if index `i` is out of range. 211 func SetBit(b []byte, i int) []byte { 212 if i >= len(b)*8 { 213 h := (i + (8 - i%8)) / 8 214 b = append(b, make([]byte, h-len(b))...) 215 } 216 217 bit := uint8(1 << (i % 8)) 218 b[i/8] |= bit 219 return b 220 } 221 222 // ClearBit clears the index `i` of bitlist `b`. 223 // Returns the original bitlist if the index `i` 224 // is out of range. 225 func ClearBit(b []byte, i int) []byte { 226 if i >= len(b)*8 { 227 return b 228 } 229 230 bit := uint8(1 << (i % 8)) 231 b[i/8] &^= bit 232 return b 233 } 234 235 // MakeEmptyBitlists returns an empty bitlist with 236 // input size `i`. 237 func MakeEmptyBitlists(i int) []byte { 238 return make([]byte, (i+(8-i%8))/8) 239 } 240 241 // HighestBitIndex returns the index of the highest 242 // bit set from bitlist `b`. 243 func HighestBitIndex(b []byte) (int, error) { 244 if len(b) == 0 { 245 return 0, errors.New("input list can't be empty or nil") 246 } 247 248 for i := len(b) - 1; i >= 0; i-- { 249 if b[i] == 0 { 250 continue 251 } 252 return bits.Len8(b[i]) + (i * 8), nil 253 } 254 255 return 0, nil 256 } 257 258 // HighestBitIndexAt returns the index of the highest 259 // bit set from bitlist `b` that is at `index` (inclusive). 260 func HighestBitIndexAt(b []byte, index int) (int, error) { 261 bLength := len(b) 262 if b == nil || bLength == 0 { 263 return 0, errors.New("input list can't be empty or nil") 264 } 265 266 start := index / 8 267 if start >= bLength { 268 start = bLength - 1 269 } 270 271 mask := byte(1<<(index%8) - 1) 272 for i := start; i >= 0; i-- { 273 if index/8 > i { 274 mask = 0xff 275 } 276 masked := b[i] & mask 277 minBitsMasked := bits.Len8(masked) 278 if b[i] == 0 || (minBitsMasked == 0 && index/8 <= i) { 279 continue 280 } 281 282 return minBitsMasked + (i * 8), nil 283 } 284 285 return 0, nil 286 } 287 288 // Uint64ToBytesLittleEndian conversion. 289 func Uint64ToBytesLittleEndian(i uint64) []byte { 290 buf := make([]byte, 8) 291 binary.LittleEndian.PutUint64(buf, i) 292 return buf 293 } 294 295 // Uint64ToBytesBigEndian conversion. 296 func Uint64ToBytesBigEndian(i uint64) []byte { 297 buf := make([]byte, 8) 298 binary.BigEndian.PutUint64(buf, i) 299 return buf 300 } 301 302 // BytesToUint64BigEndian conversion. Returns 0 if empty bytes or byte slice with length less 303 // than 8. 304 func BytesToUint64BigEndian(b []byte) uint64 { 305 if len(b) < 8 { // This will panic otherwise. 306 return 0 307 } 308 return binary.BigEndian.Uint64(b) 309 } 310 311 // EpochToBytesLittleEndian conversion. 312 func EpochToBytesLittleEndian(i types.Epoch) []byte { 313 return Uint64ToBytesLittleEndian(uint64(i)) 314 } 315 316 // EpochToBytesBigEndian conversion. 317 func EpochToBytesBigEndian(i types.Epoch) []byte { 318 return Uint64ToBytesBigEndian(uint64(i)) 319 } 320 321 // BytesToEpochBigEndian conversion. 322 func BytesToEpochBigEndian(b []byte) types.Epoch { 323 return types.Epoch(BytesToUint64BigEndian(b)) 324 } 325 326 // SlotToBytesBigEndian conversion. 327 func SlotToBytesBigEndian(i types.Slot) []byte { 328 return Uint64ToBytesBigEndian(uint64(i)) 329 } 330 331 // BytesToSlotBigEndian conversion. 332 func BytesToSlotBigEndian(b []byte) types.Slot { 333 return types.Slot(BytesToUint64BigEndian(b)) 334 } 335 336 // IsHex checks whether the byte array is a hex number prefixed with '0x'. 337 func IsHex(b []byte) (bool, error) { 338 if b == nil { 339 return false, nil 340 } 341 return regexp.Match("^(0x)[0-9a-fA-F]+$", b) 342 }