main
Raw Download raw file
  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}