github.com/mit-dci/lit@v0.0.0-20221102210550-8c3d3b49f2ce/bech32/bech32.go (about) 1 package bech32 2 3 import ( 4 "fmt" 5 "strings" 6 ) 7 8 // charset is the sequence of ascii characters that make up the bech32 9 // alphabet. Each character represents a 5-bit squashed byte. 10 // q = 0b00000, p = 0b00001, z = 0b00010, and so on. 11 const charset = "qpzry9x8gf2tvdw0s3jn54khce6mua7l" 12 13 // inverseCharset is a mapping of 8-bit ascii characters to the charset 14 // positions. Both uppercase and lowercase ascii are mapped to the 5-bit 15 // position values. 16 var inverseCharset = [256]int8{ 17 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 18 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 19 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 20 15, -1, 10, 17, 21, 20, 26, 30, 7, 5, -1, -1, -1, -1, -1, -1, 21 -1, 29, -1, 24, 13, 25, 9, 8, 23, -1, 18, 22, 31, 27, 19, -1, 22 1, 0, 3, 16, 11, 28, 12, 14, 6, 4, 2, -1, -1, -1, -1, -1, 23 -1, 29, -1, 24, 13, 25, 9, 8, 23, -1, 18, 22, 31, 27, 19, -1, 24 1, 0, 3, 16, 11, 28, 12, 14, 6, 4, 2, -1, -1, -1, -1, -1} 25 26 // Bytes8to5 extends a byte slice into a longer, padded byte slice of 5-bit elements 27 // where the high 3 bits are all 0. 28 func Bytes8to5(input []byte) []byte { 29 // no way to triger an error going from 8 to 5 30 output, _ := ByteSquasher(input, 8, 5) 31 return output 32 } 33 34 // Bytes5to8 goes from squashed bytes to full height bytes 35 func Bytes5to8(input []byte) ([]byte, error) { 36 return ByteSquasher(input, 5, 8) 37 } 38 39 // ByteSquasher squashes full-width (8-bit) bytes into "squashed" 5-bit bytes, 40 // and vice versa. It can operate on other widths but in this package only 41 // goes 5 to 8 and back again. It can return an error if the squashed input 42 // you give it isn't actually squashed, or if there is padding (trailing q characters) 43 // when going from 5 to 8 44 func ByteSquasher(input []byte, inputWidth, outputWidth uint32) ([]byte, error) { 45 var bitstash, accumulator uint32 46 var output []byte 47 maxOutputValue := uint32((1 << outputWidth) - 1) 48 for i, c := range input { 49 if c>>inputWidth != 0 { 50 return nil, fmt.Errorf("byte %d (%x) high bits set", i, c) 51 } 52 accumulator = (accumulator << inputWidth) | uint32(c) 53 bitstash += inputWidth 54 for bitstash >= outputWidth { 55 bitstash -= outputWidth 56 output = append(output, 57 byte((accumulator>>bitstash)&maxOutputValue)) 58 } 59 } 60 // pad if going from 8 to 5 61 if inputWidth == 8 && outputWidth == 5 { 62 if bitstash != 0 { 63 output = append(output, 64 byte((accumulator << (outputWidth - bitstash) & maxOutputValue))) 65 } 66 } else if bitstash >= inputWidth || 67 ((accumulator<<(outputWidth-bitstash))&maxOutputValue) != 0 { 68 // no pad from 5 to 8 allowed 69 return nil, fmt.Errorf( 70 "invalid padding from %d to %d bits", inputWidth, outputWidth) 71 } 72 return output, nil 73 } 74 75 // SquashedBytesToString swaps 5-bit bytes with a string of the corresponding letters 76 func SquashedBytesToString(input []byte) (string, error) { 77 var s string 78 for i, c := range input { 79 if c&0xe0 != 0 { 80 return "", fmt.Errorf("high bits set at position %d: %x", i, c) 81 } 82 s += string(charset[c]) 83 } 84 return s, nil 85 } 86 87 // StringToSquashedBytes uses the inverseCharset to switch from the characters 88 // back to 5-bit squashed bytes. 89 func StringToSquashedBytes(input string) ([]byte, error) { 90 b := make([]byte, len(input)) 91 for i, c := range input { 92 if inverseCharset[c] == -1 { 93 return nil, fmt.Errorf("contains invalid character %s", string(c)) 94 } 95 b[i] = byte(inverseCharset[c]) 96 } 97 return b, nil 98 } 99 100 // PolyMod takes a byte slice and returns the 32-bit BCH checksum. 101 // Note that the input bytes to PolyMod need to be squashed to 5-bits tall 102 // before being used in this function. And this function will not error, 103 // but instead return an unusable checksum, if you give it full-height bytes. 104 func PolyMod(values []byte) uint32 { 105 106 // magic generator uint32s 107 gen := []uint32{ 108 0x3b6a57b2, 0x26508e6d, 0x1ea119fa, 0x3d4233dd, 0x2a1462b3, 109 } 110 111 // start with 1 112 chk := uint32(1) 113 114 for _, v := range values { 115 top := chk >> 25 116 chk = (chk&0x1ffffff)<<5 ^ uint32(v) 117 for i, g := range gen { 118 if (top>>uint8(i))&1 == 1 { 119 chk ^= g 120 } 121 } 122 } 123 124 return chk 125 } 126 127 // HRPExpand turns the human redable part into 5bit-bytes for later processing 128 func HRPExpand(input string) []byte { 129 output := make([]byte, (len(input)*2)+1) 130 131 // first half is the input string shifted down 5 bits. 132 // not much is going on there in terms of data / entropy 133 for i, c := range input { 134 output[i] = uint8(c) >> 5 135 } 136 // then there's a 0 byte separator 137 // don't need to set 0 byte in the middle, as it starts out that way 138 139 // second half is the input string, with the top 3 bits zeroed. 140 // most of the data / entropy will live here. 141 for i, c := range input { 142 output[i+len(input)+1] = uint8(c) & 0x1f 143 } 144 return output 145 } 146 147 // create checksum makes a 6-shortbyte checksum from the HRP and data parts 148 func CreateChecksum(hrp string, data []byte) []byte { 149 values := append(HRPExpand(hrp), data...) 150 // put 6 zero bytes on at the end 151 values = append(values, make([]byte, 6)...) 152 //get checksum for whole slice 153 154 // flip the LSB of the checksum data after creating it 155 checksum := PolyMod(values) ^ 1 156 157 for i := 0; i < 6; i++ { 158 // note that this is NOT the same as converting 8 to 5 159 // this is it's own expansion to 6 bytes from 4, chopping 160 // off the MSBs. 161 values[(len(values)-6)+i] = byte(checksum>>(5*(5-uint32(i)))) & 0x1f 162 } 163 164 return values[len(values)-6:] 165 } 166 167 func VerifyChecksum(hrp string, data []byte) bool { 168 values := append(HRPExpand(hrp), data...) 169 checksum := PolyMod(values) 170 // make sure it's 1 (from the LSB flip in CreateChecksum 171 return checksum == 1 172 } 173 174 // Encode takes regular bytes of data, and an hrp prefix, and returns the 175 // bech32 encoded string. It doesn't do any segwit specific encoding. 176 func Encode(hrp string, data []byte) string { 177 fiveData := Bytes8to5(data) 178 return EncodeSquashed(hrp, fiveData) 179 } 180 181 // EncodeSquashed takes the hrp prefix, as well as byte data that has already 182 // been squashed to 5-bits high, and returns the bech32 encoded string. 183 // It does not return an error; if you give it non-squashed data it will return 184 // an empty string. 185 func EncodeSquashed(hrp string, data []byte) string { 186 combined := append(data, CreateChecksum(hrp, data)...) 187 188 // Should be squashed, return empty string if it's not. 189 dataString, err := SquashedBytesToString(combined) 190 if err != nil { 191 return "" 192 } 193 return hrp + "1" + dataString 194 } 195 196 // Decode takes a bech32 encoded string and returns the hrp and the full-height 197 // data. Can error out for various reasons, mostly problems in the string given. 198 // Doesn't do anything segwit specific. 199 func Decode(adr string) (string, []byte, error) { 200 hrp, squashedData, err := DecodeSquashed(adr) 201 if err != nil { 202 return hrp, nil, err 203 } 204 data, err := Bytes5to8(squashedData) 205 if err != nil { 206 return hrp, nil, err 207 } 208 return hrp, data, nil 209 } 210 211 // DecodeSquashed is the same as Decode, but will return squashed 5-bit high 212 // data. 213 func DecodeSquashed(adr string) (string, []byte, error) { 214 215 // make an all lowercase and all uppercase version of the input string 216 lowAdr := strings.ToLower(adr) 217 highAdr := strings.ToUpper(adr) 218 219 // if there's mixed case, that's not OK 220 if adr != lowAdr && adr != highAdr { 221 return "", nil, fmt.Errorf("mixed case address") 222 } 223 224 // default to lowercase 225 adr = lowAdr 226 227 // find the last "1" and split there 228 splitLoc := strings.LastIndex(adr, "1") 229 if splitLoc == -1 { 230 return "", nil, fmt.Errorf("1 separator not present in address") 231 } 232 233 // hrp comes before the split 234 hrp := adr[0:splitLoc] 235 236 // get squashed data 237 data, err := StringToSquashedBytes(adr[splitLoc+1:]) 238 if err != nil { 239 return hrp, nil, err 240 } 241 242 // make sure checksum works 243 sumOK := VerifyChecksum(hrp, data) 244 if !sumOK { 245 return hrp, nil, fmt.Errorf("Checksum invalid") 246 } 247 248 // chop off checksum to return only payload 249 data = data[:len(data)-6] 250 251 return hrp, data, nil 252 } 253 254 // Segwit addresses can't be used in Encode and Decode directly, because the 255 // witness version is special and doesn't get squashed. GetHRP gets the 256 // HRP without checking any validity. 257 func GetHRP(adr string) (string, error) { 258 splitLoc := strings.LastIndex(adr, "1") 259 if splitLoc == -1 { 260 return "", fmt.Errorf("1 separator not present in address") 261 } 262 return adr[0:splitLoc], nil 263 } 264 265 // SegWitAddressEncode takes an hrp and data and gives back a segwit address. 266 // The data that goes in should be the full pkscript from the txout, including the 267 // version byte and the pushdata byte. 268 func SegWitAddressEncode(hrp string, data []byte) (string, error) { 269 270 if len(data) < 4 { 271 return "", fmt.Errorf("data too short (%d bytes)", len(data)) 272 } 273 // first byte is the version number. that shouldn't be more than 274 // 16, so only 4 bits, doesn't need to be squashed 275 version := data[0] 276 // the next byte is the length. make sure it's right 277 length := data[1] 278 279 // the rest of the data is real data and needs to be squashed 280 data = data[2:] 281 282 if int(length) != len(data) { 283 return "", fmt.Errorf( 284 "push byte / payload length mismatch: %d, %d", length, len(data)) 285 } 286 287 // allow alts 288 // if hrp != "bc" && hrp != "tb" { 289 // return "", fmt.Errorf("prefix %s is not bitcoin or testnet", hrp) 290 // } 291 // 1 byte programs are not ok. Also 40 bytes should be enough for anyone. 292 if len(data) < 2 || len(data) > 40 { 293 return "", fmt.Errorf("Data length %d out of bounds", len(data)) 294 } 295 // Better get all your features in soon; only 16 possible script versions. 296 if version > 16 { 297 return "", fmt.Errorf("Invalid witness program version %d", data[0]) 298 } 299 // version 0 scripts can only be 20 bytes (p2wpkh) or 32 bytes (p2wsh) 300 if version == 0 && len(data) != 20 && len(data) != 32 { 301 return "", fmt.Errorf("expect 20 or 32 byte v0 witprog, got %d", len(data)) 302 } 303 304 // squash payload data 305 squashedData := Bytes8to5(data) 306 // prepend version byte 307 squashedData = append([]byte{version}, squashedData...) 308 309 address := EncodeSquashed(hrp, squashedData) 310 311 return address, nil 312 } 313 314 // SegWitAddressDecode takes a segwit address and returns the pkscript that 315 // can go directly into the txout. (includes version byte and data push byte) 316 func SegWitAddressDecode(adr string) ([]byte, error) { 317 _, squashedData, err := DecodeSquashed(adr) 318 if err != nil { 319 return nil, err 320 } 321 // the segwit version byte is directly put into a 5bit squashed byte 322 // since it maxes out at 16, wasting ~1 byte instead of 4. 323 324 version := squashedData[0] 325 data, err := Bytes5to8(squashedData[1:]) 326 if err != nil { 327 return nil, err 328 } 329 // Allow alts 330 // if hrp != "bc" && hrp != "tb" { 331 // return nil, fmt.Errorf("prefix %s is not bitcoin or testnet", hrp) 332 // } 333 if len(data) < 2 || len(data) > 40 { 334 return nil, fmt.Errorf("Data length %d out of bounds", len(data)) 335 } 336 337 if version > 16 { 338 return nil, fmt.Errorf("Invalid witness program version %d", data[0]) 339 } 340 if version == 0 && len(data) != 20 && len(data) != 32 { 341 return nil, fmt.Errorf("expect 20 or 32 byte v0 witprog, got %d", len(data)) 342 } 343 344 // first give version byte, then push length 345 if version > 0 { 346 version |= 0x80 347 } 348 outputScript := append([]byte{version}, byte(len(data))) 349 outputScript = append(outputScript, data...) 350 351 return outputScript, nil 352 } 353 354 // SegWitV0Encode takes an hrp prefix string and a 20 or 32 byte witness program 355 // hash, and turns it into a version 0 address. (it puts the 0 and pushdata in 356 // for you. 357 func SegWitV0Encode(hrp string, data []byte) (string, error) { 358 if len(data) != 20 && len(data) != 32 { 359 return "", fmt.Errorf("Invalid data length %d, expect 20 or 32", len(data)) 360 } 361 script := []byte{0, byte(len(data))} 362 script = append(script, data...) 363 return SegWitAddressEncode(hrp, script) 364 }