github.com/aigarnetwork/aigar@v0.0.0-20191115204914-d59a6eb70f8e/common/hexutil/hexutil.go (about)

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