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