github.com/aquanetwork/aquachain@v1.7.8/common/hexutil/hexutil.go (about)

     1  // Copyright 2016 The aquachain Authors
     2  // This file is part of the aquachain library.
     3  //
     4  // The aquachain 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 aquachain 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 aquachain 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 AquaChain 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  	"fmt"
    36  	"math/big"
    37  	"strconv"
    38  )
    39  
    40  const uintBits = 32 << (uint64(^uint(0)) >> 63)
    41  
    42  var (
    43  	ErrEmptyString   = &decError{"empty hex string"}
    44  	ErrSyntax        = &decError{"invalid hex string"}
    45  	ErrMissingPrefix = &decError{"hex string without 0x prefix"}
    46  	ErrOddLength     = &decError{"hex string of odd length"}
    47  	ErrEmptyNumber   = &decError{"hex string \"0x\""}
    48  	ErrLeadingZero   = &decError{"hex number with leading zero digits"}
    49  	ErrUint64Range   = &decError{"hex number > 64 bits"}
    50  	ErrUintRange     = &decError{fmt.Sprintf("hex number > %d bits", uintBits)}
    51  	ErrBig256Range   = &decError{"hex number > 256 bits"}
    52  )
    53  
    54  type decError struct{ msg string }
    55  
    56  func (err decError) Error() string { return err.msg }
    57  
    58  // Decode decodes a hex string with 0x prefix.
    59  func Decode(input string) ([]byte, error) {
    60  	if len(input) == 0 {
    61  		return nil, ErrEmptyString
    62  	}
    63  	if !has0xPrefix(input) {
    64  		return nil, ErrMissingPrefix
    65  	}
    66  	b, err := hex.DecodeString(input[2:])
    67  	if err != nil {
    68  		err = mapError(err)
    69  	}
    70  	return b, err
    71  }
    72  
    73  // MustDecode decodes a hex string with 0x prefix. It panics for invalid input.
    74  func MustDecode(input string) []byte {
    75  	dec, err := Decode(input)
    76  	if err != nil {
    77  		panic(err)
    78  	}
    79  	return dec
    80  }
    81  
    82  // Encode encodes b as a hex string with 0x prefix.
    83  func Encode(b []byte) string {
    84  	enc := make([]byte, len(b)*2+2)
    85  	copy(enc, "0x")
    86  	hex.Encode(enc[2:], b)
    87  	return string(enc)
    88  }
    89  
    90  // DecodeUint64 decodes a hex string with 0x prefix as a quantity.
    91  func DecodeUint64(input string) (uint64, error) {
    92  	raw, err := checkNumber(input)
    93  	if err != nil {
    94  		return 0, err
    95  	}
    96  	dec, err := strconv.ParseUint(raw, 16, 64)
    97  	if err != nil {
    98  		err = mapError(err)
    99  	}
   100  	return dec, err
   101  }
   102  
   103  // MustDecodeUint64 decodes a hex string with 0x prefix as a quantity.
   104  // It panics for invalid input.
   105  func MustDecodeUint64(input string) uint64 {
   106  	dec, err := DecodeUint64(input)
   107  	if err != nil {
   108  		panic(err)
   109  	}
   110  	return dec
   111  }
   112  
   113  // EncodeUint64 encodes i as a hex string with 0x prefix.
   114  func EncodeUint64(i uint64) string {
   115  	enc := make([]byte, 2, 10)
   116  	copy(enc, "0x")
   117  	return string(strconv.AppendUint(enc, i, 16))
   118  }
   119  
   120  var bigWordNibbles int
   121  
   122  func init() {
   123  	// This is a weird way to compute the number of nibbles required for big.Word.
   124  	// The usual way would be to use constant arithmetic but go vet can't handle that.
   125  	b, _ := new(big.Int).SetString("FFFFFFFFFF", 16)
   126  	switch len(b.Bits()) {
   127  	case 1:
   128  		bigWordNibbles = 16
   129  	case 2:
   130  		bigWordNibbles = 8
   131  	default:
   132  		panic("weird big.Word size")
   133  	}
   134  }
   135  
   136  // DecodeBig decodes a hex string with 0x prefix as a quantity.
   137  // Numbers larger than 256 bits are not accepted.
   138  func DecodeBig(input string) (*big.Int, error) {
   139  	raw, err := checkNumber(input)
   140  	if err != nil {
   141  		return nil, err
   142  	}
   143  	if len(raw) > 64 {
   144  		return nil, ErrBig256Range
   145  	}
   146  	words := make([]big.Word, len(raw)/bigWordNibbles+1)
   147  	end := len(raw)
   148  	for i := range words {
   149  		start := end - bigWordNibbles
   150  		if start < 0 {
   151  			start = 0
   152  		}
   153  		for ri := start; ri < end; ri++ {
   154  			nib := decodeNibble(raw[ri])
   155  			if nib == badNibble {
   156  				return nil, ErrSyntax
   157  			}
   158  			words[i] *= 16
   159  			words[i] += big.Word(nib)
   160  		}
   161  		end = start
   162  	}
   163  	dec := new(big.Int).SetBits(words)
   164  	return dec, nil
   165  }
   166  
   167  // MustDecodeBig decodes a hex string with 0x prefix as a quantity.
   168  // It panics for invalid input.
   169  func MustDecodeBig(input string) *big.Int {
   170  	dec, err := DecodeBig(input)
   171  	if err != nil {
   172  		panic(err)
   173  	}
   174  	return dec
   175  }
   176  
   177  // EncodeBig encodes bigint as a hex string with 0x prefix.
   178  // The sign of the integer is ignored.
   179  func EncodeBig(bigint *big.Int) string {
   180  	nbits := bigint.BitLen()
   181  	if nbits == 0 {
   182  		return "0x0"
   183  	}
   184  	return fmt.Sprintf("%#x", bigint)
   185  }
   186  
   187  func has0xPrefix(input string) bool {
   188  	return len(input) >= 2 && input[0] == '0' && (input[1] == 'x' || input[1] == 'X')
   189  }
   190  
   191  func checkNumber(input string) (raw string, err error) {
   192  	if len(input) == 0 {
   193  		return "", ErrEmptyString
   194  	}
   195  	if !has0xPrefix(input) {
   196  		return "", ErrMissingPrefix
   197  	}
   198  	input = input[2:]
   199  	if len(input) == 0 {
   200  		return "", ErrEmptyNumber
   201  	}
   202  	if len(input) > 1 && input[0] == '0' {
   203  		return "", ErrLeadingZero
   204  	}
   205  	return input, nil
   206  }
   207  
   208  const badNibble = ^uint64(0)
   209  
   210  func decodeNibble(in byte) uint64 {
   211  	switch {
   212  	case in >= '0' && in <= '9':
   213  		return uint64(in - '0')
   214  	case in >= 'A' && in <= 'F':
   215  		return uint64(in - 'A' + 10)
   216  	case in >= 'a' && in <= 'f':
   217  		return uint64(in - 'a' + 10)
   218  	default:
   219  		return badNibble
   220  	}
   221  }
   222  
   223  func mapError(err error) error {
   224  	if err, ok := err.(*strconv.NumError); ok {
   225  		switch err.Err {
   226  		case strconv.ErrRange:
   227  			return ErrUint64Range
   228  		case strconv.ErrSyntax:
   229  			return ErrSyntax
   230  		}
   231  	}
   232  	if _, ok := err.(hex.InvalidByteError); ok {
   233  		return ErrSyntax
   234  	}
   235  	if err == hex.ErrLength {
   236  		return ErrOddLength
   237  	}
   238  	return err
   239  }