123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240 |
- // Copyright 2016 The go-ethereum Authors
- // This file is part of the go-ethereum library.
- //
- // The go-ethereum library is free software: you can redistribute it and/or modify
- // it under the terms of the GNU Lesser General Public License as published by
- // the Free Software Foundation, either version 3 of the License, or
- // (at your option) any later version.
- //
- // The go-ethereum library is distributed in the hope that it will be useful,
- // but WITHOUT ANY WARRANTY; without even the implied warranty of
- // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- // GNU Lesser General Public License for more details.
- //
- // You should have received a copy of the GNU Lesser General Public License
- // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
- /*
- Package hexutil implements hex encoding with 0x prefix.
- This encoding is used by the Ethereum RPC API to transport binary data in JSON payloads.
- Encoding Rules
- All hex data must have prefix "0x".
- For byte slices, the hex data must be of even length. An empty byte slice
- encodes as "0x".
- Integers are encoded using the least amount of digits (no leading zero digits). Their
- encoding may be of uneven length. The number zero encodes as "0x0".
- */
- package hexutil
- import (
- "encoding/hex"
- "fmt"
- "math/big"
- "strconv"
- )
- const uintBits = 32 << (uint64(^uint(0)) >> 63)
- // Errors
- var (
- ErrEmptyString = &decError{"empty hex string"}
- ErrSyntax = &decError{"invalid hex string"}
- ErrMissingPrefix = &decError{"hex string without 0x prefix"}
- ErrOddLength = &decError{"hex string of odd length"}
- ErrEmptyNumber = &decError{"hex string \"0x\""}
- ErrLeadingZero = &decError{"hex number with leading zero digits"}
- ErrUint64Range = &decError{"hex number > 64 bits"}
- ErrUintRange = &decError{fmt.Sprintf("hex number > %d bits", uintBits)}
- ErrBig256Range = &decError{"hex number > 256 bits"}
- )
- type decError struct{ msg string }
- func (err decError) Error() string { return err.msg }
- // Decode decodes a hex string with 0x prefix.
- func Decode(input string) ([]byte, error) {
- if len(input) == 0 {
- return nil, ErrEmptyString
- }
- if !has0xPrefix(input) {
- return nil, ErrMissingPrefix
- }
- b, err := hex.DecodeString(input[2:])
- if err != nil {
- err = mapError(err)
- }
- return b, err
- }
- // MustDecode decodes a hex string with 0x prefix. It panics for invalid input.
- func MustDecode(input string) []byte {
- dec, err := Decode(input)
- if err != nil {
- panic(err)
- }
- return dec
- }
- // Encode encodes b as a hex string with 0x prefix.
- func Encode(b []byte) string {
- enc := make([]byte, len(b)*2+2)
- copy(enc, "0x")
- hex.Encode(enc[2:], b)
- return string(enc)
- }
- // DecodeUint64 decodes a hex string with 0x prefix as a quantity.
- func DecodeUint64(input string) (uint64, error) {
- raw, err := checkNumber(input)
- if err != nil {
- return 0, err
- }
- dec, err := strconv.ParseUint(raw, 16, 64)
- if err != nil {
- err = mapError(err)
- }
- return dec, err
- }
- // MustDecodeUint64 decodes a hex string with 0x prefix as a quantity.
- // It panics for invalid input.
- func MustDecodeUint64(input string) uint64 {
- dec, err := DecodeUint64(input)
- if err != nil {
- panic(err)
- }
- return dec
- }
- // EncodeUint64 encodes i as a hex string with 0x prefix.
- func EncodeUint64(i uint64) string {
- enc := make([]byte, 2, 10)
- copy(enc, "0x")
- return string(strconv.AppendUint(enc, i, 16))
- }
- var bigWordNibbles int
- func init() {
- // This is a weird way to compute the number of nibbles required for big.Word.
- // The usual way would be to use constant arithmetic but go vet can't handle that.
- b, _ := new(big.Int).SetString("FFFFFFFFFF", 16)
- switch len(b.Bits()) {
- case 1:
- bigWordNibbles = 16
- case 2:
- bigWordNibbles = 8
- default:
- panic("weird big.Word size")
- }
- }
- // DecodeBig decodes a hex string with 0x prefix as a quantity.
- // Numbers larger than 256 bits are not accepted.
- func DecodeBig(input string) (*big.Int, error) {
- raw, err := checkNumber(input)
- if err != nil {
- return nil, err
- }
- if len(raw) > 64 {
- return nil, ErrBig256Range
- }
- words := make([]big.Word, len(raw)/bigWordNibbles+1)
- end := len(raw)
- for i := range words {
- start := end - bigWordNibbles
- if start < 0 {
- start = 0
- }
- for ri := start; ri < end; ri++ {
- nib := decodeNibble(raw[ri])
- if nib == badNibble {
- return nil, ErrSyntax
- }
- words[i] *= 16
- words[i] += big.Word(nib)
- }
- end = start
- }
- dec := new(big.Int).SetBits(words)
- return dec, nil
- }
- // MustDecodeBig decodes a hex string with 0x prefix as a quantity.
- // It panics for invalid input.
- func MustDecodeBig(input string) *big.Int {
- dec, err := DecodeBig(input)
- if err != nil {
- panic(err)
- }
- return dec
- }
- // EncodeBig encodes bigint as a hex string with 0x prefix.
- // The sign of the integer is ignored.
- func EncodeBig(bigint *big.Int) string {
- nbits := bigint.BitLen()
- if nbits == 0 {
- return "0x0"
- }
- return fmt.Sprintf("%#x", bigint)
- }
- func has0xPrefix(input string) bool {
- return len(input) >= 2 && input[0] == '0' && (input[1] == 'x' || input[1] == 'X')
- }
- func checkNumber(input string) (raw string, err error) {
- if len(input) == 0 {
- return "", ErrEmptyString
- }
- if !has0xPrefix(input) {
- return "", ErrMissingPrefix
- }
- input = input[2:]
- if len(input) == 0 {
- return "", ErrEmptyNumber
- }
- if len(input) > 1 && input[0] == '0' {
- return "", ErrLeadingZero
- }
- return input, nil
- }
- const badNibble = ^uint64(0)
- func decodeNibble(in byte) uint64 {
- switch {
- case in >= '0' && in <= '9':
- return uint64(in - '0')
- case in >= 'A' && in <= 'F':
- return uint64(in - 'A' + 10)
- case in >= 'a' && in <= 'f':
- return uint64(in - 'a' + 10)
- default:
- return badNibble
- }
- }
- func mapError(err error) error {
- if err, ok := err.(*strconv.NumError); ok {
- switch err.Err {
- case strconv.ErrRange:
- return ErrUint64Range
- case strconv.ErrSyntax:
- return ErrSyntax
- }
- }
- if _, ok := err.(hex.InvalidByteError); ok {
- return ErrSyntax
- }
- if err == hex.ErrLength {
- return ErrOddLength
- }
- return err
- }
|