/
common.go
265 lines (232 loc) · 6.01 KB
/
common.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
// Copyright 2021 ChainSafe Systems (ON)
// SPDX-License-Identifier: LGPL-3.0-only
package common
import (
"encoding/binary"
"encoding/hex"
"errors"
"fmt"
"io"
"strconv"
"strings"
)
// ErrNoPrefix is returned when trying to convert a hex-encoded string with no 0x prefix
var ErrNoPrefix = errors.New("could not byteify non 0x prefixed string")
// StringToInts turns a string consisting of ints separated by commas into an int array
func StringToInts(in string) (res []int, err error) {
intstrs := strings.Split(in, ",")
for _, intstr := range intstrs {
i, err := strconv.Atoi(intstr)
if err != nil {
return res, err
}
res = append(res, i)
}
return res, nil
}
// StringArrayToBytes turns an array of strings into an array of byte arrays
func StringArrayToBytes(in []string) [][]byte {
b := make([][]byte, len(in))
for i := range in {
b[i] = []byte(in[i])
}
return b
}
// BytesToStringArray turns an array of byte arrays into an array strings
func BytesToStringArray(in [][]byte) []string {
strs := make([]string, len(in))
for i := range in {
strs[i] = string(in[i])
}
return strs
}
// HexToBytes turns a 0x prefixed hex string into a byte slice
func HexToBytes(in string) (b []byte, err error) {
if !strings.HasPrefix(in, "0x") {
return nil, fmt.Errorf("%w: %s", ErrNoPrefix, in)
}
b, err = hex.DecodeString(in[2:])
if err != nil {
return nil, fmt.Errorf("%w: %s", err, in)
}
return b, nil
}
// MustHexToBytes turns a 0x prefixed hex string into a byte slice
// it panic if it cannot decode the string
func MustHexToBytes(in string) []byte {
if len(in) < 2 {
panic("invalid string")
}
if strings.Compare(in[:2], "0x") != 0 {
panic(ErrNoPrefix)
}
// Ensure we have an even length, otherwise hex.DecodeString will fail and return zero hash
if len(in)%2 != 0 {
panic("cannot decode an odd length string")
}
in = in[2:]
out, err := hex.DecodeString(in)
if err != nil {
panic(err)
}
return out
}
// BytesToHex turns a byte slice into a 0x prefixed hex string
func BytesToHex(in []byte) string {
s := hex.EncodeToString(in)
return "0x" + s
}
// Concat concatenates two byte arrays
// used instead of append to prevent modifying the original byte array
func Concat(s1 []byte, s2 ...byte) []byte {
r := make([]byte, len(s1)+len(s2))
copy(r, s1)
copy(r[len(s1):], s2)
return r
}
// Uint16ToBytes converts a uint16 into a 2-byte slice
func Uint16ToBytes(in uint16) (out []byte) {
out = make([]byte, 2)
out[0] = byte(in & 0x00ff)
out[1] = byte(in >> 8 & 0x00ff)
return out
}
// UintToBytes converts a uint into a Big Endian byte slice
// using a compact number of bytes. This is to imitate
// the big.Int().Bytes() behaviour.
func UintToBytes(n uint) (b []byte) {
b = make([]byte, 0)
for n > 0 {
b = append([]byte{byte(n & 0xFF)}, b...)
n >>= 8
}
return b
}
// UintToHex converts a uint into the hex string representation
// of a Big Endian byte slice using 4 bytes for values that fit
// in a uint32 and in 8 bytes otherwise.
func UintToHex(n uint) (hexString string) {
b := UintToBytes(n)
return BytesToHex(b)
}
// BytesToUint converts a bytes slice in Big Endian compact
// format to a uint. This is to imitate the
// big.NewInt(0).SetBytes(b) behaviour.
func BytesToUint(b []byte) (n uint) {
for i := range b {
byteValue := uint(b[i])
shift := (len(b) - i - 1) * 8
n += byteValue << shift
}
return n
}
// HexToUint converts a hex string of bytes in Big Endian compact
// format to a uint. See BytesToUint for more details.
func HexToUint(hexString string) (n uint, err error) {
b, err := HexToBytes(hexString)
if err != nil {
return 0, err
}
return BytesToUint(b), nil
}
// AppendZeroes appends zeroes to the input byte array up until it has length l
func AppendZeroes(in []byte, l int) []byte {
for {
if len(in) >= l {
return in
}
in = append(in, 0)
}
}
// SwapByteNibbles swaps the two nibbles of a byte
func SwapByteNibbles(b byte) byte {
b1 := (uint(b) & 240) >> 4
b2 := (uint(b) & 15) << 4
return byte(b1 | b2)
}
// SwapNibbles swaps the nibbles for each byte in the byte array
func SwapNibbles(k []byte) []byte {
result := make([]byte, len(k))
for i, b := range k {
result[i] = SwapByteNibbles(b)
}
return result
}
// ReadByte reads a byte from the reader and returns it
func ReadByte(r io.Reader) (byte, error) {
buf := make([]byte, 1)
_, err := r.Read(buf)
if err != nil {
return 0, err
}
return buf[0], nil
}
// Read4Bytes reads 4 bytes from the reader and returns it
func Read4Bytes(r io.Reader) ([]byte, error) {
buf := make([]byte, 4)
_, err := r.Read(buf)
if err != nil {
return nil, err
}
return buf, nil
}
// ReadUint32 reads a 4-byte uint32 from the reader and returns it
func ReadUint32(r io.Reader) (uint32, error) {
buf := make([]byte, 4)
_, err := r.Read(buf)
if err != nil {
return 0, err
}
return binary.LittleEndian.Uint32(buf), nil
}
// ReadUint64 reads an 8-byte uint32 from the reader and returns it
func ReadUint64(r io.Reader) (uint64, error) {
buf := make([]byte, 8)
_, err := r.Read(buf)
if err != nil {
return 0, err
}
return binary.LittleEndian.Uint64(buf), nil
}
// Read8Bytes reads 8 bytes from the reader and returns it
func Read8Bytes(r io.Reader) ([8]byte, error) {
buf := make([]byte, 8)
_, err := r.Read(buf)
if err != nil {
return [8]byte{}, err
}
h := [8]byte{}
copy(h[:], buf)
return h, nil
}
// Read32Bytes reads 32 bytes from the reader and returns it
func Read32Bytes(r io.Reader) ([32]byte, error) {
buf := make([]byte, 32)
_, err := r.Read(buf)
if err != nil {
return [32]byte{}, err
}
h := [32]byte{}
copy(h[:], buf)
return h, nil
}
// Read64Bytes reads 64 bytes from the reader and returns it
func Read64Bytes(r io.Reader) ([64]byte, error) {
buf := make([]byte, 64)
_, err := r.Read(buf)
if err != nil {
return [64]byte{}, err
}
h := [64]byte{}
copy(h[:], buf)
return h, nil
}
// ReadBytes reads the given number bytes from the reader and returns it
func ReadBytes(r io.Reader, n int) ([]byte, error) {
buf := make([]byte, n)
_, err := r.Read(buf)
if err != nil {
return nil, err
}
return buf, nil
}