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