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  }