package btcutilw import ( "bytes" "fmt" "github.com/muun/libwallet/btcsuitew/bech32m" ) // ------------------------------------------------------------------------------------------------- // Methods below copied from btcd (address.go), but using our bech32m module instead of their bech32. // Only that change was made. Some comments inside this code are not correct. func encodeSegWitAddressV1(hrp string, witnessVersion byte, witnessProgram []byte) (string, error) { // Group the address bytes into 5 bit groups, as this is what is used to // encode each character in the address string. converted, err := bech32m.ConvertBits(witnessProgram, 8, 5, true) if err != nil { return "", err } // Concatenate the witness version and program, and encode the resulting // bytes using bech32 encoding. combined := make([]byte, len(converted)+1) combined[0] = witnessVersion copy(combined[1:], converted) bech, err := bech32m.Encode(hrp, combined) if err != nil { return "", err } // Check validity by decoding the created address. version, program, err := decodeSegWitAddressV1(bech) if err != nil { return "", fmt.Errorf("invalid taproot address: %v", err) } if version != witnessVersion || !bytes.Equal(program, witnessProgram) { return "", fmt.Errorf("invalid taproot address") } return bech, nil } func decodeSegWitAddressV1(address string) (byte, []byte, error) { // Decode the bech32 encoded address. _, data, err := bech32m.Decode(address) if err != nil { return 0, nil, err } // The first byte of the decoded address is the witness version, it must // exist. if len(data) < 1 { return 0, nil, fmt.Errorf("no witness version") } // ...and be <= 16. version := data[0] if version > 16 { return 0, nil, fmt.Errorf("invalid witness version for taproot: %v", version) } // The remaining characters of the address returned are grouped into // words of 5 bits. In order to restore the original witness program // bytes, we'll need to regroup into 8 bit words. regrouped, err := bech32m.ConvertBits(data[1:], 5, 8, false) if err != nil { return 0, nil, err } // The regrouped data must be between 2 and 40 bytes. if len(regrouped) < 2 || len(regrouped) > 40 { return 0, nil, fmt.Errorf("invalid data length") } // For witness version 0, address MUST be exactly 20 or 32 bytes. if version == 0 && len(regrouped) != 20 && len(regrouped) != 32 { return 0, nil, fmt.Errorf("invalid data length for witness "+ "version 0: %v", len(regrouped)) } return version, regrouped, nil }