github.com/digdeepmining/go-atheios@v1.5.13-0.20180902133602-d5687a2e6f43/common/hexutil/hexutil.go (about)

     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  /*
    18  Package hexutil implements hex encoding with 0x prefix.
    19  This encoding is used by the Ethereum RPC API to transport binary data in JSON payloads.
    20  
    21  Encoding Rules
    22  
    23  All hex data must have prefix "0x".
    24  
    25  For byte slices, the hex data must be of even length. An empty byte slice
    26  encodes as "0x".
    27  
    28  Integers are encoded using the least amount of digits (no leading zero digits). Their
    29  encoding may be of uneven length. The number zero encodes as "0x0".
    30  */
    31  package hexutil
    32  
    33  import (
    34  	"encoding/hex"
    35  	"errors"
    36  	"fmt"
    37  	"math/big"
    38  	"strconv"
    39  )
    40  
    41  const uintBits = 32 << (uint64(^uint(0)) >> 63)
    42  
    43  var (
    44  	ErrEmptyString   = errors.New("empty hex string")
    45  	ErrMissingPrefix = errors.New("missing 0x prefix for hex data")
    46  	ErrSyntax        = errors.New("invalid hex")
    47  	ErrEmptyNumber   = errors.New("hex number has no digits after 0x")
    48  	ErrLeadingZero   = errors.New("hex number has leading zero digits after 0x")
    49  	ErrOddLength     = errors.New("hex string has odd length")
    50  	ErrUint64Range   = errors.New("hex number does not fit into 64 bits")
    51  	ErrUintRange     = fmt.Errorf("hex number does not fit into %d bits", uintBits)
    52  )
    53  
    54  // Decode decodes a hex string with 0x prefix.
    55  func Decode(input string) ([]byte, error) {
    56  	if len(input) == 0 {
    57  		return nil, ErrEmptyString
    58  	}
    59  	if !has0xPrefix(input) {
    60  		return nil, ErrMissingPrefix
    61  	}
    62  	return hex.DecodeString(input[2:])
    63  }
    64  
    65  // MustDecode decodes a hex string with 0x prefix. It panics for invalid input.
    66  func MustDecode(input string) []byte {
    67  	dec, err := Decode(input)
    68  	if err != nil {
    69  		panic(err)
    70  	}
    71  	return dec
    72  }
    73  
    74  // Encode encodes b as a hex string with 0x prefix.
    75  func Encode(b []byte) string {
    76  	enc := make([]byte, len(b)*2+2)
    77  	copy(enc, "0x")
    78  	hex.Encode(enc[2:], b)
    79  	return string(enc)
    80  }
    81  
    82  // DecodeUint64 decodes a hex string with 0x prefix as a quantity.
    83  func DecodeUint64(input string) (uint64, error) {
    84  	raw, err := checkNumber(input)
    85  	if err != nil {
    86  		return 0, err
    87  	}
    88  	dec, err := strconv.ParseUint(raw, 16, 64)
    89  	if err != nil {
    90  		err = mapError(err)
    91  	}
    92  	return dec, err
    93  }
    94  
    95  // MustDecodeUint64 decodes a hex string with 0x prefix as a quantity.
    96  // It panics for invalid input.
    97  func MustDecodeUint64(input string) uint64 {
    98  	dec, err := DecodeUint64(input)
    99  	if err != nil {
   100  		panic(err)
   101  	}
   102  	return dec
   103  }
   104  
   105  // EncodeUint64 encodes i as a hex string with 0x prefix.
   106  func EncodeUint64(i uint64) string {
   107  	enc := make([]byte, 2, 10)
   108  	copy(enc, "0x")
   109  	return string(strconv.AppendUint(enc, i, 16))
   110  }
   111  
   112  var bigWordNibbles int
   113  
   114  func init() {
   115  	// This is a weird way to compute the number of nibbles required for big.Word.
   116  	// The usual way would be to use constant arithmetic but go vet can't handle that.
   117  	b, _ := new(big.Int).SetString("FFFFFFFFFF", 16)
   118  	switch len(b.Bits()) {
   119  	case 1:
   120  		bigWordNibbles = 16
   121  	case 2:
   122  		bigWordNibbles = 8
   123  	default:
   124  		panic("weird big.Word size")
   125  	}
   126  }
   127  
   128  // DecodeBig decodes a hex string with 0x prefix as a quantity.
   129  func DecodeBig(input string) (*big.Int, error) {
   130  	raw, err := checkNumber(input)
   131  	if err != nil {
   132  		return nil, err
   133  	}
   134  	words := make([]big.Word, len(raw)/bigWordNibbles+1)
   135  	end := len(raw)
   136  	for i := range words {
   137  		start := end - bigWordNibbles
   138  		if start < 0 {
   139  			start = 0
   140  		}
   141  		for ri := start; ri < end; ri++ {
   142  			nib := decodeNibble(raw[ri])
   143  			if nib == badNibble {
   144  				return nil, ErrSyntax
   145  			}
   146  			words[i] *= 16
   147  			words[i] += big.Word(nib)
   148  		}
   149  		end = start
   150  	}
   151  	dec := new(big.Int).SetBits(words)
   152  	return dec, nil
   153  }
   154  
   155  // MustDecodeBig decodes a hex string with 0x prefix as a quantity.
   156  // It panics for invalid input.
   157  func MustDecodeBig(input string) *big.Int {
   158  	dec, err := DecodeBig(input)
   159  	if err != nil {
   160  		panic(err)
   161  	}
   162  	return dec
   163  }
   164  
   165  // EncodeBig encodes bigint as a hex string with 0x prefix.
   166  // The sign of the integer is ignored.
   167  func EncodeBig(bigint *big.Int) string {
   168  	nbits := bigint.BitLen()
   169  	if nbits == 0 {
   170  		return "0x0"
   171  	}
   172  	return fmt.Sprintf("0x%x", bigint)
   173  }
   174  
   175  func has0xPrefix(input string) bool {
   176  	return len(input) >= 2 && input[0] == '0' && (input[1] == 'x' || input[1] == 'X')
   177  }
   178  
   179  func checkNumber(input string) (raw string, err error) {
   180  	if len(input) == 0 {
   181  		return "", ErrEmptyString
   182  	}
   183  	if !has0xPrefix(input) {
   184  		return "", ErrMissingPrefix
   185  	}
   186  	input = input[2:]
   187  	if len(input) == 0 {
   188  		return "", ErrEmptyNumber
   189  	}
   190  	if len(input) > 1 && input[0] == '0' {
   191  		return "", ErrLeadingZero
   192  	}
   193  	return input, nil
   194  }
   195  
   196  const badNibble = ^uint64(0)
   197  
   198  func decodeNibble(in byte) uint64 {
   199  	switch {
   200  	case in >= '0' && in <= '9':
   201  		return uint64(in - '0')
   202  	case in >= 'A' && in <= 'F':
   203  		return uint64(in - 'A' + 10)
   204  	case in >= 'a' && in <= 'f':
   205  		return uint64(in - 'a' + 10)
   206  	default:
   207  		return badNibble
   208  	}
   209  }
   210  
   211  func mapError(err error) error {
   212  	if err, ok := err.(*strconv.NumError); ok {
   213  		switch err.Err {
   214  		case strconv.ErrRange:
   215  			return ErrUint64Range
   216  		case strconv.ErrSyntax:
   217  			return ErrSyntax
   218  		}
   219  	}
   220  	if _, ok := err.(hex.InvalidByteError); ok {
   221  		return ErrSyntax
   222  	}
   223  	if err == hex.ErrLength {
   224  		return ErrOddLength
   225  	}
   226  	return err
   227  }