github.com/amazechain/amc@v0.1.3/common/hexutil/hexutil.go (about)

     1  // Copyright 2023 The AmazeChain Authors
     2  // This file is part of the AmazeChain library.
     3  //
     4  // The AmazeChain 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 AmazeChain 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 AmazeChain 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  	b, err := hex.DecodeString(input[2:])
    68  	if err != nil {
    69  		err = mapError(err)
    70  	}
    71  	return b, err
    72  }
    73  
    74  // MustDecode decodes a hex string with 0x prefix. It panics for invalid input.
    75  func MustDecode(input string) []byte {
    76  	dec, err := Decode(input)
    77  	if err != nil {
    78  		panic(err)
    79  	}
    80  	return dec
    81  }
    82  
    83  // Encode encodes b as a hex string with 0x prefix.
    84  func Encode(b []byte) string {
    85  	enc := make([]byte, len(b)*2+2)
    86  	copy(enc, "0x")
    87  	hex.Encode(enc[2:], b)
    88  	return string(enc)
    89  }
    90  
    91  // DecodeUint64 decodes a hex string with 0x prefix as a quantity.
    92  func DecodeUint64(input string) (uint64, error) {
    93  	raw, err := checkNumber(input)
    94  	if err != nil {
    95  		return 0, err
    96  	}
    97  	dec, err := strconv.ParseUint(raw, 16, 64)
    98  	if err != nil {
    99  		err = mapError(err)
   100  	}
   101  	return dec, err
   102  }
   103  
   104  // MustDecodeUint64 decodes a hex string with 0x prefix as a quantity.
   105  // It panics for invalid input.
   106  func MustDecodeUint64(input string) uint64 {
   107  	dec, err := DecodeUint64(input)
   108  	if err != nil {
   109  		panic(err)
   110  	}
   111  	return dec
   112  }
   113  
   114  // EncodeUint64 encodes i as a hex string with 0x prefix.
   115  func EncodeUint64(i uint64) string {
   116  	enc := make([]byte, 2, 10)
   117  	copy(enc, "0x")
   118  	return string(strconv.AppendUint(enc, i, 16))
   119  }
   120  
   121  var bigWordNibbles int
   122  
   123  func init() {
   124  	// This is a weird way to compute the number of nibbles required for big.Word.
   125  	// The usual way would be to use constant arithmetic but go vet can't handle that.
   126  	b, _ := new(big.Int).SetString("FFFFFFFFFF", 16)
   127  	switch len(b.Bits()) {
   128  	case 1:
   129  		bigWordNibbles = 16
   130  	case 2:
   131  		bigWordNibbles = 8
   132  	default:
   133  		panic("weird big.Word size")
   134  	}
   135  }
   136  
   137  // DecodeBig decodes a hex string with 0x prefix as a quantity.
   138  // Numbers larger than 256 bits are not accepted.
   139  func DecodeBig(input string) (*big.Int, error) {
   140  	raw, err := checkNumber(input)
   141  	if err != nil {
   142  		return nil, err
   143  	}
   144  	if len(raw) > 64 {
   145  		return nil, ErrBig256Range
   146  	}
   147  	words := make([]big.Word, len(raw)/bigWordNibbles+1)
   148  	end := len(raw)
   149  	for i := range words {
   150  		start := end - bigWordNibbles
   151  		if start < 0 {
   152  			start = 0
   153  		}
   154  		for ri := start; ri < end; ri++ {
   155  			nib := decodeNibble(raw[ri])
   156  			if nib == badNibble {
   157  				return nil, ErrSyntax
   158  			}
   159  			words[i] *= 16
   160  			words[i] += big.Word(nib)
   161  		}
   162  		end = start
   163  	}
   164  	dec := new(big.Int).SetBits(words)
   165  	return dec, nil
   166  }
   167  
   168  // MustDecodeBig decodes a hex string with 0x prefix as a quantity.
   169  // It panics for invalid input.
   170  func MustDecodeBig(input string) *big.Int {
   171  	dec, err := DecodeBig(input)
   172  	if err != nil {
   173  		panic(err)
   174  	}
   175  	return dec
   176  }
   177  
   178  // EncodeBig encodes bigint as a hex string with 0x prefix.
   179  // The sign of the integer is ignored.
   180  func EncodeBig(bigint *big.Int) string {
   181  	nbits := bigint.BitLen()
   182  	if nbits == 0 {
   183  		return "0x0"
   184  	}
   185  	return fmt.Sprintf("%#x", bigint)
   186  }
   187  
   188  func has0xPrefix(input string) bool {
   189  	return len(input) >= 2 && input[0] == '0' && (input[1] == 'x' || input[1] == 'X')
   190  }
   191  
   192  func checkNumber(input string) (raw string, err error) {
   193  	if len(input) == 0 {
   194  		return "", ErrEmptyString
   195  	}
   196  	if !has0xPrefix(input) {
   197  		return "", ErrMissingPrefix
   198  	}
   199  	input = input[2:]
   200  	if len(input) == 0 {
   201  		return "", ErrEmptyNumber
   202  	}
   203  	if len(input) > 1 && input[0] == '0' {
   204  		return "", ErrLeadingZero
   205  	}
   206  	return input, nil
   207  }
   208  
   209  const badNibble = ^uint64(0)
   210  
   211  func decodeNibble(in byte) uint64 {
   212  	switch {
   213  	case in >= '0' && in <= '9':
   214  		return uint64(in - '0')
   215  	case in >= 'A' && in <= 'F':
   216  		return uint64(in - 'A' + 10)
   217  	case in >= 'a' && in <= 'f':
   218  		return uint64(in - 'a' + 10)
   219  	default:
   220  		return badNibble
   221  	}
   222  }
   223  
   224  func mapError(err error) error {
   225  	if err, ok := err.(*strconv.NumError); ok {
   226  		switch err.Err {
   227  		case strconv.ErrRange:
   228  			return ErrUint64Range
   229  		case strconv.ErrSyntax:
   230  			return ErrSyntax
   231  		}
   232  	}
   233  	if _, ok := err.(hex.InvalidByteError); ok {
   234  		return ErrSyntax
   235  	}
   236  	if err == hex.ErrLength {
   237  		return ErrOddLength
   238  	}
   239  	return err
   240  }
   241  
   242  // CompressNibbles - supports only even number of nibbles
   243  // This method supports only arrays of even nibbles
   244  //
   245  // HI_NIBBLE(b) = (b >> 4) & 0x0F
   246  // LO_NIBBLE(b) = b & 0x0F
   247  func CompressNibbles(nibbles []byte, out *[]byte) {
   248  	tmp := (*out)[:0]
   249  	for i := 0; i < len(nibbles); i += 2 {
   250  		tmp = append(tmp, nibbles[i]<<4|nibbles[i+1])
   251  	}
   252  	*out = tmp
   253  }
   254  
   255  // DecompressNibbles - supports only even number of nibbles
   256  //
   257  // HI_NIBBLE(b) = (b >> 4) & 0x0F
   258  // LO_NIBBLE(b) = b & 0x0F
   259  func DecompressNibbles(in []byte, out *[]byte) {
   260  	tmp := (*out)[:0]
   261  	for i := 0; i < len(in); i++ {
   262  		tmp = append(tmp, (in[i]>>4)&0x0F, in[i]&0x0F)
   263  	}
   264  	*out = tmp
   265  }