github.com/aigarnetwork/aigar@v0.0.0-20191115204914-d59a6eb70f8e/common/hexutil/hexutil.go (about) 1 // Copyright 2018 The go-ethereum Authors 2 // Copyright 2019 The go-aigar Authors 3 // This file is part of the go-aigar library. 4 // 5 // The go-aigar library is free software: you can redistribute it and/or modify 6 // it under the terms of the GNU Lesser General Public License as published by 7 // the Free Software Foundation, either version 3 of the License, or 8 // (at your option) any later version. 9 // 10 // The go-aigar library is distributed in the hope that it will be useful, 11 // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 // GNU Lesser General Public License for more details. 14 // 15 // You should have received a copy of the GNU Lesser General Public License 16 // along with the go-aigar library. If not, see <http://www.gnu.org/licenses/>. 17 18 /* 19 Package hexutil implements hex encoding with 0x prefix. 20 This encoding is used by the Ethereum RPC API to transport binary data in JSON payloads. 21 22 Encoding Rules 23 24 All hex data must have prefix "0x". 25 26 For byte slices, the hex data must be of even length. An empty byte slice 27 encodes as "0x". 28 29 Integers are encoded using the least amount of digits (no leading zero digits). Their 30 encoding may be of uneven length. The number zero encodes as "0x0". 31 */ 32 package hexutil 33 34 import ( 35 "encoding/hex" 36 "fmt" 37 "math/big" 38 "strconv" 39 ) 40 41 const uintBits = 32 << (uint64(^uint(0)) >> 63) 42 43 // Errors 44 var ( 45 ErrEmptyString = &decError{"empty hex string"} 46 ErrSyntax = &decError{"invalid hex string"} 47 ErrMissingPrefix = &decError{"hex string without 0x prefix"} 48 ErrOddLength = &decError{"hex string of odd length"} 49 ErrEmptyNumber = &decError{"hex string \"0x\""} 50 ErrLeadingZero = &decError{"hex number with leading zero digits"} 51 ErrUint64Range = &decError{"hex number > 64 bits"} 52 ErrUintRange = &decError{fmt.Sprintf("hex number > %d bits", uintBits)} 53 ErrBig256Range = &decError{"hex number > 256 bits"} 54 ) 55 56 type decError struct{ msg string } 57 58 func (err decError) Error() string { return err.msg } 59 60 // Decode decodes a hex string with 0x prefix. 61 func Decode(input string) ([]byte, error) { 62 if len(input) == 0 { 63 return nil, ErrEmptyString 64 } 65 if !has0xPrefix(input) { 66 return nil, ErrMissingPrefix 67 } 68 b, err := hex.DecodeString(input[2:]) 69 if err != nil { 70 err = mapError(err) 71 } 72 return b, err 73 } 74 75 // MustDecode decodes a hex string with 0x prefix. It panics for invalid input. 76 func MustDecode(input string) []byte { 77 dec, err := Decode(input) 78 if err != nil { 79 panic(err) 80 } 81 return dec 82 } 83 84 // Encode encodes b as a hex string with 0x prefix. 85 func Encode(b []byte) string { 86 enc := make([]byte, len(b)*2+2) 87 copy(enc, "0x") 88 hex.Encode(enc[2:], b) 89 return string(enc) 90 } 91 92 // DecodeUint64 decodes a hex string with 0x prefix as a quantity. 93 func DecodeUint64(input string) (uint64, error) { 94 raw, err := checkNumber(input) 95 if err != nil { 96 return 0, err 97 } 98 dec, err := strconv.ParseUint(raw, 16, 64) 99 if err != nil { 100 err = mapError(err) 101 } 102 return dec, err 103 } 104 105 // MustDecodeUint64 decodes a hex string with 0x prefix as a quantity. 106 // It panics for invalid input. 107 func MustDecodeUint64(input string) uint64 { 108 dec, err := DecodeUint64(input) 109 if err != nil { 110 panic(err) 111 } 112 return dec 113 } 114 115 // EncodeUint64 encodes i as a hex string with 0x prefix. 116 func EncodeUint64(i uint64) string { 117 enc := make([]byte, 2, 10) 118 copy(enc, "0x") 119 return string(strconv.AppendUint(enc, i, 16)) 120 } 121 122 var bigWordNibbles int 123 124 func init() { 125 // This is a weird way to compute the number of nibbles required for big.Word. 126 // The usual way would be to use constant arithmetic but go vet can't handle that. 127 b, _ := new(big.Int).SetString("FFFFFFFFFF", 16) 128 switch len(b.Bits()) { 129 case 1: 130 bigWordNibbles = 16 131 case 2: 132 bigWordNibbles = 8 133 default: 134 panic("weird big.Word size") 135 } 136 } 137 138 // DecodeBig decodes a hex string with 0x prefix as a quantity. 139 // Numbers larger than 256 bits are not accepted. 140 func DecodeBig(input string) (*big.Int, error) { 141 raw, err := checkNumber(input) 142 if err != nil { 143 return nil, err 144 } 145 if len(raw) > 64 { 146 return nil, ErrBig256Range 147 } 148 words := make([]big.Word, len(raw)/bigWordNibbles+1) 149 end := len(raw) 150 for i := range words { 151 start := end - bigWordNibbles 152 if start < 0 { 153 start = 0 154 } 155 for ri := start; ri < end; ri++ { 156 nib := decodeNibble(raw[ri]) 157 if nib == badNibble { 158 return nil, ErrSyntax 159 } 160 words[i] *= 16 161 words[i] += big.Word(nib) 162 } 163 end = start 164 } 165 dec := new(big.Int).SetBits(words) 166 return dec, nil 167 } 168 169 // MustDecodeBig decodes a hex string with 0x prefix as a quantity. 170 // It panics for invalid input. 171 func MustDecodeBig(input string) *big.Int { 172 dec, err := DecodeBig(input) 173 if err != nil { 174 panic(err) 175 } 176 return dec 177 } 178 179 // EncodeBig encodes bigint as a hex string with 0x prefix. 180 // The sign of the integer is ignored. 181 func EncodeBig(bigint *big.Int) string { 182 nbits := bigint.BitLen() 183 if nbits == 0 { 184 return "0x0" 185 } 186 return fmt.Sprintf("%#x", bigint) 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 }