github.com/sberex/go-sberex@v1.8.2-0.20181113200658-ed96ac38f7d7/common/hexutil/hexutil.go (about)

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