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