github.com/luckypickle/go-ethereum-vet@v1.14.2/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 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 }