1// Copyright 2016 The go-ethereum Authors
2// This file is part of the go-ethereum library.
3//
4// The go-ethereum library is free software: you can redistribute it and/or modify
5// it under the terms of the GNU Lesser General Public License as published by
6// the Free Software Foundation, either version 3 of the License, or
7// (at your option) any later version.
8//
9// The go-ethereum library is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12// GNU Lesser General Public License for more details.
13//
14// You should have received a copy of the GNU Lesser General Public License
15// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
16
17/*
18Package hexutil implements hex encoding with 0x prefix.
19This encoding is used by the Ethereum RPC API to transport binary data in JSON payloads.
20
21Encoding Rules
22
23All hex data must have prefix "0x".
24
25For byte slices, the hex data must be of even length. An empty byte slice
26encodes as "0x".
27
28Integers are encoded using the least amount of digits (no leading zero digits). Their
29encoding may be of uneven length. The number zero encodes as "0x0".
30*/
31package hexutil
32
33import (
34	"encoding/hex"
35	"fmt"
36	"math/big"
37	"strconv"
38)
39
40const uintBits = 32 << (uint64(^uint(0)) >> 63)
41
42// Errors
43var (
44	ErrEmptyString   = &decError{"empty hex string"}
45	ErrSyntax        = &decError{"invalid hex string"}
46	ErrMissingPrefix = &decError{"hex string without 0x prefix"}
47	ErrOddLength     = &decError{"hex string of odd length"}
48	ErrEmptyNumber   = &decError{"hex string \"0x\""}
49	ErrLeadingZero   = &decError{"hex number with leading zero digits"}
50	ErrUint64Range   = &decError{"hex number > 64 bits"}
51	ErrUintRange     = &decError{fmt.Sprintf("hex number > %d bits", uintBits)}
52	ErrBig256Range   = &decError{"hex number > 256 bits"}
53)
54
55type decError struct{ msg string }
56
57func (err decError) Error() string { return err.msg }
58
59// Decode decodes a hex string with 0x prefix.
60func Decode(input string) ([]byte, error) {
61	if len(input) == 0 {
62		return nil, ErrEmptyString
63	}
64	if !has0xPrefix(input) {
65		return nil, ErrMissingPrefix
66	}
67	b, err := hex.DecodeString(input[2:])
68	if err != nil {
69		err = mapError(err)
70	}
71	return b, err
72}
73
74// MustDecode decodes a hex string with 0x prefix. It panics for invalid input.
75func MustDecode(input string) []byte {
76	dec, err := Decode(input)
77	if err != nil {
78		panic(err)
79	}
80	return dec
81}
82
83// Encode encodes b as a hex string with 0x prefix.
84func Encode(b []byte) string {
85	enc := make([]byte, len(b)*2+2)
86	copy(enc, "0x")
87	hex.Encode(enc[2:], b)
88	return string(enc)
89}
90
91// DecodeUint64 decodes a hex string with 0x prefix as a quantity.
92func DecodeUint64(input string) (uint64, error) {
93	raw, err := checkNumber(input)
94	if err != nil {
95		return 0, err
96	}
97	dec, err := strconv.ParseUint(raw, 16, 64)
98	if err != nil {
99		err = mapError(err)
100	}
101	return dec, err
102}
103
104// MustDecodeUint64 decodes a hex string with 0x prefix as a quantity.
105// It panics for invalid input.
106func MustDecodeUint64(input string) uint64 {
107	dec, err := DecodeUint64(input)
108	if err != nil {
109		panic(err)
110	}
111	return dec
112}
113
114// EncodeUint64 encodes i as a hex string with 0x prefix.
115func EncodeUint64(i uint64) string {
116	enc := make([]byte, 2, 10)
117	copy(enc, "0x")
118	return string(strconv.AppendUint(enc, i, 16))
119}
120
121var bigWordNibbles int
122
123func init() {
124	// This is a weird way to compute the number of nibbles required for big.Word.
125	// The usual way would be to use constant arithmetic but go vet can't handle that.
126	b, _ := new(big.Int).SetString("FFFFFFFFFF", 16)
127	switch len(b.Bits()) {
128	case 1:
129		bigWordNibbles = 16
130	case 2:
131		bigWordNibbles = 8
132	default:
133		panic("weird big.Word size")
134	}
135}
136
137// DecodeBig decodes a hex string with 0x prefix as a quantity.
138// Numbers larger than 256 bits are not accepted.
139func DecodeBig(input string) (*big.Int, error) {
140	raw, err := checkNumber(input)
141	if err != nil {
142		return nil, err
143	}
144	if len(raw) > 64 {
145		return nil, ErrBig256Range
146	}
147	words := make([]big.Word, len(raw)/bigWordNibbles+1)
148	end := len(raw)
149	for i := range words {
150		start := end - bigWordNibbles
151		if start < 0 {
152			start = 0
153		}
154		for ri := start; ri < end; ri++ {
155			nib := decodeNibble(raw[ri])
156			if nib == badNibble {
157				return nil, ErrSyntax
158			}
159			words[i] *= 16
160			words[i] += big.Word(nib)
161		}
162		end = start
163	}
164	dec := new(big.Int).SetBits(words)
165	return dec, nil
166}
167
168// MustDecodeBig decodes a hex string with 0x prefix as a quantity.
169// It panics for invalid input.
170func MustDecodeBig(input string) *big.Int {
171	dec, err := DecodeBig(input)
172	if err != nil {
173		panic(err)
174	}
175	return dec
176}
177
178// EncodeBig encodes bigint as a hex string with 0x prefix.
179func EncodeBig(bigint *big.Int) string {
180	if sign := bigint.Sign(); sign == 0 {
181		return "0x0"
182	} else if sign > 0 {
183		return "0x" + bigint.Text(16)
184	} else {
185		return "-0x" + bigint.Text(16)[1:]
186	}
187}
188
189func has0xPrefix(input string) bool {
190	return len(input) >= 2 && input[0] == '0' && (input[1] == 'x' || input[1] == 'X')
191}
192
193func checkNumber(input string) (raw string, err error) {
194	if len(input) == 0 {
195		return "", ErrEmptyString
196	}
197	if !has0xPrefix(input) {
198		return "", ErrMissingPrefix
199	}
200	input = input[2:]
201	if len(input) == 0 {
202		return "", ErrEmptyNumber
203	}
204	if len(input) > 1 && input[0] == '0' {
205		return "", ErrLeadingZero
206	}
207	return input, nil
208}
209
210const badNibble = ^uint64(0)
211
212func decodeNibble(in byte) uint64 {
213	switch {
214	case in >= '0' && in <= '9':
215		return uint64(in - '0')
216	case in >= 'A' && in <= 'F':
217		return uint64(in - 'A' + 10)
218	case in >= 'a' && in <= 'f':
219		return uint64(in - 'a' + 10)
220	default:
221		return badNibble
222	}
223}
224
225func mapError(err error) error {
226	if err, ok := err.(*strconv.NumError); ok {
227		switch err.Err {
228		case strconv.ErrRange:
229			return ErrUint64Range
230		case strconv.ErrSyntax:
231			return ErrSyntax
232		}
233	}
234	if _, ok := err.(hex.InvalidByteError); ok {
235		return ErrSyntax
236	}
237	if err == hex.ErrLength {
238		return ErrOddLength
239	}
240	return err
241}
242