github.com/ethxdao/go-ethereum@v0.0.0-20221218102228-5ae34a9cc189/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 func EncodeBig(bigint *big.Int) string { 180 if sign := bigint.Sign(); sign == 0 { 181 return "0x0" 182 } else if sign > 0 { 183 return "0x" + bigint.Text(16) 184 } else { 185 return "-0x" + bigint.Text(16)[1:] 186 } 187 } 188 189 func has0xPrefix(input string) bool { 190 return len(input) >= 2 && input[0] == '0' && (input[1] == 'x' || input[1] == 'X') 191 } 192 193 func checkNumber(input string) (raw string, err error) { 194 if len(input) == 0 { 195 return "", ErrEmptyString 196 } 197 if !has0xPrefix(input) { 198 return "", ErrMissingPrefix 199 } 200 input = input[2:] 201 if len(input) == 0 { 202 return "", ErrEmptyNumber 203 } 204 if len(input) > 1 && input[0] == '0' { 205 return "", ErrLeadingZero 206 } 207 return input, nil 208 } 209 210 const badNibble = ^uint64(0) 211 212 func decodeNibble(in byte) uint64 { 213 switch { 214 case in >= '0' && in <= '9': 215 return uint64(in - '0') 216 case in >= 'A' && in <= 'F': 217 return uint64(in - 'A' + 10) 218 case in >= 'a' && in <= 'f': 219 return uint64(in - 'a' + 10) 220 default: 221 return badNibble 222 } 223 } 224 225 func mapError(err error) error { 226 if err, ok := err.(*strconv.NumError); ok { 227 switch err.Err { 228 case strconv.ErrRange: 229 return ErrUint64Range 230 case strconv.ErrSyntax: 231 return ErrSyntax 232 } 233 } 234 if _, ok := err.(hex.InvalidByteError); ok { 235 return ErrSyntax 236 } 237 if err == hex.ErrLength { 238 return ErrOddLength 239 } 240 return err 241 }