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