mirror of
https://github.com/muun/recovery.git
synced 2025-02-24 03:49:13 -05:00
85 lines
2.5 KiB
Go
85 lines
2.5 KiB
Go
|
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
|
||
|
}
|