main
1package conv
2
3import (
4 "encoding/binary"
5 "fmt"
6 "math/big"
7 "strings"
8
9 "golang.org/x/crypto/cryptobyte"
10)
11
12// BytesLe2Hex returns an hexadecimal string of a number stored in a
13// little-endian order slice x.
14func BytesLe2Hex(x []byte) string {
15 b := &strings.Builder{}
16 b.Grow(2*len(x) + 2)
17 fmt.Fprint(b, "0x")
18 if len(x) == 0 {
19 fmt.Fprint(b, "00")
20 }
21 for i := len(x) - 1; i >= 0; i-- {
22 fmt.Fprintf(b, "%02x", x[i])
23 }
24 return b.String()
25}
26
27// BytesLe2BigInt converts a little-endian slice x into a big-endian
28// math/big.Int.
29func BytesLe2BigInt(x []byte) *big.Int {
30 n := len(x)
31 b := new(big.Int)
32 if len(x) > 0 {
33 y := make([]byte, n)
34 for i := 0; i < n; i++ {
35 y[n-1-i] = x[i]
36 }
37 b.SetBytes(y)
38 }
39 return b
40}
41
42// BytesBe2Uint64Le converts a big-endian slice x to a little-endian slice of uint64.
43func BytesBe2Uint64Le(x []byte) []uint64 {
44 l := len(x)
45 z := make([]uint64, (l+7)/8)
46 blocks := l / 8
47 for i := 0; i < blocks; i++ {
48 z[i] = binary.BigEndian.Uint64(x[l-8*(i+1):])
49 }
50 remBytes := l % 8
51 for i := 0; i < remBytes; i++ {
52 z[blocks] |= uint64(x[l-1-8*blocks-i]) << uint(8*i)
53 }
54 return z
55}
56
57// BigInt2BytesLe stores a positive big.Int number x into a little-endian slice z.
58// The slice is modified if the bitlength of x <= 8*len(z) (padding with zeros).
59// If x does not fit in the slice or is negative, z is not modified.
60func BigInt2BytesLe(z []byte, x *big.Int) {
61 xLen := (x.BitLen() + 7) >> 3
62 zLen := len(z)
63 if zLen >= xLen && x.Sign() >= 0 {
64 y := x.Bytes()
65 for i := 0; i < xLen; i++ {
66 z[i] = y[xLen-1-i]
67 }
68 for i := xLen; i < zLen; i++ {
69 z[i] = 0
70 }
71 }
72}
73
74// Uint64Le2BigInt converts a little-endian slice x into a big number.
75func Uint64Le2BigInt(x []uint64) *big.Int {
76 n := len(x)
77 b := new(big.Int)
78 var bi big.Int
79 for i := n - 1; i >= 0; i-- {
80 bi.SetUint64(x[i])
81 b.Lsh(b, 64)
82 b.Add(b, &bi)
83 }
84 return b
85}
86
87// Uint64Le2BytesLe converts a little-endian slice x to a little-endian slice of bytes.
88func Uint64Le2BytesLe(x []uint64) []byte {
89 b := make([]byte, 8*len(x))
90 n := len(x)
91 for i := 0; i < n; i++ {
92 binary.LittleEndian.PutUint64(b[i*8:], x[i])
93 }
94 return b
95}
96
97// Uint64Le2BytesBe converts a little-endian slice x to a big-endian slice of bytes.
98func Uint64Le2BytesBe(x []uint64) []byte {
99 b := make([]byte, 8*len(x))
100 n := len(x)
101 for i := 0; i < n; i++ {
102 binary.BigEndian.PutUint64(b[i*8:], x[n-1-i])
103 }
104 return b
105}
106
107// Uint64Le2Hex returns an hexadecimal string of a number stored in a
108// little-endian order slice x.
109func Uint64Le2Hex(x []uint64) string {
110 b := new(strings.Builder)
111 b.Grow(16*len(x) + 2)
112 fmt.Fprint(b, "0x")
113 if len(x) == 0 {
114 fmt.Fprint(b, "00")
115 }
116 for i := len(x) - 1; i >= 0; i-- {
117 fmt.Fprintf(b, "%016x", x[i])
118 }
119 return b.String()
120}
121
122// BigInt2Uint64Le stores a positive big.Int number x into a little-endian slice z.
123// The slice is modified if the bitlength of x <= 8*len(z) (padding with zeros).
124// If x does not fit in the slice or is negative, z is not modified.
125func BigInt2Uint64Le(z []uint64, x *big.Int) {
126 xLen := (x.BitLen() + 63) >> 6 // number of 64-bit words
127 zLen := len(z)
128 if zLen >= xLen && x.Sign() > 0 {
129 var y, yi big.Int
130 y.Set(x)
131 two64 := big.NewInt(1)
132 two64.Lsh(two64, 64).Sub(two64, big.NewInt(1))
133 for i := 0; i < xLen; i++ {
134 yi.And(&y, two64)
135 z[i] = yi.Uint64()
136 y.Rsh(&y, 64)
137 }
138 }
139 for i := xLen; i < zLen; i++ {
140 z[i] = 0
141 }
142}
143
144// MarshalBinary encodes a value into a byte array in a format readable by UnmarshalBinary.
145func MarshalBinary(v cryptobyte.MarshalingValue) ([]byte, error) {
146 const DefaultSize = 32
147 b := cryptobyte.NewBuilder(make([]byte, 0, DefaultSize))
148 b.AddValue(v)
149 return b.Bytes()
150}
151
152// MarshalBinaryLen encodes a value into an array of n bytes in a format readable by UnmarshalBinary.
153func MarshalBinaryLen(v cryptobyte.MarshalingValue, length uint) ([]byte, error) {
154 b := cryptobyte.NewFixedBuilder(make([]byte, 0, length))
155 b.AddValue(v)
156 return b.Bytes()
157}
158
159// A UnmarshalingValue decodes itself from a cryptobyte.String and advances the pointer.
160// It reports whether the read was successful.
161type UnmarshalingValue interface {
162 Unmarshal(*cryptobyte.String) bool
163}
164
165// UnmarshalBinary recovers a value from a byte array.
166// It returns an error if the read was unsuccessful.
167func UnmarshalBinary(v UnmarshalingValue, data []byte) (err error) {
168 s := cryptobyte.String(data)
169 if data == nil || !v.Unmarshal(&s) || !s.Empty() {
170 err = fmt.Errorf("cannot read %T from input string", v)
171 }
172 return
173}