| 
									
										
										
										
											2016-09-15 02:57:48 +02:00
										 |  |  | // 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) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-06-14 02:52:50 -07:00
										 |  |  | // Errors | 
					
						
							| 
									
										
										
										
											2016-09-15 02:57:48 +02:00
										 |  |  | var ( | 
					
						
							| 
									
										
										
										
											2017-06-23 10:50:49 +02:00
										 |  |  | 	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"} | 
					
						
							| 
									
										
										
										
											2016-09-15 02:57:48 +02:00
										 |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-06-23 10:50:49 +02:00
										 |  |  | type decError struct{ msg string } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-11-10 18:06:45 +01:00
										 |  |  | func (err decError) Error() string { return err.msg } | 
					
						
							| 
									
										
										
										
											2017-06-23 10:50:49 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-15 02:57:48 +02:00
										 |  |  | // 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 | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-02-22 17:55:04 +01:00
										 |  |  | 	b, err := hex.DecodeString(input[2:]) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		err = mapError(err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return b, err | 
					
						
							| 
									
										
										
										
											2016-09-15 02:57:48 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // 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. | 
					
						
							| 
									
										
										
										
											2017-02-22 17:35:11 +01:00
										 |  |  | // Numbers larger than 256 bits are not accepted. | 
					
						
							| 
									
										
										
										
											2016-09-15 02:57:48 +02:00
										 |  |  | func DecodeBig(input string) (*big.Int, error) { | 
					
						
							|  |  |  | 	raw, err := checkNumber(input) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return nil, err | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-02-22 17:35:11 +01:00
										 |  |  | 	if len(raw) > 64 { | 
					
						
							|  |  |  | 		return nil, ErrBig256Range | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-09-15 02:57:48 +02:00
										 |  |  | 	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" | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-02-26 19:40:33 +01:00
										 |  |  | 	return fmt.Sprintf("%#x", bigint) | 
					
						
							| 
									
										
										
										
											2016-09-15 02:57:48 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 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 | 
					
						
							|  |  |  | } |