github.com/piotrnar/gocoin@v0.0.0-20240512203912-faa0448c5e96/lib/others/bech32/segwit.go (about) 1 package bech32 2 3 import ( 4 "bytes" 5 "errors" 6 ) 7 8 // convert_bits returns nil on error. 9 func convert_bits(outbits uint, in []byte, inbits uint, pad bool) []byte { 10 var val uint32 11 var bits uint 12 maxv := uint32(1<<outbits) - 1 13 out := new(bytes.Buffer) 14 for inx := range in { 15 val = (val << inbits) | uint32(in[inx]) 16 bits += inbits 17 for bits >= outbits { 18 bits -= outbits 19 out.WriteByte(byte((val >> bits) & maxv)) 20 } 21 } 22 if pad { 23 if bits != 0 { 24 out.WriteByte(byte((val << (outbits - bits)) & maxv)) 25 } 26 } else if ((val<<(outbits-bits))&maxv) != 0 || bits >= inbits { 27 return nil 28 } 29 return out.Bytes() 30 } 31 32 // SegwitEncode returns an empty string on error. 33 func SegwitEncode(hrp string, witver int, witprog []byte) string { 34 if witver > 16 { 35 return "" 36 } 37 if witver == 0 && len(witprog) != 20 && len(witprog) != 32 { 38 return "" 39 } 40 if len(witprog) < 2 || len(witprog) > 40 { 41 return "" 42 } 43 return Encode(hrp, append([]byte{byte(witver)}, convert_bits(5, witprog, 8, true)...), witver > 0) 44 } 45 46 // SegwitDecode returns (0, nil) on error. 47 func SegwitDecode(hrp, addr string) (witver int, witdata []byte, er error) { 48 hrp_actual, data, bech32m := Decode(addr) 49 if hrp_actual == "" || len(data) == 0 || len(data) > 65 { 50 er = errors.New("BECH32 decode error") 51 return 52 } 53 if hrp != hrp_actual { 54 er = errors.New("HRP mismatch") 55 return 56 } 57 if data[0] > 16 { 58 er = errors.New("WITNESS Version too high") 59 return 60 } 61 if data[0] == 0 && bech32m { 62 er = errors.New("WITNESS using M for Version 0") 63 return 64 } 65 if data[0] != 0 && !bech32m { 66 er = errors.New("WITNESS not using M when needed") 67 return 68 } 69 witdata = convert_bits(8, data[1:], 5, false) 70 if witdata == nil { 71 er = errors.New("ERROR from convert_bits") 72 return 73 } 74 if len(witdata) < 2 || len(witdata) > 40 { 75 er = errors.New("WITNESS data length error") 76 witdata = nil 77 return 78 } 79 if data[0] == 0 && len(witdata) != 20 && len(witdata) != 32 { 80 er = errors.New("WITNESS Version 0 data length error") 81 witdata = nil 82 return 83 } 84 witver = int(data[0]) 85 return 86 }