What changed, and why it matters
This commit is a large code reorganization: it moves the Bitcoin address-handling code into its own top-level Go module and upgrades its internal import path to version 2. The actual address/base58/bech32 logic appears to be copied over largely unchanged, with only minor additions such as a new pay-to-anchor address type. There is no obvious security bug introduced by the move itself, and the commit message does not describe any security fix.
Treat as a routine module refactor. If using the new `address/v2` module, verify that downstream consumers update imports and that the new P2A address type behaves correctly in your integration tests. No urgent security action is required based on this commit alone.
Security signals we found
Large refactor with no security-relevant commit message
New address type added (P2A / pay-to-anchor)
No changes to checksum, length, or validation logic visible in supplied diff
No vendor disclosure or CVE references present
Evidence from the diff
The diff creates a new address/ top-level module under github.com/btcsuite/btcd/address/v2, copying address.go, base58, bech32, tests, and module files from their previous location. Imports are updated to the v2 path. A new AddressPayToAnchor type is added for BIP-anchored outputs. No algorithmic changes to base58/bech32 decoding/encoding are visible in the supplied diff. The change is structural (module split) rather than a security patch.
Changed components
address/address.goaddress/base58address/bech32address/go.modaddress/go.sumInspect captured patch +3940 / −3886
diff --git a/address/address.go b/address/address.go
new file mode 100644
index 0000000..aa24752
--- /dev/null
+++ b/address/address.go
@@ -0,0 +1,801 @@
+// Copyright (c) 2013-2017 The btcsuite developers
+// Use of this source code is governed by an ISC
+// license that can be found in the LICENSE file.
+
+package address
+
+import (
+ "bytes"
+ "encoding/hex"
+ "errors"
+ "fmt"
+ "strings"
+
+ "github.com/btcsuite/btcd/address/v2/base58"
+ "github.com/btcsuite/btcd/address/v2/bech32"
+ "github.com/btcsuite/btcd/btcec/v2"
+ "github.com/btcsuite/btcd/chaincfg/v2"
+ "golang.org/x/crypto/ripemd160"
+)
+
+// UnsupportedWitnessVerError describes an error where a segwit address being
+// decoded has an unsupported witness version.
+type UnsupportedWitnessVerError byte
+
+func (e UnsupportedWitnessVerError) Error() string {
+ return fmt.Sprintf("unsupported witness version: %#x", byte(e))
+}
+
+// UnsupportedWitnessProgLenError describes an error where a segwit address
+// being decoded has an unsupported witness program length.
+type UnsupportedWitnessProgLenError int
+
+func (e UnsupportedWitnessProgLenError) Error() string {
+ return fmt.Sprintf("unsupported witness program length: %d", int(e))
+}
+
+var (
+ // ErrChecksumMismatch describes an error where decoding failed due
+ // to a bad checksum.
+ ErrChecksumMismatch = errors.New("checksum mismatch")
+
+ // ErrUnknownAddressType describes an error where an address can not
+ // decoded as a specific address type due to the string encoding
+ // beginning with an identifier byte unknown to any standard or
+ // registered (via chaincfg.Register) network.
+ ErrUnknownAddressType = errors.New("unknown address type")
+
+ // ErrAddressCollision describes an error where an address can not
+ // be uniquely determined as either a pay-to-pubkey-hash or
+ // pay-to-script-hash address since the leading identifier is used for
+ // describing both address kinds, but for different networks. Rather
+ // than assuming or defaulting to one or the other, this error is
+ // returned and the caller must decide how to decode the address.
+ ErrAddressCollision = errors.New("address collision")
+)
+
+// encodeAddress returns a human-readable payment address given a ripemd160 hash
+// and netID which encodes the bitcoin network and address type. It is used
+// in both pay-to-pubkey-hash (P2PKH) and pay-to-script-hash (P2SH) address
+// encoding.
+func encodeAddress(hash160 []byte, netID byte) string {
+ // Format is 1 byte for a network and address class (i.e. P2PKH vs
+ // P2SH), 20 bytes for a RIPEMD160 hash, and 4 bytes of checksum.
+ return base58.CheckEncode(hash160[:ripemd160.Size], netID)
+}
+
+// encodeSegWitAddress creates a bech32 (or bech32m for SegWit v1) encoded
+// address string representation from witness version and witness program.
+func encodeSegWitAddress(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 := bech32.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)
+
+ var bech string
+ switch witnessVersion {
+ case 0:
+ bech, err = bech32.Encode(hrp, combined)
+
+ case 1:
+ bech, err = bech32.EncodeM(hrp, combined)
+
+ default:
+ return "", fmt.Errorf("unsupported witness version %d",
+ witnessVersion)
+ }
+ if err != nil {
+ return "", err
+ }
+
+ // Check validity by decoding the created address.
+ version, program, err := decodeSegWitAddress(bech)
+ if err != nil {
+ return "", fmt.Errorf("invalid segwit address: %v", err)
+ }
+
+ if version != witnessVersion || !bytes.Equal(program, witnessProgram) {
+ return "", fmt.Errorf("invalid segwit address")
+ }
+
+ return bech, nil
+}
+
+// Address is an interface type for any type of destination a transaction
+// output may spend to. This includes pay-to-pubkey (P2PK), pay-to-pubkey-hash
+// (P2PKH), and pay-to-script-hash (P2SH). Address is designed to be generic
+// enough that other kinds of addresses may be added in the future without
+// changing the decoding and encoding API.
+type Address interface {
+ // String returns the string encoding of the transaction output
+ // destination.
+ //
+ // Please note that String differs subtly from EncodeAddress: String
+ // will return the value as a string without any conversion, while
+ // EncodeAddress may convert destination types (for example,
+ // converting pubkeys to P2PKH addresses) before encoding as a
+ // payment address string.
+ String() string
+
+ // EncodeAddress returns the string encoding of the payment address
+ // associated with the Address value. See the comment on String
+ // for how this method differs from String.
+ EncodeAddress() string
+
+ // ScriptAddress returns the raw bytes of the address to be used
+ // when inserting the address into a txout's script.
+ ScriptAddress() []byte
+
+ // IsForNet returns whether or not the address is associated with the
+ // passed bitcoin network.
+ IsForNet(*chaincfg.Params) bool
+}
+
+// DecodeAddress decodes the string encoding of an address and returns
+// the Address if addr is a valid encoding for a known address type.
+//
+// The bitcoin network the address is associated with is extracted if possible.
+// When the address does not encode the network, such as in the case of a raw
+// public key, the address will be associated with the passed defaultNet.
+func DecodeAddress(addr string, defaultNet *chaincfg.Params) (Address, error) {
+ // Bech32 encoded segwit addresses start with a human-readable part
+ // (hrp) followed by '1'. For Bitcoin mainnet the hrp is "bc", and for
+ // testnet it is "tb". If the address string has a prefix that matches
+ // one of the prefixes for the known networks, we try to decode it as
+ // a segwit address.
+ oneIndex := strings.LastIndexByte(addr, '1')
+ if oneIndex > 1 {
+ prefix := addr[:oneIndex+1]
+ if chaincfg.IsBech32SegwitPrefix(prefix) {
+ witnessVer, witnessProg, err := decodeSegWitAddress(addr)
+ if err != nil {
+ return nil, err
+ }
+
+ // We currently only support P2WPKH and P2WSH, which is
+ // witness version 0 and P2TR which is witness version
+ // 1.
+ if witnessVer != 0 && witnessVer != 1 {
+ return nil, UnsupportedWitnessVerError(witnessVer)
+ }
+
+ // The HRP is everything before the found '1'.
+ hrp := prefix[:len(prefix)-1]
+
+ switch len(witnessProg) {
+ case 2:
+ // Check if it's a P2A address (witness version
+ // 1, program 0x4e73).
+ if witnessVer == 1 && bytes.Equal(
+ witnessProg, []byte{0x4e, 0x73},
+ ) {
+ return newAddressPayToAnchor(hrp), nil
+ }
+
+ return nil, UnsupportedWitnessProgLenError(len(witnessProg))
+
+ case 20:
+ return newAddressWitnessPubKeyHash(hrp, witnessProg)
+
+ case 32:
+ if witnessVer == 1 {
+ return newAddressTaproot(hrp, witnessProg)
+ }
+
+ return newAddressWitnessScriptHash(hrp, witnessProg)
+ default:
+ return nil, UnsupportedWitnessProgLenError(len(witnessProg))
+ }
+ }
+ }
+
+ // Serialized public keys are either 65 bytes (130 hex chars) if
+ // uncompressed/hybrid or 33 bytes (66 hex chars) if compressed.
+ if len(addr) == 130 || len(addr) == 66 {
+ serializedPubKey, err := hex.DecodeString(addr)
+ if err != nil {
+ return nil, err
+ }
+ return NewAddressPubKey(serializedPubKey, defaultNet)
+ }
+
+ // Switch on decoded length to determine the type.
+ decoded, netID, err := base58.CheckDecode(addr)
+ if err != nil {
+ if err == base58.ErrChecksum {
+ return nil, ErrChecksumMismatch
+ }
+ return nil, errors.New("decoded address is of unknown format")
+ }
+ switch len(decoded) {
+ case ripemd160.Size: // P2PKH or P2SH
+ isP2PKH := netID == defaultNet.PubKeyHashAddrID
+ isP2SH := netID == defaultNet.ScriptHashAddrID
+ switch hash160 := decoded; {
+ case isP2PKH && isP2SH:
+ return nil, ErrAddressCollision
+ case isP2PKH:
+ return newAddressPubKeyHash(hash160, netID)
+ case isP2SH:
+ return newAddressScriptHashFromHash(hash160, netID)
+ default:
+ return nil, ErrUnknownAddressType
+ }
+
+ default:
+ return nil, errors.New("decoded address is of unknown size")
+ }
+}
+
+// decodeSegWitAddress parses a bech32 encoded segwit address string and
+// returns the witness version and witness program byte representation.
+func decodeSegWitAddress(address string) (byte, []byte, error) {
+ // Decode the bech32 encoded address.
+ _, data, bech32version, err := bech32.DecodeGeneric(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: %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 := bech32.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))
+ }
+
+ // For witness version 0, the bech32 encoding must be used.
+ if version == 0 && bech32version != bech32.Version0 {
+ return 0, nil, fmt.Errorf("invalid checksum expected bech32 " +
+ "encoding for address with witness version 0")
+ }
+
+ // For witness version 1, the bech32m encoding must be used.
+ if version == 1 && bech32version != bech32.VersionM {
+ return 0, nil, fmt.Errorf("invalid checksum expected bech32m " +
+ "encoding for address with witness version 1")
+ }
+
+ return version, regrouped, nil
+}
+
+// AddressPubKeyHash is an Address for a pay-to-pubkey-hash (P2PKH)
+// transaction.
+type AddressPubKeyHash struct {
+ hash [ripemd160.Size]byte
+ netID byte
+}
+
+// NewAddressPubKeyHash returns a new AddressPubKeyHash. pkHash mustbe 20
+// bytes.
+func NewAddressPubKeyHash(pkHash []byte, net *chaincfg.Params) (*AddressPubKeyHash, error) {
+ return newAddressPubKeyHash(pkHash, net.PubKeyHashAddrID)
+}
+
+// newAddressPubKeyHash is the internal API to create a pubkey hash address
+// with a known leading identifier byte for a network, rather than looking
+// it up through its parameters. This is useful when creating a new address
+// structure from a string encoding where the identifier byte is already
+// known.
+func newAddressPubKeyHash(pkHash []byte, netID byte) (*AddressPubKeyHash, error) {
+ // Check for a valid pubkey hash length.
+ if len(pkHash) != ripemd160.Size {
+ return nil, errors.New("pkHash must be 20 bytes")
+ }
+
+ addr := &AddressPubKeyHash{netID: netID}
+ copy(addr.hash[:], pkHash)
+ return addr, nil
+}
+
+// EncodeAddress returns the string encoding of a pay-to-pubkey-hash
+// address. Part of the Address interface.
+func (a *AddressPubKeyHash) EncodeAddress() string {
+ return encodeAddress(a.hash[:], a.netID)
+}
+
+// ScriptAddress returns the bytes to be included in a txout script to pay
+// to a pubkey hash. Part of the Address interface.
+func (a *AddressPubKeyHash) ScriptAddress() []byte {
+ return a.hash[:]
+}
+
+// IsForNet returns whether or not the pay-to-pubkey-hash address is associated
+// with the passed bitcoin network.
+func (a *AddressPubKeyHash) IsForNet(net *chaincfg.Params) bool {
+ return a.netID == net.PubKeyHashAddrID
+}
+
+// String returns a human-readable string for the pay-to-pubkey-hash address.
+// This is equivalent to calling EncodeAddress, but is provided so the type can
+// be used as a fmt.Stringer.
+func (a *AddressPubKeyHash) String() string {
+ return a.EncodeAddress()
+}
+
+// Hash160 returns the underlying array of the pubkey hash. This can be useful
+// when an array is more appropriate than a slice (for example, when used as map
+// keys).
+func (a *AddressPubKeyHash) Hash160() *[ripemd160.Size]byte {
+ return &a.hash
+}
+
+// AddressScriptHash is an Address for a pay-to-script-hash (P2SH)
+// transaction.
+type AddressScriptHash struct {
+ hash [ripemd160.Size]byte
+ netID byte
+}
+
+// NewAddressScriptHash returns a new AddressScriptHash.
+func NewAddressScriptHash(serializedScript []byte, net *chaincfg.Params) (*AddressScriptHash, error) {
+ scriptHash := Hash160(serializedScript)
+ return newAddressScriptHashFromHash(scriptHash, net.ScriptHashAddrID)
+}
+
+// NewAddressScriptHashFromHash returns a new AddressScriptHash. scriptHash
+// must be 20 bytes.
+func NewAddressScriptHashFromHash(scriptHash []byte, net *chaincfg.Params) (*AddressScriptHash, error) {
+ return newAddressScriptHashFromHash(scriptHash, net.ScriptHashAddrID)
+}
+
+// newAddressScriptHashFromHash is the internal API to create a script hash
+// address with a known leading identifier byte for a network, rather than
+// looking it up through its parameters. This is useful when creating a new
+// address structure from a string encoding where the identifier byte is already
+// known.
+func newAddressScriptHashFromHash(scriptHash []byte, netID byte) (*AddressScriptHash, error) {
+ // Check for a valid script hash length.
+ if len(scriptHash) != ripemd160.Size {
+ return nil, errors.New("scriptHash must be 20 bytes")
+ }
+
+ addr := &AddressScriptHash{netID: netID}
+ copy(addr.hash[:], scriptHash)
+ return addr, nil
+}
+
+// EncodeAddress returns the string encoding of a pay-to-script-hash
+// address. Part of the Address interface.
+func (a *AddressScriptHash) EncodeAddress() string {
+ return encodeAddress(a.hash[:], a.netID)
+}
+
+// ScriptAddress returns the bytes to be included in a txout script to pay
+// to a script hash. Part of the Address interface.
+func (a *AddressScriptHash) ScriptAddress() []byte {
+ return a.hash[:]
+}
+
+// IsForNet returns whether or not the pay-to-script-hash address is associated
+// with the passed bitcoin network.
+func (a *AddressScriptHash) IsForNet(net *chaincfg.Params) bool {
+ return a.netID == net.ScriptHashAddrID
+}
+
+// String returns a human-readable string for the pay-to-script-hash address.
+// This is equivalent to calling EncodeAddress, but is provided so the type can
+// be used as a fmt.Stringer.
+func (a *AddressScriptHash) String() string {
+ return a.EncodeAddress()
+}
+
+// Hash160 returns the underlying array of the script hash. This can be useful
+// when an array is more appropriate than a slice (for example, when used as map
+// keys).
+func (a *AddressScriptHash) Hash160() *[ripemd160.Size]byte {
+ return &a.hash
+}
+
+// PubKeyFormat describes what format to use for a pay-to-pubkey address.
+type PubKeyFormat int
+
+const (
+ // PKFUncompressed indicates the pay-to-pubkey address format is an
+ // uncompressed public key.
+ PKFUncompressed PubKeyFormat = iota
+
+ // PKFCompressed indicates the pay-to-pubkey address format is a
+ // compressed public key.
+ PKFCompressed
+)
+
+// AddressPubKey is an Address for a pay-to-pubkey transaction.
+type AddressPubKey struct {
+ pubKeyFormat PubKeyFormat
+ pubKey *btcec.PublicKey
+ pubKeyHashID byte
+}
+
+// NewAddressPubKey returns a new AddressPubKey which represents a pay-to-pubkey
+// address. The serializedPubKey parameter must be a valid pubkey and can be
+// uncompressed, compressed, or hybrid.
+func NewAddressPubKey(serializedPubKey []byte, net *chaincfg.Params) (*AddressPubKey, error) {
+ pubKey, err := btcec.ParsePubKey(serializedPubKey)
+ if err != nil {
+ return nil, err
+ }
+
+ // Set the format of the pubkey. This probably should be returned
+ // from btcec, but do it here to avoid API churn. We already know the
+ // pubkey is valid since it parsed above, so it's safe to simply examine
+ // the leading byte to get the format.
+ pkFormat := PKFUncompressed
+ switch serializedPubKey[0] {
+ case 0x02, 0x03:
+ pkFormat = PKFCompressed
+ }
+
+ return &AddressPubKey{
+ pubKeyFormat: pkFormat,
+ pubKey: pubKey,
+ pubKeyHashID: net.PubKeyHashAddrID,
+ }, nil
+}
+
+// serialize returns the serialization of the public key according to the
+// format associated with the address.
+func (a *AddressPubKey) serialize() []byte {
+ switch a.pubKeyFormat {
+ default:
+ fallthrough
+ case PKFUncompressed:
+ return a.pubKey.SerializeUncompressed()
+
+ case PKFCompressed:
+ return a.pubKey.SerializeCompressed()
+ }
+}
+
+// EncodeAddress returns the string encoding of the public key as a
+// pay-to-pubkey-hash. Note that the public key format (uncompressed,
+// compressed, etc) will change the resulting address. This is expected since
+// pay-to-pubkey-hash is a hash of the serialized public key which obviously
+// differs with the format. At the time of this writing, most Bitcoin addresses
+// are pay-to-pubkey-hash constructed from the uncompressed public key.
+//
+// Part of the Address interface.
+func (a *AddressPubKey) EncodeAddress() string {
+ return encodeAddress(Hash160(a.serialize()), a.pubKeyHashID)
+}
+
+// ScriptAddress returns the bytes to be included in a txout script to pay
+// to a public key. Setting the public key format will affect the output of
+// this function accordingly. Part of the Address interface.
+func (a *AddressPubKey) ScriptAddress() []byte {
+ return a.serialize()
+}
+
+// IsForNet returns whether or not the pay-to-pubkey address is associated
+// with the passed bitcoin network.
+func (a *AddressPubKey) IsForNet(net *chaincfg.Params) bool {
+ return a.pubKeyHashID == net.PubKeyHashAddrID
+}
+
+// String returns the hex-encoded human-readable string for the pay-to-pubkey
+// address. This is not the same as calling EncodeAddress.
+func (a *AddressPubKey) String() string {
+ return hex.EncodeToString(a.serialize())
+}
+
+// Format returns the format (uncompressed, compressed, etc) of the
+// pay-to-pubkey address.
+func (a *AddressPubKey) Format() PubKeyFormat {
+ return a.pubKeyFormat
+}
+
+// SetFormat sets the format (uncompressed, compressed, etc) of the
+// pay-to-pubkey address.
+func (a *AddressPubKey) SetFormat(pkFormat PubKeyFormat) {
+ a.pubKeyFormat = pkFormat
+}
+
+// AddressPubKeyHash returns the pay-to-pubkey address converted to a
+// pay-to-pubkey-hash address. Note that the public key format (uncompressed,
+// compressed, etc) will change the resulting address. This is expected since
+// pay-to-pubkey-hash is a hash of the serialized public key which obviously
+// differs with the format. At the time of this writing, most Bitcoin addresses
+// are pay-to-pubkey-hash constructed from the uncompressed public key.
+func (a *AddressPubKey) AddressPubKeyHash() *AddressPubKeyHash {
+ addr := &AddressPubKeyHash{netID: a.pubKeyHashID}
+ copy(addr.hash[:], Hash160(a.serialize()))
+ return addr
+}
+
+// PubKey returns the underlying public key for the address.
+func (a *AddressPubKey) PubKey() *btcec.PublicKey {
+ return a.pubKey
+}
+
+// AddressSegWit is the base address type for all SegWit addresses.
+type AddressSegWit struct {
+ hrp string
+ witnessVersion byte
+ witnessProgram []byte
+}
+
+// EncodeAddress returns the bech32 (or bech32m for SegWit v1) string encoding
+// of an AddressSegWit.
+//
+// NOTE: This method is part of the Address interface.
+func (a *AddressSegWit) EncodeAddress() string {
+ str, err := encodeSegWitAddress(
+ a.hrp, a.witnessVersion, a.witnessProgram[:],
+ )
+ if err != nil {
+ return ""
+ }
+ return str
+}
+
+// ScriptAddress returns the witness program for this address.
+//
+// NOTE: This method is part of the Address interface.
+func (a *AddressSegWit) ScriptAddress() []byte {
+ return a.witnessProgram[:]
+}
+
+// IsForNet returns whether the AddressSegWit is associated with the passed
+// bitcoin network.
+//
+// NOTE: This method is part of the Address interface.
+func (a *AddressSegWit) IsForNet(net *chaincfg.Params) bool {
+ return a.hrp == net.Bech32HRPSegwit
+}
+
+// String returns a human-readable string for the AddressWitnessPubKeyHash.
+// This is equivalent to calling EncodeAddress, but is provided so the type
+// can be used as a fmt.Stringer.
+//
+// NOTE: This method is part of the Address interface.
+func (a *AddressSegWit) String() string {
+ return a.EncodeAddress()
+}
+
+// Hrp returns the human-readable part of the bech32 (or bech32m for SegWit v1)
+// encoded AddressSegWit.
+func (a *AddressSegWit) Hrp() string {
+ return a.hrp
+}
+
+// WitnessVersion returns the witness version of the AddressSegWit.
+func (a *AddressSegWit) WitnessVersion() byte {
+ return a.witnessVersion
+}
+
+// WitnessProgram returns the witness program of the AddressSegWit.
+func (a *AddressSegWit) WitnessProgram() []byte {
+ return a.witnessProgram[:]
+}
+
+// AddressWitnessPubKeyHash is an Address for a pay-to-witness-pubkey-hash
+// (P2WPKH) output. See BIP 173 for further details regarding native segregated
+// witness address encoding:
+// https://github.com/bitcoin/bips/blob/master/bip-0173.mediawiki
+type AddressWitnessPubKeyHash struct {
+ AddressSegWit
+}
+
+// NewAddressWitnessPubKeyHash returns a new AddressWitnessPubKeyHash.
+func NewAddressWitnessPubKeyHash(witnessProg []byte,
+ net *chaincfg.Params) (*AddressWitnessPubKeyHash, error) {
+
+ return newAddressWitnessPubKeyHash(net.Bech32HRPSegwit, witnessProg)
+}
+
+// newAddressWitnessPubKeyHash is an internal helper function to create an
+// AddressWitnessPubKeyHash with a known human-readable part, rather than
+// looking it up through its parameters.
+func newAddressWitnessPubKeyHash(hrp string,
+ witnessProg []byte) (*AddressWitnessPubKeyHash, error) {
+
+ // Check for valid program length for witness version 0, which is 20
+ // for P2WPKH.
+ if len(witnessProg) != 20 {
+ return nil, errors.New("witness program must be 20 " +
+ "bytes for p2wpkh")
+ }
+
+ addr := &AddressWitnessPubKeyHash{
+ AddressSegWit{
+ hrp: strings.ToLower(hrp),
+ witnessVersion: 0x00,
+ witnessProgram: witnessProg,
+ },
+ }
+
+ return addr, nil
+}
+
+// Hash160 returns the witness program of the AddressWitnessPubKeyHash as a
+// byte array.
+func (a *AddressWitnessPubKeyHash) Hash160() *[20]byte {
+ var pubKeyHashWitnessProgram [20]byte
+ copy(pubKeyHashWitnessProgram[:], a.witnessProgram)
+ return &pubKeyHashWitnessProgram
+}
+
+// AddressWitnessScriptHash is an Address for a pay-to-witness-script-hash
+// (P2WSH) output. See BIP 173 for further details regarding native segregated
+// witness address encoding:
+// https://github.com/bitcoin/bips/blob/master/bip-0173.mediawiki
+type AddressWitnessScriptHash struct {
+ AddressSegWit
+}
+
+// NewAddressWitnessScriptHash returns a new AddressWitnessPubKeyHash.
+func NewAddressWitnessScriptHash(witnessProg []byte,
+ net *chaincfg.Params) (*AddressWitnessScriptHash, error) {
+
+ return newAddressWitnessScriptHash(net.Bech32HRPSegwit, witnessProg)
+}
+
+// newAddressWitnessScriptHash is an internal helper function to create an
+// AddressWitnessScriptHash with a known human-readable part, rather than
+// looking it up through its parameters.
+func newAddressWitnessScriptHash(hrp string,
+ witnessProg []byte) (*AddressWitnessScriptHash, error) {
+
+ // Check for valid program length for witness version 0, which is 32
+ // for P2WSH.
+ if len(witnessProg) != 32 {
+ return nil, errors.New("witness program must be 32 " +
+ "bytes for p2wsh")
+ }
+
+ addr := &AddressWitnessScriptHash{
+ AddressSegWit{
+ hrp: strings.ToLower(hrp),
+ witnessVersion: 0x00,
+ witnessProgram: witnessProg,
+ },
+ }
+
+ return addr, nil
+}
+
+// AddressTaproot is an Address for a pay-to-taproot (P2TR) output. See BIP 341
+// for further details.
+type AddressTaproot struct {
+ AddressSegWit
+}
+
+// NewAddressTaproot returns a new AddressTaproot.
+func NewAddressTaproot(witnessProg []byte,
+ net *chaincfg.Params) (*AddressTaproot, error) {
+
+ return newAddressTaproot(net.Bech32HRPSegwit, witnessProg)
+}
+
+// newAddressTaproot is an internal helper function to create an
+// AddressTaproot with a known human-readable part, rather than
+// looking it up through its parameters.
+func newAddressTaproot(hrp string,
+ witnessProg []byte) (*AddressTaproot, error) {
+
+ // Check for valid program length for witness version 1, which is 32
+ // for P2TR.
+ if len(witnessProg) != 32 {
+ return nil, errors.New("witness program must be 32 bytes for " +
+ "p2tr")
+ }
+
+ addr := &AddressTaproot{
+ AddressSegWit{
+ hrp: strings.ToLower(hrp),
+ witnessVersion: 0x01,
+ witnessProgram: witnessProg,
+ },
+ }
+
+ return addr, nil
+}
+
+// payToAnchorScript is the fixed script bytes for a pay-to-anchor output:
+// OP_1 OP_DATA_2 0x4e73. This is defined here to avoid an import cycle with
+// txscript. The same constant is exported as txscript.PayToAnchorScript;
+// keep both definitions in sync.
+var payToAnchorScript = []byte{0x51, 0x02, 0x4e, 0x73}
+
+// payToAnchorWitnessProgram is the 2-byte witness program portion of a P2A
+// output (i.e. the bytes that follow the OP_1 / OP_DATA_2 prefix in
+// payToAnchorScript).
+var payToAnchorWitnessProgram = []byte{0x4e, 0x73}
+
+// AddressPayToAnchor is an Address for a pay-to-anchor (P2A) output. P2A
+// outputs use the fixed script OP_1 <0x4e73> and have specific bech32
+// addresses for each network.
+type AddressPayToAnchor struct {
+ hrp string
+}
+
+// NewAddressPayToAnchor returns a new AddressPayToAnchor for the given network.
+func NewAddressPayToAnchor(net *chaincfg.Params) (*AddressPayToAnchor, error) {
+ if net == nil {
+ return nil, errors.New("nil network")
+ }
+
+ return newAddressPayToAnchor(net.Bech32HRPSegwit), nil
+}
+
+// newAddressPayToAnchor is an internal helper function to create an
+// AddressPayToAnchor with a known human-readable part, rather than looking it
+// up through its parameters. The HRP is normalized to lowercase so that
+// addresses decoded from all-uppercase bech32 strings (which BIP 173 allows)
+// still compare equal to the lowercase network HRP in IsForNet.
+func newAddressPayToAnchor(hrp string) *AddressPayToAnchor {
+ return &AddressPayToAnchor{
+ hrp: strings.ToLower(hrp),
+ }
+}
+
+// String returns a human-readable string for the pay-to-anchor address. This
+// is equivalent to EncodeAddress, but is provided to satisfy the Stringer
+// interface.
+func (a *AddressPayToAnchor) String() string {
+ return a.EncodeAddress()
+}
+
+// EncodeAddress returns the bech32m string encoding of the pay-to-anchor
+// address. P2A addresses are encoded using witness version 1 with the program
+// bytes 0x4e73, resulting in these addresses per network:
+//
+// - Mainnet: bc1pfeessrawgf
+// - Testnet: tb1pfees9rn5nz
+// - Regtest: bcrt1pfeesnyr2tx
+// - Simnet: sb1pfeesxv0pfa
+func (a *AddressPayToAnchor) EncodeAddress() string {
+ // For unknown networks, generate the address from the anchor data.
+ // This shouldn't happen in practice.
+ anchorData := []byte{0x4e, 0x73}
+ addr, err := encodeSegWitAddress(a.hrp, 1, anchorData)
+ if err != nil {
+ return ""
+ }
+ return addr
+}
+
+// ScriptAddress returns the witness program portion of the P2A address (the
+// 2-byte program 0x4e73). This matches the convention used by other segwit
+// address types, where ScriptAddress returns the witness program and the
+// outer script wrapping (OP_1 OP_DATA_2 ...) is added by PayToAddrScript.
+func (a *AddressPayToAnchor) ScriptAddress() []byte {
+ return payToAnchorWitnessProgram
+}
+
+// IsForNet returns whether the address is associated with the passed
+// bitcoin network.
+func (a *AddressPayToAnchor) IsForNet(net *chaincfg.Params) bool {
+ return a.hrp == net.Bech32HRPSegwit
+}
diff --git a/address/address_test.go b/address/address_test.go
new file mode 100644
index 0000000..c646cfb
--- /dev/null
+++ b/address/address_test.go
@@ -0,0 +1,896 @@
+// Copyright (c) 2013-2017 The btcsuite developers
+// Use of this source code is governed by an ISC
+// license that can be found in the LICENSE file.
+
+package address_test
+
+import (
+ "bytes"
+ "encoding/hex"
+ "fmt"
+ "reflect"
+ "strings"
+ "testing"
+
+ "github.com/btcsuite/btcd/address/v2"
+ "github.com/btcsuite/btcd/chaincfg/v2"
+ "github.com/btcsuite/btcd/wire/v2"
+ "golang.org/x/crypto/ripemd160"
+)
+
+type CustomParamStruct struct {
+ Net wire.BitcoinNet
+ PubKeyHashAddrID byte
+ ScriptHashAddrID byte
+ Bech32HRPSegwit string
+}
+
+var CustomParams = CustomParamStruct{
+ Net: 0xdbb6c0fb, // litecoin mainnet HD version bytes
+ PubKeyHashAddrID: 0x30, // starts with L
+ ScriptHashAddrID: 0x32, // starts with M
+ Bech32HRPSegwit: "ltc", // starts with ltc
+}
+
+// We use this function to be able to test functionality in DecodeAddress for
+// defaultNet addresses
+func applyCustomParams(params chaincfg.Params, customParams CustomParamStruct) chaincfg.Params {
+ params.Net = customParams.Net
+ params.PubKeyHashAddrID = customParams.PubKeyHashAddrID
+ params.ScriptHashAddrID = customParams.ScriptHashAddrID
+ params.Bech32HRPSegwit = customParams.Bech32HRPSegwit
+ return params
+}
+
+var customParams = applyCustomParams(chaincfg.MainNetParams, CustomParams)
+
+func TestAddresses(t *testing.T) {
+ tests := []struct {
+ name string
+ addr string
+ encoded string
+ valid bool
+ result address.Address
+ f func() (address.Address, error)
+ net *chaincfg.Params
+ }{
+ // Positive P2PKH tests.
+ {
+ name: "mainnet p2pkh",
+ addr: "1MirQ9bwyQcGVJPwKUgapu5ouK2E2Ey4gX",
+ encoded: "1MirQ9bwyQcGVJPwKUgapu5ouK2E2Ey4gX",
+ valid: true,
+ result: address.TstAddressPubKeyHash(
+ [ripemd160.Size]byte{
+ 0xe3, 0x4c, 0xce, 0x70, 0xc8, 0x63, 0x73, 0x27, 0x3e, 0xfc,
+ 0xc5, 0x4c, 0xe7, 0xd2, 0xa4, 0x91, 0xbb, 0x4a, 0x0e, 0x84},
+ chaincfg.MainNetParams.PubKeyHashAddrID),
+ f: func() (address.Address, error) {
+ pkHash := []byte{
+ 0xe3, 0x4c, 0xce, 0x70, 0xc8, 0x63, 0x73, 0x27, 0x3e, 0xfc,
+ 0xc5, 0x4c, 0xe7, 0xd2, 0xa4, 0x91, 0xbb, 0x4a, 0x0e, 0x84}
+ return address.NewAddressPubKeyHash(pkHash, &chaincfg.MainNetParams)
+ },
+ net: &chaincfg.MainNetParams,
+ },
+ {
+ name: "mainnet p2pkh 2",
+ addr: "12MzCDwodF9G1e7jfwLXfR164RNtx4BRVG",
+ encoded: "12MzCDwodF9G1e7jfwLXfR164RNtx4BRVG",
+ valid: true,
+ result: address.TstAddressPubKeyHash(
+ [ripemd160.Size]byte{
+ 0x0e, 0xf0, 0x30, 0x10, 0x7f, 0xd2, 0x6e, 0x0b, 0x6b, 0xf4,
+ 0x05, 0x12, 0xbc, 0xa2, 0xce, 0xb1, 0xdd, 0x80, 0xad, 0xaa},
+ chaincfg.MainNetParams.PubKeyHashAddrID),
+ f: func() (address.Address, error) {
+ pkHash := []byte{
+ 0x0e, 0xf0, 0x30, 0x10, 0x7f, 0xd2, 0x6e, 0x0b, 0x6b, 0xf4,
+ 0x05, 0x12, 0xbc, 0xa2, 0xce, 0xb1, 0xdd, 0x80, 0xad, 0xaa}
+ return address.NewAddressPubKeyHash(pkHash, &chaincfg.MainNetParams)
+ },
+ net: &chaincfg.MainNetParams,
+ },
+ {
+ name: "litecoin mainnet p2pkh",
+ addr: "LM2WMpR1Rp6j3Sa59cMXMs1SPzj9eXpGc1",
+ encoded: "LM2WMpR1Rp6j3Sa59cMXMs1SPzj9eXpGc1",
+ valid: true,
+ result: address.TstAddressPubKeyHash(
+ [ripemd160.Size]byte{
+ 0x13, 0xc6, 0x0d, 0x8e, 0x68, 0xd7, 0x34, 0x9f, 0x5b, 0x4c,
+ 0xa3, 0x62, 0xc3, 0x95, 0x4b, 0x15, 0x04, 0x50, 0x61, 0xb1},
+ CustomParams.PubKeyHashAddrID),
+ f: func() (address.Address, error) {
+ pkHash := []byte{
+ 0x13, 0xc6, 0x0d, 0x8e, 0x68, 0xd7, 0x34, 0x9f, 0x5b, 0x4c,
+ 0xa3, 0x62, 0xc3, 0x95, 0x4b, 0x15, 0x04, 0x50, 0x61, 0xb1}
+ return address.NewAddressPubKeyHash(pkHash, &customParams)
+ },
+ net: &customParams,
+ },
+ {
+ name: "testnet p2pkh",
+ addr: "mrX9vMRYLfVy1BnZbc5gZjuyaqH3ZW2ZHz",
+ encoded: "mrX9vMRYLfVy1BnZbc5gZjuyaqH3ZW2ZHz",
+ valid: true,
+ result: address.TstAddressPubKeyHash(
+ [ripemd160.Size]byte{
+ 0x78, 0xb3, 0x16, 0xa0, 0x86, 0x47, 0xd5, 0xb7, 0x72, 0x83,
+ 0xe5, 0x12, 0xd3, 0x60, 0x3f, 0x1f, 0x1c, 0x8d, 0xe6, 0x8f},
+ chaincfg.TestNet3Params.PubKeyHashAddrID),
+ f: func() (address.Address, error) {
+ pkHash := []byte{
+ 0x78, 0xb3, 0x16, 0xa0, 0x86, 0x47, 0xd5, 0xb7, 0x72, 0x83,
+ 0xe5, 0x12, 0xd3, 0x60, 0x3f, 0x1f, 0x1c, 0x8d, 0xe6, 0x8f}
+ return address.NewAddressPubKeyHash(pkHash, &chaincfg.TestNet3Params)
+ },
+ net: &chaincfg.TestNet3Params,
+ },
+
+ // Negative P2PKH tests.
+ {
+ name: "p2pkh wrong hash length",
+ addr: "",
+ valid: false,
+ f: func() (address.Address, error) {
+ pkHash := []byte{
+ 0x00, 0x0e, 0xf0, 0x30, 0x10, 0x7f, 0xd2, 0x6e, 0x0b, 0x6b,
+ 0xf4, 0x05, 0x12, 0xbc, 0xa2, 0xce, 0xb1, 0xdd, 0x80, 0xad,
+ 0xaa}
+ return address.NewAddressPubKeyHash(pkHash, &chaincfg.MainNetParams)
+ },
+ net: &chaincfg.MainNetParams,
+ },
+ {
+ name: "p2pkh bad checksum",
+ addr: "1MirQ9bwyQcGVJPwKUgapu5ouK2E2Ey4gY",
+ valid: false,
+ net: &chaincfg.MainNetParams,
+ },
+
+ // Positive P2SH tests.
+ {
+ // Taken from transactions:
+ // output: 3c9018e8d5615c306d72397f8f5eef44308c98fb576a88e030c25456b4f3a7ac
+ // input: 837dea37ddc8b1e3ce646f1a656e79bbd8cc7f558ac56a169626d649ebe2a3ba.
+ name: "mainnet p2sh",
+ addr: "3QJmV3qfvL9SuYo34YihAf3sRCW3qSinyC",
+ encoded: "3QJmV3qfvL9SuYo34YihAf3sRCW3qSinyC",
+ valid: true,
+ result: address.TstAddressScriptHash(
+ [ripemd160.Size]byte{
+ 0xf8, 0x15, 0xb0, 0x36, 0xd9, 0xbb, 0xbc, 0xe5, 0xe9, 0xf2,
+ 0xa0, 0x0a, 0xbd, 0x1b, 0xf3, 0xdc, 0x91, 0xe9, 0x55, 0x10},
+ chaincfg.MainNetParams.ScriptHashAddrID),
+ f: func() (address.Address, error) {
+ script := []byte{
+ 0x52, 0x41, 0x04, 0x91, 0xbb, 0xa2, 0x51, 0x09, 0x12, 0xa5,
+ 0xbd, 0x37, 0xda, 0x1f, 0xb5, 0xb1, 0x67, 0x30, 0x10, 0xe4,
+ 0x3d, 0x2c, 0x6d, 0x81, 0x2c, 0x51, 0x4e, 0x91, 0xbf, 0xa9,
+ 0xf2, 0xeb, 0x12, 0x9e, 0x1c, 0x18, 0x33, 0x29, 0xdb, 0x55,
+ 0xbd, 0x86, 0x8e, 0x20, 0x9a, 0xac, 0x2f, 0xbc, 0x02, 0xcb,
+ 0x33, 0xd9, 0x8f, 0xe7, 0x4b, 0xf2, 0x3f, 0x0c, 0x23, 0x5d,
+ 0x61, 0x26, 0xb1, 0xd8, 0x33, 0x4f, 0x86, 0x41, 0x04, 0x86,
+ 0x5c, 0x40, 0x29, 0x3a, 0x68, 0x0c, 0xb9, 0xc0, 0x20, 0xe7,
+ 0xb1, 0xe1, 0x06, 0xd8, 0xc1, 0x91, 0x6d, 0x3c, 0xef, 0x99,
+ 0xaa, 0x43, 0x1a, 0x56, 0xd2, 0x53, 0xe6, 0x92, 0x56, 0xda,
+ 0xc0, 0x9e, 0xf1, 0x22, 0xb1, 0xa9, 0x86, 0x81, 0x8a, 0x7c,
+ 0xb6, 0x24, 0x53, 0x2f, 0x06, 0x2c, 0x1d, 0x1f, 0x87, 0x22,
+ 0x08, 0x48, 0x61, 0xc5, 0xc3, 0x29, 0x1c, 0xcf, 0xfe, 0xf4,
+ 0xec, 0x68, 0x74, 0x41, 0x04, 0x8d, 0x24, 0x55, 0xd2, 0x40,
+ 0x3e, 0x08, 0x70, 0x8f, 0xc1, 0xf5, 0x56, 0x00, 0x2f, 0x1b,
+ 0x6c, 0xd8, 0x3f, 0x99, 0x2d, 0x08, 0x50, 0x97, 0xf9, 0x97,
+ 0x4a, 0xb0, 0x8a, 0x28, 0x83, 0x8f, 0x07, 0x89, 0x6f, 0xba,
+ 0xb0, 0x8f, 0x39, 0x49, 0x5e, 0x15, 0xfa, 0x6f, 0xad, 0x6e,
+ 0xdb, 0xfb, 0x1e, 0x75, 0x4e, 0x35, 0xfa, 0x1c, 0x78, 0x44,
+ 0xc4, 0x1f, 0x32, 0x2a, 0x18, 0x63, 0xd4, 0x62, 0x13, 0x53,
+ 0xae}
+ return address.NewAddressScriptHash(script, &chaincfg.MainNetParams)
+ },
+ net: &chaincfg.MainNetParams,
+ },
+ {
+ name: "litecoin mainnet P2SH ",
+ addr: "MVcg9uEvtWuP5N6V48EHfEtbz48qR8TKZ9",
+ encoded: "MVcg9uEvtWuP5N6V48EHfEtbz48qR8TKZ9",
+ valid: true,
+ result: address.TstAddressScriptHash(
+ [ripemd160.Size]byte{
+ 0xee, 0x34, 0xac, 0x67, 0x6b, 0xda, 0xf6, 0xe3, 0x70, 0xc8,
+ 0xc8, 0x20, 0xb9, 0x48, 0xed, 0xfa, 0xd3, 0xa8, 0x73, 0xd8},
+ CustomParams.ScriptHashAddrID),
+ f: func() (address.Address, error) {
+ pkHash := []byte{
+ 0xEE, 0x34, 0xAC, 0x67, 0x6B, 0xDA, 0xF6, 0xE3, 0x70, 0xC8,
+ 0xC8, 0x20, 0xB9, 0x48, 0xED, 0xFA, 0xD3, 0xA8, 0x73, 0xD8}
+ return address.NewAddressScriptHashFromHash(pkHash, &customParams)
+ },
+ net: &customParams,
+ },
+ {
+ // Taken from transactions:
+ // output: b0539a45de13b3e0403909b8bd1a555b8cbe45fd4e3f3fda76f3a5f52835c29d
+ // input: (not yet redeemed at time test was written)
+ name: "mainnet p2sh 2",
+ addr: "3NukJ6fYZJ5Kk8bPjycAnruZkE5Q7UW7i8",
+ encoded: "3NukJ6fYZJ5Kk8bPjycAnruZkE5Q7UW7i8",
+ valid: true,
+ result: address.TstAddressScriptHash(
+ [ripemd160.Size]byte{
+ 0xe8, 0xc3, 0x00, 0xc8, 0x79, 0x86, 0xef, 0xa8, 0x4c, 0x37,
+ 0xc0, 0x51, 0x99, 0x29, 0x01, 0x9e, 0xf8, 0x6e, 0xb5, 0xb4},
+ chaincfg.MainNetParams.ScriptHashAddrID),
+ f: func() (address.Address, error) {
+ hash := []byte{
+ 0xe8, 0xc3, 0x00, 0xc8, 0x79, 0x86, 0xef, 0xa8, 0x4c, 0x37,
+ 0xc0, 0x51, 0x99, 0x29, 0x01, 0x9e, 0xf8, 0x6e, 0xb5, 0xb4}
+ return address.NewAddressScriptHashFromHash(hash, &chaincfg.MainNetParams)
+ },
+ net: &chaincfg.MainNetParams,
+ },
+ {
+ // Taken from bitcoind base58_keys_valid.
+ name: "testnet p2sh",
+ addr: "2NBFNJTktNa7GZusGbDbGKRZTxdK9VVez3n",
+ encoded: "2NBFNJTktNa7GZusGbDbGKRZTxdK9VVez3n",
+ valid: true,
+ result: address.TstAddressScriptHash(
+ [ripemd160.Size]byte{
+ 0xc5, 0x79, 0x34, 0x2c, 0x2c, 0x4c, 0x92, 0x20, 0x20, 0x5e,
+ 0x2c, 0xdc, 0x28, 0x56, 0x17, 0x04, 0x0c, 0x92, 0x4a, 0x0a},
+ chaincfg.TestNet3Params.ScriptHashAddrID),
+ f: func() (address.Address, error) {
+ hash := []byte{
+ 0xc5, 0x79, 0x34, 0x2c, 0x2c, 0x4c, 0x92, 0x20, 0x20, 0x5e,
+ 0x2c, 0xdc, 0x28, 0x56, 0x17, 0x04, 0x0c, 0x92, 0x4a, 0x0a}
+ return address.NewAddressScriptHashFromHash(hash, &chaincfg.TestNet3Params)
+ },
+ net: &chaincfg.TestNet3Params,
+ },
+
+ // Negative P2SH tests.
+ {
+ name: "p2sh wrong hash length",
+ addr: "",
+ valid: false,
+ f: func() (address.Address, error) {
+ hash := []byte{
+ 0x00, 0xf8, 0x15, 0xb0, 0x36, 0xd9, 0xbb, 0xbc, 0xe5, 0xe9,
+ 0xf2, 0xa0, 0x0a, 0xbd, 0x1b, 0xf3, 0xdc, 0x91, 0xe9, 0x55,
+ 0x10}
+ return address.NewAddressScriptHashFromHash(hash, &chaincfg.MainNetParams)
+ },
+ net: &chaincfg.MainNetParams,
+ },
+
+ // Positive P2PK tests.
+ {
+ name: "mainnet p2pk compressed (0x02)",
+ addr: "02192d74d0cb94344c9569c2e77901573d8d7903c3ebec3a957724895dca52c6b4",
+ encoded: "13CG6SJ3yHUXo4Cr2RY4THLLJrNFuG3gUg",
+ valid: true,
+ result: address.TstAddressPubKey(
+ []byte{
+ 0x02, 0x19, 0x2d, 0x74, 0xd0, 0xcb, 0x94, 0x34, 0x4c, 0x95,
+ 0x69, 0xc2, 0xe7, 0x79, 0x01, 0x57, 0x3d, 0x8d, 0x79, 0x03,
+ 0xc3, 0xeb, 0xec, 0x3a, 0x95, 0x77, 0x24, 0x89, 0x5d, 0xca,
+ 0x52, 0xc6, 0xb4},
+ address.PKFCompressed, chaincfg.MainNetParams.PubKeyHashAddrID),
+ f: func() (address.Address, error) {
+ serializedPubKey := []byte{
+ 0x02, 0x19, 0x2d, 0x74, 0xd0, 0xcb, 0x94, 0x34, 0x4c, 0x95,
+ 0x69, 0xc2, 0xe7, 0x79, 0x01, 0x57, 0x3d, 0x8d, 0x79, 0x03,
+ 0xc3, 0xeb, 0xec, 0x3a, 0x95, 0x77, 0x24, 0x89, 0x5d, 0xca,
+ 0x52, 0xc6, 0xb4}
+ return address.NewAddressPubKey(serializedPubKey, &chaincfg.MainNetParams)
+ },
+ net: &chaincfg.MainNetParams,
+ },
+ {
+ name: "mainnet p2pk compressed (0x03)",
+ addr: "03b0bd634234abbb1ba1e986e884185c61cf43e001f9137f23c2c409273eb16e65",
+ encoded: "15sHANNUBSh6nDp8XkDPmQcW6n3EFwmvE6",
+ valid: true,
+ result: address.TstAddressPubKey(
+ []byte{
+ 0x03, 0xb0, 0xbd, 0x63, 0x42, 0x34, 0xab, 0xbb, 0x1b, 0xa1,
+ 0xe9, 0x86, 0xe8, 0x84, 0x18, 0x5c, 0x61, 0xcf, 0x43, 0xe0,
+ 0x01, 0xf9, 0x13, 0x7f, 0x23, 0xc2, 0xc4, 0x09, 0x27, 0x3e,
+ 0xb1, 0x6e, 0x65},
+ address.PKFCompressed, chaincfg.MainNetParams.PubKeyHashAddrID),
+ f: func() (address.Address, error) {
+ serializedPubKey := []byte{
+ 0x03, 0xb0, 0xbd, 0x63, 0x42, 0x34, 0xab, 0xbb, 0x1b, 0xa1,
+ 0xe9, 0x86, 0xe8, 0x84, 0x18, 0x5c, 0x61, 0xcf, 0x43, 0xe0,
+ 0x01, 0xf9, 0x13, 0x7f, 0x23, 0xc2, 0xc4, 0x09, 0x27, 0x3e,
+ 0xb1, 0x6e, 0x65}
+ return address.NewAddressPubKey(serializedPubKey, &chaincfg.MainNetParams)
+ },
+ net: &chaincfg.MainNetParams,
+ },
+ {
+ name: "mainnet p2pk uncompressed (0x04)",
+ addr: "0411db93e1dcdb8a016b49840f8c53bc1eb68a382e97b1482ecad7b148a6909a5cb2" +
+ "e0eaddfb84ccf9744464f82e160bfa9b8b64f9d4c03f999b8643f656b412a3",
+ encoded: "12cbQLTFMXRnSzktFkuoG3eHoMeFtpTu3S",
+ valid: true,
+ result: address.TstAddressPubKey(
+ []byte{
+ 0x04, 0x11, 0xdb, 0x93, 0xe1, 0xdc, 0xdb, 0x8a, 0x01, 0x6b,
+ 0x49, 0x84, 0x0f, 0x8c, 0x53, 0xbc, 0x1e, 0xb6, 0x8a, 0x38,
+ 0x2e, 0x97, 0xb1, 0x48, 0x2e, 0xca, 0xd7, 0xb1, 0x48, 0xa6,
+ 0x90, 0x9a, 0x5c, 0xb2, 0xe0, 0xea, 0xdd, 0xfb, 0x84, 0xcc,
+ 0xf9, 0x74, 0x44, 0x64, 0xf8, 0x2e, 0x16, 0x0b, 0xfa, 0x9b,
+ 0x8b, 0x64, 0xf9, 0xd4, 0xc0, 0x3f, 0x99, 0x9b, 0x86, 0x43,
+ 0xf6, 0x56, 0xb4, 0x12, 0xa3},
+ address.PKFUncompressed, chaincfg.MainNetParams.PubKeyHashAddrID),
+ f: func() (address.Address, error) {
+ serializedPubKey := []byte{
+ 0x04, 0x11, 0xdb, 0x93, 0xe1, 0xdc, 0xdb, 0x8a, 0x01, 0x6b,
+ 0x49, 0x84, 0x0f, 0x8c, 0x53, 0xbc, 0x1e, 0xb6, 0x8a, 0x38,
+ 0x2e, 0x97, 0xb1, 0x48, 0x2e, 0xca, 0xd7, 0xb1, 0x48, 0xa6,
+ 0x90, 0x9a, 0x5c, 0xb2, 0xe0, 0xea, 0xdd, 0xfb, 0x84, 0xcc,
+ 0xf9, 0x74, 0x44, 0x64, 0xf8, 0x2e, 0x16, 0x0b, 0xfa, 0x9b,
+ 0x8b, 0x64, 0xf9, 0xd4, 0xc0, 0x3f, 0x99, 0x9b, 0x86, 0x43,
+ 0xf6, 0x56, 0xb4, 0x12, 0xa3}
+ return address.NewAddressPubKey(serializedPubKey, &chaincfg.MainNetParams)
+ },
+ net: &chaincfg.MainNetParams,
+ },
+ {
+ name: "testnet p2pk compressed (0x02)",
+ addr: "02192d74d0cb94344c9569c2e77901573d8d7903c3ebec3a957724895dca52c6b4",
+ encoded: "mhiDPVP2nJunaAgTjzWSHCYfAqxxrxzjmo",
+ valid: true,
+ result: address.TstAddressPubKey(
+ []byte{
+ 0x02, 0x19, 0x2d, 0x74, 0xd0, 0xcb, 0x94, 0x34, 0x4c, 0x95,
+ 0x69, 0xc2, 0xe7, 0x79, 0x01, 0x57, 0x3d, 0x8d, 0x79, 0x03,
+ 0xc3, 0xeb, 0xec, 0x3a, 0x95, 0x77, 0x24, 0x89, 0x5d, 0xca,
+ 0x52, 0xc6, 0xb4},
+ address.PKFCompressed, chaincfg.TestNet3Params.PubKeyHashAddrID),
+ f: func() (address.Address, error) {
+ serializedPubKey := []byte{
+ 0x02, 0x19, 0x2d, 0x74, 0xd0, 0xcb, 0x94, 0x34, 0x4c, 0x95,
+ 0x69, 0xc2, 0xe7, 0x79, 0x01, 0x57, 0x3d, 0x8d, 0x79, 0x03,
+ 0xc3, 0xeb, 0xec, 0x3a, 0x95, 0x77, 0x24, 0x89, 0x5d, 0xca,
+ 0x52, 0xc6, 0xb4}
+ return address.NewAddressPubKey(serializedPubKey, &chaincfg.TestNet3Params)
+ },
+ net: &chaincfg.TestNet3Params,
+ },
+ {
+ name: "testnet p2pk compressed (0x03)",
+ addr: "03b0bd634234abbb1ba1e986e884185c61cf43e001f9137f23c2c409273eb16e65",
+ encoded: "mkPETRTSzU8MZLHkFKBmbKppxmdw9qT42t",
+ valid: true,
+ result: address.TstAddressPubKey(
+ []byte{
+ 0x03, 0xb0, 0xbd, 0x63, 0x42, 0x34, 0xab, 0xbb, 0x1b, 0xa1,
+ 0xe9, 0x86, 0xe8, 0x84, 0x18, 0x5c, 0x61, 0xcf, 0x43, 0xe0,
+ 0x01, 0xf9, 0x13, 0x7f, 0x23, 0xc2, 0xc4, 0x09, 0x27, 0x3e,
+ 0xb1, 0x6e, 0x65},
+ address.PKFCompressed, chaincfg.TestNet3Params.PubKeyHashAddrID),
+ f: func() (address.Address, error) {
+ serializedPubKey := []byte{
+ 0x03, 0xb0, 0xbd, 0x63, 0x42, 0x34, 0xab, 0xbb, 0x1b, 0xa1,
+ 0xe9, 0x86, 0xe8, 0x84, 0x18, 0x5c, 0x61, 0xcf, 0x43, 0xe0,
+ 0x01, 0xf9, 0x13, 0x7f, 0x23, 0xc2, 0xc4, 0x09, 0x27, 0x3e,
+ 0xb1, 0x6e, 0x65}
+ return address.NewAddressPubKey(serializedPubKey, &chaincfg.TestNet3Params)
+ },
+ net: &chaincfg.TestNet3Params,
+ },
+ {
+ name: "testnet p2pk uncompressed (0x04)",
+ addr: "0411db93e1dcdb8a016b49840f8c53bc1eb68a382e97b1482ecad7b148a6909a5" +
+ "cb2e0eaddfb84ccf9744464f82e160bfa9b8b64f9d4c03f999b8643f656b412a3",
+ encoded: "mh8YhPYEAYs3E7EVyKtB5xrcfMExkkdEMF",
+ valid: true,
+ result: address.TstAddressPubKey(
+ []byte{
+ 0x04, 0x11, 0xdb, 0x93, 0xe1, 0xdc, 0xdb, 0x8a, 0x01, 0x6b,
+ 0x49, 0x84, 0x0f, 0x8c, 0x53, 0xbc, 0x1e, 0xb6, 0x8a, 0x38,
+ 0x2e, 0x97, 0xb1, 0x48, 0x2e, 0xca, 0xd7, 0xb1, 0x48, 0xa6,
+ 0x90, 0x9a, 0x5c, 0xb2, 0xe0, 0xea, 0xdd, 0xfb, 0x84, 0xcc,
+ 0xf9, 0x74, 0x44, 0x64, 0xf8, 0x2e, 0x16, 0x0b, 0xfa, 0x9b,
+ 0x8b, 0x64, 0xf9, 0xd4, 0xc0, 0x3f, 0x99, 0x9b, 0x86, 0x43,
+ 0xf6, 0x56, 0xb4, 0x12, 0xa3},
+ address.PKFUncompressed, chaincfg.TestNet3Params.PubKeyHashAddrID),
+ f: func() (address.Address, error) {
+ serializedPubKey := []byte{
+ 0x04, 0x11, 0xdb, 0x93, 0xe1, 0xdc, 0xdb, 0x8a, 0x01, 0x6b,
+ 0x49, 0x84, 0x0f, 0x8c, 0x53, 0xbc, 0x1e, 0xb6, 0x8a, 0x38,
+ 0x2e, 0x97, 0xb1, 0x48, 0x2e, 0xca, 0xd7, 0xb1, 0x48, 0xa6,
+ 0x90, 0x9a, 0x5c, 0xb2, 0xe0, 0xea, 0xdd, 0xfb, 0x84, 0xcc,
+ 0xf9, 0x74, 0x44, 0x64, 0xf8, 0x2e, 0x16, 0x0b, 0xfa, 0x9b,
+ 0x8b, 0x64, 0xf9, 0xd4, 0xc0, 0x3f, 0x99, 0x9b, 0x86, 0x43,
+ 0xf6, 0x56, 0xb4, 0x12, 0xa3}
+ return address.NewAddressPubKey(serializedPubKey, &chaincfg.TestNet3Params)
+ },
+ net: &chaincfg.TestNet3Params,
+ },
+ // Segwit address tests.
+ {
+ name: "segwit mainnet p2wpkh v0",
+ addr: "BC1QW508D6QEJXTDG4Y5R3ZARVARY0C5XW7KV8F3T4",
+ encoded: "bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4",
+ valid: true,
+ result: address.TstAddressWitnessPubKeyHash(
+ 0,
+ [20]byte{
+ 0x75, 0x1e, 0x76, 0xe8, 0x19, 0x91, 0x96, 0xd4, 0x54, 0x94,
+ 0x1c, 0x45, 0xd1, 0xb3, 0xa3, 0x23, 0xf1, 0x43, 0x3b, 0xd6},
+ chaincfg.MainNetParams.Bech32HRPSegwit),
+ f: func() (address.Address, error) {
+ pkHash := []byte{
+ 0x75, 0x1e, 0x76, 0xe8, 0x19, 0x91, 0x96, 0xd4, 0x54, 0x94,
+ 0x1c, 0x45, 0xd1, 0xb3, 0xa3, 0x23, 0xf1, 0x43, 0x3b, 0xd6}
+ return address.NewAddressWitnessPubKeyHash(pkHash, &chaincfg.MainNetParams)
+ },
+ net: &chaincfg.MainNetParams,
+ },
+ {
+ name: "segwit mainnet p2wsh v0",
+ addr: "bc1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3qccfmv3",
+ encoded: "bc1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3qccfmv3",
+ valid: true,
+ result: address.TstAddressWitnessScriptHash(
+ 0,
+ [32]byte{
+ 0x18, 0x63, 0x14, 0x3c, 0x14, 0xc5, 0x16, 0x68,
+ 0x04, 0xbd, 0x19, 0x20, 0x33, 0x56, 0xda, 0x13,
+ 0x6c, 0x98, 0x56, 0x78, 0xcd, 0x4d, 0x27, 0xa1,
+ 0xb8, 0xc6, 0x32, 0x96, 0x04, 0x90, 0x32, 0x62},
+ chaincfg.MainNetParams.Bech32HRPSegwit),
+ f: func() (address.Address, error) {
+ scriptHash := []byte{
+ 0x18, 0x63, 0x14, 0x3c, 0x14, 0xc5, 0x16, 0x68,
+ 0x04, 0xbd, 0x19, 0x20, 0x33, 0x56, 0xda, 0x13,
+ 0x6c, 0x98, 0x56, 0x78, 0xcd, 0x4d, 0x27, 0xa1,
+ 0xb8, 0xc6, 0x32, 0x96, 0x04, 0x90, 0x32, 0x62}
+ return address.NewAddressWitnessScriptHash(scriptHash, &chaincfg.MainNetParams)
+ },
+ net: &chaincfg.MainNetParams,
+ },
+ {
+ name: "segwit testnet p2wpkh v0",
+ addr: "tb1qw508d6qejxtdg4y5r3zarvary0c5xw7kxpjzsx",
+ encoded: "tb1qw508d6qejxtdg4y5r3zarvary0c5xw7kxpjzsx",
+ valid: true,
+ result: address.TstAddressWitnessPubKeyHash(
+ 0,
+ [20]byte{
+ 0x75, 0x1e, 0x76, 0xe8, 0x19, 0x91, 0x96, 0xd4, 0x54, 0x94,
+ 0x1c, 0x45, 0xd1, 0xb3, 0xa3, 0x23, 0xf1, 0x43, 0x3b, 0xd6},
+ chaincfg.TestNet3Params.Bech32HRPSegwit),
+ f: func() (address.Address, error) {
+ pkHash := []byte{
+ 0x75, 0x1e, 0x76, 0xe8, 0x19, 0x91, 0x96, 0xd4, 0x54, 0x94,
+ 0x1c, 0x45, 0xd1, 0xb3, 0xa3, 0x23, 0xf1, 0x43, 0x3b, 0xd6}
+ return address.NewAddressWitnessPubKeyHash(pkHash, &chaincfg.TestNet3Params)
+ },
+ net: &chaincfg.TestNet3Params,
+ },
+ {
+ name: "segwit testnet p2wsh v0",
+ addr: "tb1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3q0sl5k7",
+ encoded: "tb1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3q0sl5k7",
+ valid: true,
+ result: address.TstAddressWitnessScriptHash(
+ 0,
+ [32]byte{
+ 0x18, 0x63, 0x14, 0x3c, 0x14, 0xc5, 0x16, 0x68,
+ 0x04, 0xbd, 0x19, 0x20, 0x33, 0x56, 0xda, 0x13,
+ 0x6c, 0x98, 0x56, 0x78, 0xcd, 0x4d, 0x27, 0xa1,
+ 0xb8, 0xc6, 0x32, 0x96, 0x04, 0x90, 0x32, 0x62},
+ chaincfg.TestNet3Params.Bech32HRPSegwit),
+ f: func() (address.Address, error) {
+ scriptHash := []byte{
+ 0x18, 0x63, 0x14, 0x3c, 0x14, 0xc5, 0x16, 0x68,
+ 0x04, 0xbd, 0x19, 0x20, 0x33, 0x56, 0xda, 0x13,
+ 0x6c, 0x98, 0x56, 0x78, 0xcd, 0x4d, 0x27, 0xa1,
+ 0xb8, 0xc6, 0x32, 0x96, 0x04, 0x90, 0x32, 0x62}
+ return address.NewAddressWitnessScriptHash(scriptHash, &chaincfg.TestNet3Params)
+ },
+ net: &chaincfg.TestNet3Params,
+ },
+ {
+ name: "segwit testnet p2wsh witness v0",
+ addr: "tb1qqqqqp399et2xygdj5xreqhjjvcmzhxw4aywxecjdzew6hylgvsesrxh6hy",
+ encoded: "tb1qqqqqp399et2xygdj5xreqhjjvcmzhxw4aywxecjdzew6hylgvsesrxh6hy",
+ valid: true,
+ result: address.TstAddressWitnessScriptHash(
+ 0,
+ [32]byte{
+ 0x00, 0x00, 0x00, 0xc4, 0xa5, 0xca, 0xd4, 0x62,
+ 0x21, 0xb2, 0xa1, 0x87, 0x90, 0x5e, 0x52, 0x66,
+ 0x36, 0x2b, 0x99, 0xd5, 0xe9, 0x1c, 0x6c, 0xe2,
+ 0x4d, 0x16, 0x5d, 0xab, 0x93, 0xe8, 0x64, 0x33},
+ chaincfg.TestNet3Params.Bech32HRPSegwit),
+ f: func() (address.Address, error) {
+ scriptHash := []byte{
+ 0x00, 0x00, 0x00, 0xc4, 0xa5, 0xca, 0xd4, 0x62,
+ 0x21, 0xb2, 0xa1, 0x87, 0x90, 0x5e, 0x52, 0x66,
+ 0x36, 0x2b, 0x99, 0xd5, 0xe9, 0x1c, 0x6c, 0xe2,
+ 0x4d, 0x16, 0x5d, 0xab, 0x93, 0xe8, 0x64, 0x33}
+ return address.NewAddressWitnessScriptHash(scriptHash, &chaincfg.TestNet3Params)
+ },
+ net: &chaincfg.TestNet3Params,
+ },
+ {
+ name: "segwit litecoin mainnet p2wpkh v0",
+ addr: "LTC1QW508D6QEJXTDG4Y5R3ZARVARY0C5XW7KGMN4N9",
+ encoded: "ltc1qw508d6qejxtdg4y5r3zarvary0c5xw7kgmn4n9",
+ valid: true,
+ result: address.TstAddressWitnessPubKeyHash(
+ 0,
+ [20]byte{
+ 0x75, 0x1e, 0x76, 0xe8, 0x19, 0x91, 0x96, 0xd4, 0x54, 0x94,
+ 0x1c, 0x45, 0xd1, 0xb3, 0xa3, 0x23, 0xf1, 0x43, 0x3b, 0xd6},
+ CustomParams.Bech32HRPSegwit,
+ ),
+ f: func() (address.Address, error) {
+ pkHash := []byte{
+ 0x75, 0x1e, 0x76, 0xe8, 0x19, 0x91, 0x96, 0xd4, 0x54, 0x94,
+ 0x1c, 0x45, 0xd1, 0xb3, 0xa3, 0x23, 0xf1, 0x43, 0x3b, 0xd6}
+ return address.NewAddressWitnessPubKeyHash(pkHash, &customParams)
+ },
+ net: &customParams,
+ },
+
+ // P2TR address tests.
+ {
+ name: "segwit v1 mainnet p2tr",
+ addr: "bc1paardr2nczq0rx5rqpfwnvpzm497zvux64y0f7wjgcs7xuuuh2nnqwr2d5c",
+ encoded: "bc1paardr2nczq0rx5rqpfwnvpzm497zvux64y0f7wjgcs7xuuuh2nnqwr2d5c",
+ valid: true,
+ result: address.TstAddressTaproot(
+ 1, [32]byte{
+ 0xef, 0x46, 0xd1, 0xaa, 0x78, 0x10, 0x1e, 0x33,
+ 0x50, 0x60, 0x0a, 0x5d, 0x36, 0x04, 0x5b, 0xa9,
+ 0x7c, 0x26, 0x70, 0xda, 0xa9, 0x1e, 0x9f, 0x3a,
+ 0x48, 0xc4, 0x3c, 0x6e, 0x73, 0x97, 0x54, 0xe6,
+ }, chaincfg.MainNetParams.Bech32HRPSegwit,
+ ),
+ f: func() (address.Address, error) {
+ scriptHash := []byte{
+ 0xef, 0x46, 0xd1, 0xaa, 0x78, 0x10, 0x1e, 0x33,
+ 0x50, 0x60, 0x0a, 0x5d, 0x36, 0x04, 0x5b, 0xa9,
+ 0x7c, 0x26, 0x70, 0xda, 0xa9, 0x1e, 0x9f, 0x3a,
+ 0x48, 0xc4, 0x3c, 0x6e, 0x73, 0x97, 0x54, 0xe6,
+ }
+ return address.NewAddressTaproot(
+ scriptHash, &chaincfg.MainNetParams,
+ )
+ },
+ net: &chaincfg.MainNetParams,
+ },
+
+ // Invalid bech32m tests. Source:
+ // https://github.com/bitcoin/bips/blob/master/bip-0350.mediawiki
+ {
+ name: "segwit v1 invalid human-readable part",
+ addr: "tc1p0xlxvlhemja6c4dqv22uapctqupfhlxm9h8z3k2e72q4k9hcz7vq5zuyut",
+ valid: false,
+ net: &chaincfg.MainNetParams,
+ },
+ {
+ name: "segwit v1 mainnet bech32 instead of bech32m",
+ addr: "bc1p0xlxvlhemja6c4dqv22uapctqupfhlxm9h8z3k2e72q4k9hcz7vqh2y7hd",
+ valid: false,
+ net: &chaincfg.MainNetParams,
+ },
+ {
+ name: "segwit v1 testnet bech32 instead of bech32m",
+ addr: "tb1z0xlxvlhemja6c4dqv22uapctqupfhlxm9h8z3k2e72q4k9hcz7vqglt7rf",
+ valid: false,
+ net: &chaincfg.TestNet3Params,
+ },
+ {
+ name: "segwit v1 mainnet bech32 instead of bech32m upper case",
+ addr: "BC1S0XLXVLHEMJA6C4DQV22UAPCTQUPFHLXM9H8Z3K2E72Q4K9HCZ7VQ54WELL",
+ valid: false,
+ net: &chaincfg.MainNetParams,
+ },
+ {
+ name: "segwit v0 mainnet bech32m instead of bech32",
+ addr: "bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kemeawh",
+ valid: false,
+ net: &chaincfg.MainNetParams,
+ },
+ {
+ name: "segwit v1 testnet bech32 instead of bech32m second test",
+ addr: "tb1q0xlxvlhemja6c4dqv22uapctqupfhlxm9h8z3k2e72q4k9hcz7vq24jc47",
+ valid: false,
+ net: &chaincfg.TestNet3Params,
+ },
+ {
+ name: "segwit v1 mainnet bech32m invalid character in checksum",
+ addr: "bc1p38j9r5y49hruaue7wxjce0updqjuyyx0kh56v8s25huc6995vvpql3jow4",
+ valid: false,
+ net: &chaincfg.MainNetParams,
+ },
+ {
+ name: "segwit mainnet witness v17",
+ addr: "BC130XLXVLHEMJA6C4DQV22UAPCTQUPFHLXM9H8Z3K2E72Q4K9HCZ7VQ7ZWS8R",
+ valid: false,
+ net: &chaincfg.MainNetParams,
+ },
+ {
+ name: "segwit v1 mainnet bech32m invalid program length (1 byte)",
+ addr: "bc1pw5dgrnzv",
+ valid: false,
+ net: &chaincfg.MainNetParams,
+ },
+ {
+ name: "segwit v1 mainnet bech32m invalid program length (41 bytes)",
+ addr: "bc1p0xlxvlhemja6c4dqv22uapctqupfhlxm9h8z3k2e72q4k9hcz7v8n0nx0muaewav253zgeav",
+ valid: false,
+ net: &chaincfg.MainNetParams,
+ },
+ {
+ name: "segwit v1 testnet bech32m mixed case",
+ addr: "tb1p0xlxvlhemja6c4dqv22uapctqupfhlxm9h8z3k2e72q4k9hcz7vq47Zagq",
+ valid: false,
+ net: &chaincfg.TestNet3Params,
+ },
+ {
+ name: "segwit v1 mainnet bech32m zero padding of more than 4 bits",
+ addr: "bc1p0xlxvlhemja6c4dqv22uapctqupfhlxm9h8z3k2e72q4k9hcz7v07qwwzcrf",
+ valid: false,
+ net: &chaincfg.MainNetParams,
+ },
+ {
+ name: "segwit v1 mainnet bech32m non-zero padding in 8-to-5-conversion",
+ addr: "tb1p0xlxvlhemja6c4dqv22uapctqupfhlxm9h8z3k2e72q4k9hcz7vpggkg4j",
+ valid: false,
+ net: &chaincfg.TestNet3Params,
+ },
+ {
+ name: "segwit v1 mainnet bech32m empty data section",
+ addr: "bc1gmk9yu",
+ valid: false,
+ net: &chaincfg.MainNetParams,
+ },
+
+ // Unsupported witness versions (version 0 and 1 only supported at this point)
+ {
+ name: "segwit mainnet witness v16",
+ addr: "BC1SW50QA3JX3S",
+ valid: false,
+ net: &chaincfg.MainNetParams,
+ },
+ {
+ name: "segwit mainnet witness v2",
+ addr: "bc1zw508d6qejxtdg4y5r3zarvaryvg6kdaj",
+ valid: false,
+ net: &chaincfg.MainNetParams,
+ },
+ // Invalid segwit addresses
+ {
+ name: "segwit invalid hrp",
+ addr: "tc1qw508d6qejxtdg4y5r3zarvary0c5xw7kg3g4ty",
+ valid: false,
+ net: &chaincfg.TestNet3Params,
+ },
+ {
+ name: "segwit invalid checksum",
+ addr: "bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t5",
+ valid: false,
+ net: &chaincfg.MainNetParams,
+ },
+ {
+ name: "segwit invalid witness version",
+ addr: "BC13W508D6QEJXTDG4Y5R3ZARVARY0C5XW7KN40WF2",
+ valid: false,
+ net: &chaincfg.MainNetParams,
+ },
+ {
+ name: "segwit invalid program length",
+ addr: "bc1rw5uspcuh",
+ valid: false,
+ net: &chaincfg.MainNetParams,
+ },
+ {
+ name: "segwit invalid program length",
+ addr: "bc10w508d6qejxtdg4y5r3zarvary0c5xw7kw508d6qejxtdg4y5r3zarvary0c5xw7kw5rljs90",
+ valid: false,
+ net: &chaincfg.MainNetParams,
+ },
+ {
+ name: "segwit invalid program length for witness version 0 (per BIP141)",
+ addr: "BC1QR508D6QEJXTDG4Y5R3ZARVARYV98GJ9P",
+ valid: false,
+ net: &chaincfg.MainNetParams,
+ },
+ {
+ name: "segwit mixed case",
+ addr: "tb1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3q0sL5k7",
+ valid: false,
+ net: &chaincfg.TestNet3Params,
+ },
+ {
+ name: "segwit zero padding of more than 4 bits",
+ addr: "tb1pw508d6qejxtdg4y5r3zarqfsj6c3",
+ valid: false,
+ net: &chaincfg.TestNet3Params,
+ },
+ {
+ name: "segwit non-zero padding in 8-to-5 conversion",
+ addr: "tb1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3pjxtptv",
+ valid: false,
+ net: &chaincfg.TestNet3Params,
+ },
+ }
+
+ if err := chaincfg.Register(&customParams); err != nil {
+ panic(err)
+ }
+
+ for _, test := range tests {
+ // Decode addr and compare error against valid.
+ decoded, err := address.DecodeAddress(test.addr, test.net)
+ if (err == nil) != test.valid {
+ t.Errorf("%v: decoding test failed: %v", test.name, err)
+ return
+ }
+
+ if err == nil {
+ // Ensure the stringer returns the same address as the
+ // original.
+ if decodedStringer, ok := decoded.(fmt.Stringer); ok {
+ addr := test.addr
+
+ // For Segwit addresses the string representation
+ // will always be lower case, so in that case we
+ // convert the original to lower case first.
+ if strings.Contains(test.name, "segwit") {
+ addr = strings.ToLower(addr)
+ }
+
+ if addr != decodedStringer.String() {
+ t.Errorf("%v: String on decoded value does not match expected value: %v != %v",
+ test.name, test.addr, decodedStringer.String())
+ return
+ }
+ }
+
+ // Encode again and compare against the original.
+ encoded := decoded.EncodeAddress()
+ if test.encoded != encoded {
+ t.Errorf("%v: decoding and encoding produced different addresses: %v != %v",
+ test.name, test.encoded, encoded)
+ return
+ }
+
+ // Perform type-specific calculations.
+ var saddr []byte
+ switch d := decoded.(type) {
+ case *address.AddressPubKeyHash:
+ saddr = address.TstAddressSAddr(encoded)
+
+ case *address.AddressScriptHash:
+ saddr = address.TstAddressSAddr(encoded)
+
+ case *address.AddressPubKey:
+ // Ignore the error here since the script
+ // address is checked below.
+ saddr, _ = hex.DecodeString(d.String())
+ case *address.AddressWitnessPubKeyHash:
+ saddr = address.TstAddressSegwitSAddr(encoded)
+ case *address.AddressWitnessScriptHash:
+ saddr = address.TstAddressSegwitSAddr(encoded)
+ case *address.AddressTaproot:
+ saddr = address.TstAddressTaprootSAddr(encoded)
+ }
+
+ // Check script address, as well as the Hash160 method for P2PKH and
+ // P2SH addresses.
+ if !bytes.Equal(saddr, decoded.ScriptAddress()) {
+ t.Errorf("%v: script addresses do not match:\n%x != \n%x",
+ test.name, saddr, decoded.ScriptAddress())
+ return
+ }
+ switch a := decoded.(type) {
+ case *address.AddressPubKeyHash:
+ if h := a.Hash160()[:]; !bytes.Equal(saddr, h) {
+ t.Errorf("%v: hashes do not match:\n%x != \n%x",
+ test.name, saddr, h)
+ return
+ }
+
+ case *address.AddressScriptHash:
+ if h := a.Hash160()[:]; !bytes.Equal(saddr, h) {
+ t.Errorf("%v: hashes do not match:\n%x != \n%x",
+ test.name, saddr, h)
+ return
+ }
+
+ case *address.AddressWitnessPubKeyHash:
+ if hrp := a.Hrp(); test.net.Bech32HRPSegwit != hrp {
+ t.Errorf("%v: hrps do not match:\n%x != \n%x",
+ test.name, test.net.Bech32HRPSegwit, hrp)
+ return
+ }
+
+ expVer := test.result.(*address.AddressWitnessPubKeyHash).WitnessVersion()
+ if v := a.WitnessVersion(); v != expVer {
+ t.Errorf("%v: witness versions do not match:\n%x != \n%x",
+ test.name, expVer, v)
+ return
+ }
+
+ if p := a.WitnessProgram(); !bytes.Equal(saddr, p) {
+ t.Errorf("%v: witness programs do not match:\n%x != \n%x",
+ test.name, saddr, p)
+ return
+ }
+
+ case *address.AddressWitnessScriptHash:
+ if hrp := a.Hrp(); test.net.Bech32HRPSegwit != hrp {
+ t.Errorf("%v: hrps do not match:\n%x != \n%x",
+ test.name, test.net.Bech32HRPSegwit, hrp)
+ return
+ }
+
+ expVer := test.result.(*address.AddressWitnessScriptHash).WitnessVersion()
+ if v := a.WitnessVersion(); v != expVer {
+ t.Errorf("%v: witness versions do not match:\n%x != \n%x",
+ test.name, expVer, v)
+ return
+ }
+
+ if p := a.WitnessProgram(); !bytes.Equal(saddr, p) {
+ t.Errorf("%v: witness programs do not match:\n%x != \n%x",
+ test.name, saddr, p)
+ return
+ }
+ }
+
+ // Ensure the address is for the expected network.
+ if !decoded.IsForNet(test.net) {
+ t.Errorf("%v: calculated network does not match expected",
+ test.name)
+ return
+ }
+ } else {
+ // If there is an error, make sure we can print it
+ // correctly.
+ errStr := err.Error()
+ if errStr == "" {
+ t.Errorf("%v: error was non-nil but message is"+
+ "empty: %v", test.name, err)
+ }
+ }
+
+ if !test.valid {
+ // If address is invalid, but a creation function exists,
+ // verify that it returns a nil addr and non-nil error.
+ if test.f != nil {
+ _, err := test.f()
+ if err == nil {
+ t.Errorf("%v: address is invalid but creating new address succeeded",
+ test.name)
+ return
+ }
+ }
+ continue
+ }
+
+ // Valid test, compare address created with f against expected result.
+ addr, err := test.f()
+ if err != nil {
+ t.Errorf("%v: address is valid but creating new address failed with error %v",
+ test.name, err)
+ return
+ }
+
+ if !reflect.DeepEqual(addr, test.result) {
+ t.Errorf("%v: created address does not match expected result",
+ test.name)
+ return
+ }
+ }
+}
diff --git a/address/base58/README.md b/address/base58/README.md
new file mode 100644
index 0000000..1fb7f27
--- /dev/null
+++ b/address/base58/README.md
@@ -0,0 +1,34 @@
+base58
+==========
+
+[](https://github.com/btcsuite/btcd/actions)
+[](http://copyfree.org)
+[](http://godoc.org/github.com/btcsuite/btcd/address/v2/base58)
+
+Package base58 provides an API for encoding and decoding to and from the
+modified base58 encoding. It also provides an API to do Base58Check encoding,
+as described [here](https://en.bitcoin.it/wiki/Base58Check_encoding).
+
+A comprehensive suite of tests is provided to ensure proper functionality.
+
+## Installation and Updating
+
+```bash
+$ go get -u github.com/btcsuite/btcd/address/v2/base58
+```
+
+## Examples
+
+* [Decode Example](http://godoc.org/github.com/btcsuite/btcd/address/v2/base58#example-Decode)
+ Demonstrates how to decode modified base58 encoded data.
+* [Encode Example](http://godoc.org/github.com/btcsuite/btcd/address/v2/base58#example-Encode)
+ Demonstrates how to encode data using the modified base58 encoding scheme.
+* [CheckDecode Example](http://godoc.org/github.com/btcsuite/btcd/address/v2/base58#example-CheckDecode)
+ Demonstrates how to decode Base58Check encoded data.
+* [CheckEncode Example](http://godoc.org/github.com/btcsuite/btcd/address/v2/base58#example-CheckEncode)
+ Demonstrates how to encode data using the Base58Check encoding scheme.
+
+## License
+
+Package base58 is licensed under the [copyfree](http://copyfree.org) ISC
+License.
diff --git a/address/base58/alphabet.go b/address/base58/alphabet.go
new file mode 100644
index 0000000..6bb39fe
--- /dev/null
+++ b/address/base58/alphabet.go
@@ -0,0 +1,49 @@
+// Copyright (c) 2015 The btcsuite developers
+// Use of this source code is governed by an ISC
+// license that can be found in the LICENSE file.
+
+// AUTOGENERATED by genalphabet.go; do not edit.
+
+package base58
+
+const (
+ // alphabet is the modified base58 alphabet used by Bitcoin.
+ alphabet = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"
+
+ alphabetIdx0 = '1'
+)
+
+var b58 = [256]byte{
+ 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 0, 1, 2, 3, 4, 5, 6,
+ 7, 8, 255, 255, 255, 255, 255, 255,
+ 255, 9, 10, 11, 12, 13, 14, 15,
+ 16, 255, 17, 18, 19, 20, 21, 255,
+ 22, 23, 24, 25, 26, 27, 28, 29,
+ 30, 31, 32, 255, 255, 255, 255, 255,
+ 255, 33, 34, 35, 36, 37, 38, 39,
+ 40, 41, 42, 43, 255, 44, 45, 46,
+ 47, 48, 49, 50, 51, 52, 53, 54,
+ 55, 56, 57, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255,
+}
diff --git a/address/base58/base58.go b/address/base58/base58.go
new file mode 100644
index 0000000..bd0ea47
--- /dev/null
+++ b/address/base58/base58.go
@@ -0,0 +1,142 @@
+// Copyright (c) 2013-2015 The btcsuite developers
+// Use of this source code is governed by an ISC
+// license that can be found in the LICENSE file.
+
+package base58
+
+import (
+ "math/big"
+)
+
+//go:generate go run genalphabet.go
+
+var bigRadix = [...]*big.Int{
+ big.NewInt(0),
+ big.NewInt(58),
+ big.NewInt(58 * 58),
+ big.NewInt(58 * 58 * 58),
+ big.NewInt(58 * 58 * 58 * 58),
+ big.NewInt(58 * 58 * 58 * 58 * 58),
+ big.NewInt(58 * 58 * 58 * 58 * 58 * 58),
+ big.NewInt(58 * 58 * 58 * 58 * 58 * 58 * 58),
+ big.NewInt(58 * 58 * 58 * 58 * 58 * 58 * 58 * 58),
+ big.NewInt(58 * 58 * 58 * 58 * 58 * 58 * 58 * 58 * 58),
+ bigRadix10,
+}
+
+var bigRadix10 = big.NewInt(58 * 58 * 58 * 58 * 58 * 58 * 58 * 58 * 58 * 58) // 58^10
+
+// Decode decodes a modified base58 string to a byte slice.
+func Decode(b string) []byte {
+ answer := big.NewInt(0)
+ scratch := new(big.Int)
+
+ // Calculating with big.Int is slow for each iteration.
+ // x += b58[b[i]] * j
+ // j *= 58
+ //
+ // Instead we can try to do as much calculations on int64.
+ // We can represent a 10 digit base58 number using an int64.
+ //
+ // Hence we'll try to convert 10, base58 digits at a time.
+ // The rough idea is to calculate `t`, such that:
+ //
+ // t := b58[b[i+9]] * 58^9 ... + b58[b[i+1]] * 58^1 + b58[b[i]] * 58^0
+ // x *= 58^10
+ // x += t
+ //
+ // Of course, in addition, we'll need to handle boundary condition when `b` is not multiple of 58^10.
+ // In that case we'll use the bigRadix[n] lookup for the appropriate power.
+ for t := b; len(t) > 0; {
+ n := len(t)
+ if n > 10 {
+ n = 10
+ }
+
+ total := uint64(0)
+ for _, v := range t[:n] {
+ if v > 255 {
+ return []byte("")
+ }
+
+ tmp := b58[v]
+ if tmp == 255 {
+ return []byte("")
+ }
+ total = total*58 + uint64(tmp)
+ }
+
+ answer.Mul(answer, bigRadix[n])
+ scratch.SetUint64(total)
+ answer.Add(answer, scratch)
+
+ t = t[n:]
+ }
+
+ tmpval := answer.Bytes()
+
+ var numZeros int
+ for numZeros = 0; numZeros < len(b); numZeros++ {
+ if b[numZeros] != alphabetIdx0 {
+ break
+ }
+ }
+ flen := numZeros + len(tmpval)
+ val := make([]byte, flen)
+ copy(val[numZeros:], tmpval)
+
+ return val
+}
+
+// Encode encodes a byte slice to a modified base58 string.
+func Encode(b []byte) string {
+ x := new(big.Int)
+ x.SetBytes(b)
+
+ // maximum length of output is log58(2^(8*len(b))) == len(b) * 8 / log(58)
+ maxlen := int(float64(len(b))*1.365658237309761) + 1
+ answer := make([]byte, 0, maxlen)
+ mod := new(big.Int)
+ for x.Sign() > 0 {
+ // Calculating with big.Int is slow for each iteration.
+ // x, mod = x / 58, x % 58
+ //
+ // Instead we can try to do as much calculations on int64.
+ // x, mod = x / 58^10, x % 58^10
+ //
+ // Which will give us mod, which is 10 digit base58 number.
+ // We'll loop that 10 times to convert to the answer.
+
+ x.DivMod(x, bigRadix10, mod)
+ if x.Sign() == 0 {
+ // When x = 0, we need to ensure we don't add any extra zeros.
+ m := mod.Int64()
+ for m > 0 {
+ answer = append(answer, alphabet[m%58])
+ m /= 58
+ }
+ } else {
+ m := mod.Int64()
+ for i := 0; i < 10; i++ {
+ answer = append(answer, alphabet[m%58])
+ m /= 58
+ }
+ }
+ }
+
+ // leading zero bytes
+ for _, i := range b {
+ if i != 0 {
+ break
+ }
+ answer = append(answer, alphabetIdx0)
+ }
+
+ // reverse
+ alen := len(answer)
+ for i := 0; i < alen/2; i++ {
+ answer[i], answer[alen-1-i] = answer[alen-1-i], answer[i]
+ }
+
+ return string(answer)
+}
diff --git a/address/base58/base58_test.go b/address/base58/base58_test.go
new file mode 100644
index 0000000..fc5098e
--- /dev/null
+++ b/address/base58/base58_test.go
@@ -0,0 +1,103 @@
+// Copyright (c) 2013-2017 The btcsuite developers
+// Use of this source code is governed by an ISC
+// license that can be found in the LICENSE file.
+
+package base58_test
+
+import (
+ "bytes"
+ "encoding/hex"
+ "testing"
+
+ "github.com/btcsuite/btcd/address/v2/base58"
+)
+
+var stringTests = []struct {
+ in string
+ out string
+}{
+ {"", ""},
+ {" ", "Z"},
+ {"-", "n"},
+ {"0", "q"},
+ {"1", "r"},
+ {"-1", "4SU"},
+ {"11", "4k8"},
+ {"abc", "ZiCa"},
+ {"1234598760", "3mJr7AoUXx2Wqd"},
+ {"abcdefghijklmnopqrstuvwxyz", "3yxU3u1igY8WkgtjK92fbJQCd4BZiiT1v25f"},
+ {"00000000000000000000000000000000000000000000000000000000000000", "3sN2THZeE9Eh9eYrwkvZqNstbHGvrxSAM7gXUXvyFQP8XvQLUqNCS27icwUeDT7ckHm4FUHM2mTVh1vbLmk7y"},
+}
+
+var invalidStringTests = []struct {
+ in string
+ out string
+}{
+ {"0", ""},
+ {"O", ""},
+ {"I", ""},
+ {"l", ""},
+ {"3mJr0", ""},
+ {"O3yxU", ""},
+ {"3sNI", ""},
+ {"4kl8", ""},
+ {"0OIl", ""},
+ {"!@#$%^&*()-_=+~`", ""},
+ {"abcd\xd80", ""},
+ {"abcd\U000020BF", ""},
+}
+
+var hexTests = []struct {
+ in string
+ out string
+}{
+ {"", ""},
+ {"61", "2g"},
+ {"626262", "a3gV"},
+ {"636363", "aPEr"},
+ {"73696d706c792061206c6f6e6720737472696e67", "2cFupjhnEsSn59qHXstmK2ffpLv2"},
+ {"00eb15231dfceb60925886b67d065299925915aeb172c06647", "1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L"},
+ {"516b6fcd0f", "ABnLTmg"},
+ {"bf4f89001e670274dd", "3SEo3LWLoPntC"},
+ {"572e4794", "3EFU7m"},
+ {"ecac89cad93923c02321", "EJDM8drfXA6uyA"},
+ {"10c8511e", "Rt5zm"},
+ {"00000000000000000000", "1111111111"},
+ {"000111d38e5fc9071ffcd20b4a763cc9ae4f252bb4e48fd66a835e252ada93ff480d6dd43dc62a641155a5", "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"},
+ {"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", "1cWB5HCBdLjAuqGGReWE3R3CguuwSjw6RHn39s2yuDRTS5NsBgNiFpWgAnEx6VQi8csexkgYw3mdYrMHr8x9i7aEwP8kZ7vccXWqKDvGv3u1GxFKPuAkn8JCPPGDMf3vMMnbzm6Nh9zh1gcNsMvH3ZNLmP5fSG6DGbbi2tuwMWPthr4boWwCxf7ewSgNQeacyozhKDDQQ1qL5fQFUW52QKUZDZ5fw3KXNQJMcNTcaB723LchjeKun7MuGW5qyCBZYzA1KjofN1gYBV3NqyhQJ3Ns746GNuf9N2pQPmHz4xpnSrrfCvy6TVVz5d4PdrjeshsWQwpZsZGzvbdAdN8MKV5QsBDY"},
+}
+
+func TestBase58(t *testing.T) {
+ // Encode tests
+ for x, test := range stringTests {
+ tmp := []byte(test.in)
+ if res := base58.Encode(tmp); res != test.out {
+ t.Errorf("Encode test #%d failed: got: %s want: %s",
+ x, res, test.out)
+ continue
+ }
+ }
+
+ // Decode tests
+ for x, test := range hexTests {
+ b, err := hex.DecodeString(test.in)
+ if err != nil {
+ t.Errorf("hex.DecodeString failed failed #%d: got: %s", x, test.in)
+ continue
+ }
+ if res := base58.Decode(test.out); !bytes.Equal(res, b) {
+ t.Errorf("Decode test #%d failed: got: %q want: %q",
+ x, res, test.in)
+ continue
+ }
+ }
+
+ // Decode with invalid input
+ for x, test := range invalidStringTests {
+ if res := base58.Decode(test.in); string(res) != test.out {
+ t.Errorf("Decode invalidString test #%d failed: got: %q want: %q",
+ x, res, test.out)
+ continue
+ }
+ }
+}
diff --git a/address/base58/base58bench_test.go b/address/base58/base58bench_test.go
new file mode 100644
index 0000000..a16bd3a
--- /dev/null
+++ b/address/base58/base58bench_test.go
@@ -0,0 +1,47 @@
+// Copyright (c) 2013-2014 The btcsuite developers
+// Use of this source code is governed by an ISC
+// license that can be found in the LICENSE file.
+
+package base58_test
+
+import (
+ "bytes"
+ "testing"
+
+ "github.com/btcsuite/btcd/address/v2/base58"
+)
+
+var (
+ raw5k = bytes.Repeat([]byte{0xff}, 5000)
+ raw100k = bytes.Repeat([]byte{0xff}, 100*1000)
+ encoded5k = base58.Encode(raw5k)
+ encoded100k = base58.Encode(raw100k)
+)
+
+func BenchmarkBase58Encode_5K(b *testing.B) {
+ b.SetBytes(int64(len(raw5k)))
+ for i := 0; i < b.N; i++ {
+ base58.Encode(raw5k)
+ }
+}
+
+func BenchmarkBase58Encode_100K(b *testing.B) {
+ b.SetBytes(int64(len(raw100k)))
+ for i := 0; i < b.N; i++ {
+ base58.Encode(raw100k)
+ }
+}
+
+func BenchmarkBase58Decode_5K(b *testing.B) {
+ b.SetBytes(int64(len(encoded5k)))
+ for i := 0; i < b.N; i++ {
+ base58.Decode(encoded5k)
+ }
+}
+
+func BenchmarkBase58Decode_100K(b *testing.B) {
+ b.SetBytes(int64(len(encoded100k)))
+ for i := 0; i < b.N; i++ {
+ base58.Decode(encoded100k)
+ }
+}
diff --git a/address/base58/base58check.go b/address/base58/base58check.go
new file mode 100644
index 0000000..402c323
--- /dev/null
+++ b/address/base58/base58check.go
@@ -0,0 +1,52 @@
+// Copyright (c) 2013-2014 The btcsuite developers
+// Use of this source code is governed by an ISC
+// license that can be found in the LICENSE file.
+
+package base58
+
+import (
+ "crypto/sha256"
+ "errors"
+)
+
+// ErrChecksum indicates that the checksum of a check-encoded string does not verify against
+// the checksum.
+var ErrChecksum = errors.New("checksum error")
+
+// ErrInvalidFormat indicates that the check-encoded string has an invalid format.
+var ErrInvalidFormat = errors.New("invalid format: version and/or checksum bytes missing")
+
+// checksum: first four bytes of sha256^2
+func checksum(input []byte) (cksum [4]byte) {
+ h := sha256.Sum256(input)
+ h2 := sha256.Sum256(h[:])
+ copy(cksum[:], h2[:4])
+ return
+}
+
+// CheckEncode prepends a version byte and appends a four byte checksum.
+func CheckEncode(input []byte, version byte) string {
+ b := make([]byte, 0, 1+len(input)+4)
+ b = append(b, version)
+ b = append(b, input...)
+ cksum := checksum(b)
+ b = append(b, cksum[:]...)
+ return Encode(b)
+}
+
+// CheckDecode decodes a string that was encoded with CheckEncode and verifies the checksum.
+func CheckDecode(input string) (result []byte, version byte, err error) {
+ decoded := Decode(input)
+ if len(decoded) < 5 {
+ return nil, 0, ErrInvalidFormat
+ }
+ version = decoded[0]
+ var cksum [4]byte
+ copy(cksum[:], decoded[len(decoded)-4:])
+ if checksum(decoded[:len(decoded)-4]) != cksum {
+ return nil, 0, ErrChecksum
+ }
+ payload := decoded[1 : len(decoded)-4]
+ result = append(result, payload...)
+ return
+}
diff --git a/address/base58/base58check_test.go b/address/base58/base58check_test.go
new file mode 100644
index 0000000..8fa412b
--- /dev/null
+++ b/address/base58/base58check_test.go
@@ -0,0 +1,69 @@
+// Copyright (c) 2013-2014 The btcsuite developers
+// Use of this source code is governed by an ISC
+// license that can be found in the LICENSE file.
+
+package base58_test
+
+import (
+ "testing"
+
+ "github.com/btcsuite/btcd/address/v2/base58"
+)
+
+var checkEncodingStringTests = []struct {
+ version byte
+ in string
+ out string
+}{
+ {20, "", "3MNQE1X"},
+ {20, " ", "B2Kr6dBE"},
+ {20, "-", "B3jv1Aft"},
+ {20, "0", "B482yuaX"},
+ {20, "1", "B4CmeGAC"},
+ {20, "-1", "mM7eUf6kB"},
+ {20, "11", "mP7BMTDVH"},
+ {20, "abc", "4QiVtDjUdeq"},
+ {20, "1234598760", "ZmNb8uQn5zvnUohNCEPP"},
+ {20, "abcdefghijklmnopqrstuvwxyz", "K2RYDcKfupxwXdWhSAxQPCeiULntKm63UXyx5MvEH2"},
+ {20, "00000000000000000000000000000000000000000000000000000000000000", "bi1EWXwJay2udZVxLJozuTb8Meg4W9c6xnmJaRDjg6pri5MBAxb9XwrpQXbtnqEoRV5U2pixnFfwyXC8tRAVC8XxnjK"},
+}
+
+func TestBase58Check(t *testing.T) {
+ for x, test := range checkEncodingStringTests {
+ // test encoding
+ if res := base58.CheckEncode([]byte(test.in), test.version); res != test.out {
+ t.Errorf("CheckEncode test #%d failed: got %s, want: %s", x, res, test.out)
+ }
+
+ // test decoding
+ res, version, err := base58.CheckDecode(test.out)
+ switch {
+ case err != nil:
+ t.Errorf("CheckDecode test #%d failed with err: %v", x, err)
+
+ case version != test.version:
+ t.Errorf("CheckDecode test #%d failed: got version: %d want: %d", x, version, test.version)
+
+ case string(res) != test.in:
+ t.Errorf("CheckDecode test #%d failed: got: %s want: %s", x, res, test.in)
+ }
+ }
+
+ // test the two decoding failure cases
+ // case 1: checksum error
+ _, _, err := base58.CheckDecode("3MNQE1Y")
+ if err != base58.ErrChecksum {
+ t.Error("Checkdecode test failed, expected ErrChecksum")
+ }
+ // case 2: invalid formats (string lengths below 5 mean the version byte and/or the checksum
+ // bytes are missing).
+ testString := ""
+ for len := 0; len < 4; len++ {
+ testString += "x"
+ _, _, err = base58.CheckDecode(testString)
+ if err != base58.ErrInvalidFormat {
+ t.Error("Checkdecode test failed, expected ErrInvalidFormat")
+ }
+ }
+
+}
diff --git a/address/base58/cov_report.sh b/address/base58/cov_report.sh
new file mode 100644
index 0000000..e41c928
--- /dev/null
+++ b/address/base58/cov_report.sh
@@ -0,0 +1,9 @@
+#!/bin/sh
+
+# This script uses the standard Go test coverage tools to generate a test coverage report.
+
+# Run tests with coverage enabled and generate coverage profile.
+go test -cover -coverprofile=coverage.txt ./...
+
+# Display function-level coverage statistics.
+go tool cover -func=coverage.txt
diff --git a/address/base58/doc.go b/address/base58/doc.go
new file mode 100644
index 0000000..d657f05
--- /dev/null
+++ b/address/base58/doc.go
@@ -0,0 +1,29 @@
+// Copyright (c) 2014 The btcsuite developers
+// Use of this source code is governed by an ISC
+// license that can be found in the LICENSE file.
+
+/*
+Package base58 provides an API for working with modified base58 and Base58Check
+encodings.
+
+# Modified Base58 Encoding
+
+Standard base58 encoding is similar to standard base64 encoding except, as the
+name implies, it uses a 58 character alphabet which results in an alphanumeric
+string and allows some characters which are problematic for humans to be
+excluded. Due to this, there can be various base58 alphabets.
+
+The modified base58 alphabet used by Bitcoin, and hence this package, omits the
+0, O, I, and l characters that look the same in many fonts and are therefore
+hard to humans to distinguish.
+
+# Base58Check Encoding Scheme
+
+The Base58Check encoding scheme is primarily used for Bitcoin addresses at the
+time of this writing, however it can be used to generically encode arbitrary
+byte arrays into human-readable strings along with a version byte that can be
+used to differentiate the same payload. For Bitcoin addresses, the extra
+version is used to differentiate the network of otherwise identical public keys
+which helps prevent using an address intended for one network on another.
+*/
+package base58
diff --git a/address/base58/example_test.go b/address/base58/example_test.go
new file mode 100644
index 0000000..803f575
--- /dev/null
+++ b/address/base58/example_test.go
@@ -0,0 +1,71 @@
+// Copyright (c) 2014 The btcsuite developers
+// Use of this source code is governed by an ISC
+// license that can be found in the LICENSE file.
+
+package base58_test
+
+import (
+ "fmt"
+
+ "github.com/btcsuite/btcd/address/v2/base58"
+)
+
+// This example demonstrates how to decode modified base58 encoded data.
+func ExampleDecode() {
+ // Decode example modified base58 encoded data.
+ encoded := "25JnwSn7XKfNQ"
+ decoded := base58.Decode(encoded)
+
+ // Show the decoded data.
+ fmt.Println("Decoded Data:", string(decoded))
+
+ // Output:
+ // Decoded Data: Test data
+}
+
+// This example demonstrates how to encode data using the modified base58
+// encoding scheme.
+func ExampleEncode() {
+ // Encode example data with the modified base58 encoding scheme.
+ data := []byte("Test data")
+ encoded := base58.Encode(data)
+
+ // Show the encoded data.
+ fmt.Println("Encoded Data:", encoded)
+
+ // Output:
+ // Encoded Data: 25JnwSn7XKfNQ
+}
+
+// This example demonstrates how to decode Base58Check encoded data.
+func ExampleCheckDecode() {
+ // Decode an example Base58Check encoded data.
+ encoded := "1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa"
+ decoded, version, err := base58.CheckDecode(encoded)
+ if err != nil {
+ fmt.Println(err)
+ return
+ }
+
+ // Show the decoded data.
+ fmt.Printf("Decoded data: %x\n", decoded)
+ fmt.Println("Version Byte:", version)
+
+ // Output:
+ // Decoded data: 62e907b15cbf27d5425399ebf6f0fb50ebb88f18
+ // Version Byte: 0
+}
+
+// This example demonstrates how to encode data using the Base58Check encoding
+// scheme.
+func ExampleCheckEncode() {
+ // Encode example data with the Base58Check encoding scheme.
+ data := []byte("Test data")
+ encoded := base58.CheckEncode(data, 0)
+
+ // Show the encoded data.
+ fmt.Println("Encoded Data:", encoded)
+
+ // Output:
+ // Encoded Data: 182iP79GRURMp7oMHDU
+}
diff --git a/address/base58/genalphabet.go b/address/base58/genalphabet.go
new file mode 100644
index 0000000..959f34d
--- /dev/null
+++ b/address/base58/genalphabet.go
@@ -0,0 +1,80 @@
+// Copyright (c) 2015 The btcsuite developers
+// Use of this source code is governed by an ISC
+// license that can be found in the LICENSE file.
+
+//go:build ignore
+// +build ignore
+
+package main
+
+import (
+ "bytes"
+ "io"
+ "log"
+ "os"
+ "strconv"
+)
+
+var (
+ start = []byte(`// Copyright (c) 2015 The btcsuite developers
+// Use of this source code is governed by an ISC
+// license that can be found in the LICENSE file.
+
+// AUTOGENERATED by genalphabet.go; do not edit.
+
+package base58
+
+const (
+ // alphabet is the modified base58 alphabet used by Bitcoin.
+ alphabet = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"
+
+ alphabetIdx0 = '1'
+)
+
+var b58 = [256]byte{`)
+
+ end = []byte(`}`)
+
+ alphabet = []byte("123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz")
+ tab = []byte("\t")
+ invalid = []byte("255")
+ comma = []byte(",")
+ space = []byte(" ")
+ nl = []byte("\n")
+)
+
+func write(w io.Writer, b []byte) {
+ _, err := w.Write(b)
+ if err != nil {
+ log.Fatal(err)
+ }
+}
+
+func main() {
+ fi, err := os.Create("alphabet.go")
+ if err != nil {
+ log.Fatal(err)
+ }
+ defer fi.Close()
+
+ write(fi, start)
+ write(fi, nl)
+ for i := byte(0); i < 32; i++ {
+ write(fi, tab)
+ for j := byte(0); j < 8; j++ {
+ idx := bytes.IndexByte(alphabet, i*8+j)
+ if idx == -1 {
+ write(fi, invalid)
+ } else {
+ write(fi, strconv.AppendInt(nil, int64(idx), 10))
+ }
+ write(fi, comma)
+ if j != 7 {
+ write(fi, space)
+ }
+ }
+ write(fi, nl)
+ }
+ write(fi, end)
+ write(fi, nl)
+}
diff --git a/address/bech32/README.md b/address/bech32/README.md
new file mode 100644
index 0000000..eed3550
--- /dev/null
+++ b/address/bech32/README.md
@@ -0,0 +1,29 @@
+bech32
+==========
+
+[](https://github.com/btcsuite/btcd/actions)
+[](http://copyfree.org)
+[](http://godoc.org/github.com/btcsuite/btcd/address/v2/bech32)
+
+Package bech32 provides a Go implementation of the bech32 format specified in
+[BIP 173](https://github.com/bitcoin/bips/blob/master/bip-0173.mediawiki).
+
+Test vectors from BIP 173 are added to ensure compatibility with the BIP.
+
+## Installation and Updating
+
+```bash
+$ go get -u github.com/btcsuite/btcd/address/v2/bech32
+```
+
+## Examples
+
+* [Bech32 decode Example](http://godoc.org/github.com/btcsuite/btcd/address/v2/bech32#example-Bech32Decode)
+ Demonstrates how to decode a bech32 encoded string.
+* [Bech32 encode Example](http://godoc.org/github.com/btcsuite/btcd/address/v2/bech32#example-BechEncode)
+ Demonstrates how to encode data into a bech32 string.
+
+## License
+
+Package bech32 is licensed under the [copyfree](http://copyfree.org) ISC
+License.
diff --git a/address/bech32/bech32.go b/address/bech32/bech32.go
new file mode 100644
index 0000000..92994b2
--- /dev/null
+++ b/address/bech32/bech32.go
@@ -0,0 +1,445 @@
+// Copyright (c) 2017 The btcsuite developers
+// Copyright (c) 2019 The Decred developers
+// Use of this source code is governed by an ISC
+// license that can be found in the LICENSE file.
+
+package bech32
+
+import (
+ "strings"
+)
+
+// charset is the set of characters used in the data section of bech32 strings.
+// Note that this is ordered, such that for a given charset[i], i is the binary
+// value of the character.
+const charset = "qpzry9x8gf2tvdw0s3jn54khce6mua7l"
+
+// gen encodes the generator polynomial for the bech32 BCH checksum.
+var gen = []int{0x3b6a57b2, 0x26508e6d, 0x1ea119fa, 0x3d4233dd, 0x2a1462b3}
+
+// toBytes converts each character in the string 'chars' to the value of the
+// index of the corresponding character in 'charset'.
+func toBytes(chars string) ([]byte, error) {
+ decoded := make([]byte, 0, len(chars))
+ for i := 0; i < len(chars); i++ {
+ index := strings.IndexByte(charset, chars[i])
+ if index < 0 {
+ return nil, ErrNonCharsetChar(chars[i])
+ }
+ decoded = append(decoded, byte(index))
+ }
+ return decoded, nil
+}
+
+// bech32Polymod calculates the BCH checksum for a given hrp, values and
+// checksum data. Checksum is optional, and if nil a 0 checksum is assumed.
+//
+// Values and checksum (if provided) MUST be encoded as 5 bits per element (base
+// 32), otherwise the results are undefined.
+//
+// For more details on the polymod calculation, please refer to BIP 173.
+func bech32Polymod(hrp string, values, checksum []byte) int {
+ chk := 1
+
+ // Account for the high bits of the HRP in the checksum.
+ for i := 0; i < len(hrp); i++ {
+ b := chk >> 25
+ hiBits := int(hrp[i]) >> 5
+ chk = (chk&0x1ffffff)<<5 ^ hiBits
+ for i := 0; i < 5; i++ {
+ if (b>>uint(i))&1 == 1 {
+ chk ^= gen[i]
+ }
+ }
+ }
+
+ // Account for the separator (0) between high and low bits of the HRP.
+ // x^0 == x, so we eliminate the redundant xor used in the other rounds.
+ b := chk >> 25
+ chk = (chk & 0x1ffffff) << 5
+ for i := 0; i < 5; i++ {
+ if (b>>uint(i))&1 == 1 {
+ chk ^= gen[i]
+ }
+ }
+
+ // Account for the low bits of the HRP.
+ for i := 0; i < len(hrp); i++ {
+ b := chk >> 25
+ loBits := int(hrp[i]) & 31
+ chk = (chk&0x1ffffff)<<5 ^ loBits
+ for i := 0; i < 5; i++ {
+ if (b>>uint(i))&1 == 1 {
+ chk ^= gen[i]
+ }
+ }
+ }
+
+ // Account for the values.
+ for _, v := range values {
+ b := chk >> 25
+ chk = (chk&0x1ffffff)<<5 ^ int(v)
+ for i := 0; i < 5; i++ {
+ if (b>>uint(i))&1 == 1 {
+ chk ^= gen[i]
+ }
+ }
+ }
+
+ if checksum == nil {
+ // A nil checksum is used during encoding, so assume all bytes are zero.
+ // x^0 == x, so we eliminate the redundant xor used in the other rounds.
+ for v := 0; v < 6; v++ {
+ b := chk >> 25
+ chk = (chk & 0x1ffffff) << 5
+ for i := 0; i < 5; i++ {
+ if (b>>uint(i))&1 == 1 {
+ chk ^= gen[i]
+ }
+ }
+ }
+ } else {
+ // Checksum is provided during decoding, so use it.
+ for _, v := range checksum {
+ b := chk >> 25
+ chk = (chk&0x1ffffff)<<5 ^ int(v)
+ for i := 0; i < 5; i++ {
+ if (b>>uint(i))&1 == 1 {
+ chk ^= gen[i]
+ }
+ }
+ }
+ }
+
+ return chk
+}
+
+// writeBech32Checksum calculates the checksum data expected for a string that
+// will have the given hrp and payload data and writes it to the provided string
+// builder.
+//
+// The payload data MUST be encoded as a base 32 (5 bits per element) byte slice
+// and the hrp MUST only use the allowed character set (ascii chars between 33
+// and 126), otherwise the results are undefined.
+//
+// For more details on the checksum calculation, please refer to BIP 173.
+func writeBech32Checksum(hrp string, data []byte, bldr *strings.Builder,
+ version Version) {
+
+ bech32Const := int(VersionToConsts[version])
+ polymod := bech32Polymod(hrp, data, nil) ^ bech32Const
+ for i := 0; i < 6; i++ {
+ b := byte((polymod >> uint(5*(5-i))) & 31)
+
+ // This can't fail, given we explicitly cap the previous b byte by the
+ // first 31 bits.
+ c := charset[b]
+ bldr.WriteByte(c)
+ }
+}
+
+// bech32VerifyChecksum verifies whether the bech32 string specified by the
+// provided hrp and payload data (encoded as 5 bits per element byte slice) has
+// the correct checksum suffix. The version of bech32 used (bech32 OG, or
+// bech32m) is also returned to allow the caller to perform proper address
+// validation (segwitv0 should use bech32, v1+ should use bech32m).
+//
+// Data MUST have more than 6 elements, otherwise this function panics.
+//
+// For more details on the checksum verification, please refer to BIP 173.
+func bech32VerifyChecksum(hrp string, data []byte) (Version, bool) {
+ checksum := data[len(data)-6:]
+ values := data[:len(data)-6]
+ polymod := bech32Polymod(hrp, values, checksum)
+
+ // Before BIP-350, we'd always check this against a static constant of
+ // 1 to know if the checksum was computed properly. As we want to
+ // generically support decoding for bech32m as well as bech32, we'll
+ // look up the returned value and compare it to the set of defined
+ // constants.
+ bech32Version, ok := ConstsToVersion[ChecksumConst(polymod)]
+ if ok {
+ return bech32Version, true
+ }
+
+ return VersionUnknown, false
+}
+
+// DecodeNoLimitWithVersion is a bech32 checksum version aware arbitrary string
+// length decoder. This function will return the version of the decoded
+// checksum constant so higher level validation can be performed to ensure the
+// correct version of bech32 was used when encoding.
+//
+// Note that the returned data is 5-bit (base32) encoded and the human-readable
+// part will be lowercase.
+func DecodeNoLimitWithVersion(bech string) (string, []byte, Version, error) {
+ // The minimum allowed size of a bech32 string is 8 characters, since it
+ // needs a non-empty HRP, a separator, and a 6 character checksum.
+ if len(bech) < 8 {
+ return "", nil, VersionUnknown, ErrInvalidLength(len(bech))
+ }
+
+ // Only ASCII characters between 33 and 126 are allowed.
+ var hasLower, hasUpper bool
+ for i := 0; i < len(bech); i++ {
+ if bech[i] < 33 || bech[i] > 126 {
+ return "", nil, VersionUnknown, ErrInvalidCharacter(bech[i])
+ }
+
+ // The characters must be either all lowercase or all uppercase. Testing
+ // directly with ascii codes is safe here, given the previous test.
+ hasLower = hasLower || (bech[i] >= 97 && bech[i] <= 122)
+ hasUpper = hasUpper || (bech[i] >= 65 && bech[i] <= 90)
+ if hasLower && hasUpper {
+ return "", nil, VersionUnknown, ErrMixedCase{}
+ }
+ }
+
+ // Bech32 standard uses only the lowercase for of strings for checksum
+ // calculation.
+ if hasUpper {
+ bech = strings.ToLower(bech)
+ }
+
+ // The string is invalid if the last '1' is non-existent, it is the
+ // first character of the string (no human-readable part) or one of the
+ // last 6 characters of the string (since checksum cannot contain '1').
+ one := strings.LastIndexByte(bech, '1')
+ if one < 1 || one+7 > len(bech) {
+ return "", nil, VersionUnknown, ErrInvalidSeparatorIndex(one)
+ }
+
+ // The human-readable part is everything before the last '1'.
+ hrp := bech[:one]
+ data := bech[one+1:]
+
+ // Each character corresponds to the byte with value of the index in
+ // 'charset'.
+ decoded, err := toBytes(data)
+ if err != nil {
+ return "", nil, VersionUnknown, err
+ }
+
+ // Verify if the checksum (stored inside decoded[:]) is valid, given the
+ // previously decoded hrp.
+ bech32Version, ok := bech32VerifyChecksum(hrp, decoded)
+ if !ok {
+ // Invalid checksum. Calculate what it should have been, so that the
+ // error contains this information.
+
+ // Extract the payload bytes and actual checksum in the string.
+ actual := bech[len(bech)-6:]
+ payload := decoded[:len(decoded)-6]
+
+ // Calculate the expected checksum, given the hrp and payload
+ // data. We'll actually compute _both_ possibly valid checksum
+ // to further aide in debugging.
+ var expectedBldr strings.Builder
+ expectedBldr.Grow(6)
+ writeBech32Checksum(hrp, payload, &expectedBldr, Version0)
+ expectedVersion0 := expectedBldr.String()
+
+ var b strings.Builder
+ b.Grow(6)
+ writeBech32Checksum(hrp, payload, &expectedBldr, VersionM)
+ expectedVersionM := expectedBldr.String()
+
+ err = ErrInvalidChecksum{
+ Expected: expectedVersion0,
+ ExpectedM: expectedVersionM,
+ Actual: actual,
+ }
+ return "", nil, VersionUnknown, err
+ }
+
+ // We exclude the last 6 bytes, which is the checksum.
+ return hrp, decoded[:len(decoded)-6], bech32Version, nil
+}
+
+// DecodeNoLimit decodes a bech32 encoded string, returning the human-readable
+// part and the data part excluding the checksum. This function does NOT
+// validate against the BIP-173 maximum length allowed for bech32 strings and
+// is meant for use in custom applications (such as lightning network payment
+// requests), NOT on-chain addresses.
+//
+// Note that the returned data is 5-bit (base32) encoded and the human-readable
+// part will be lowercase.
+func DecodeNoLimit(bech string) (string, []byte, error) {
+ hrp, data, _, err := DecodeNoLimitWithVersion(bech)
+ return hrp, data, err
+}
+
+// Decode decodes a bech32 encoded string, returning the human-readable part and
+// the data part excluding the checksum.
+//
+// Note that the returned data is 5-bit (base32) encoded and the human-readable
+// part will be lowercase.
+func Decode(bech string) (string, []byte, error) {
+ // The maximum allowed length for a bech32 string is 90.
+ if len(bech) > 90 {
+ return "", nil, ErrInvalidLength(len(bech))
+ }
+
+ hrp, data, _, err := DecodeNoLimitWithVersion(bech)
+ return hrp, data, err
+}
+
+// DecodeGeneric is identical to the existing Decode method, but will also
+// return bech32 version that matches the decoded checksum. This method should
+// be used when decoding segwit addresses, as it enables additional
+// verification to ensure the proper checksum is used.
+func DecodeGeneric(bech string) (string, []byte, Version, error) {
+ // The maximum allowed length for a bech32 string is 90.
+ if len(bech) > 90 {
+ return "", nil, VersionUnknown, ErrInvalidLength(len(bech))
+ }
+
+ return DecodeNoLimitWithVersion(bech)
+}
+
+// encodeGeneric is the base bech32 encoding function that is aware of the
+// existence of the checksum versions. This method is private, as the Encode
+// and EncodeM methods are intended to be used instead.
+func encodeGeneric(hrp string, data []byte,
+ version Version) (string, error) {
+
+ // The resulting bech32 string is the concatenation of the lowercase
+ // hrp, the separator 1, data and the 6-byte checksum.
+ hrp = strings.ToLower(hrp)
+ var bldr strings.Builder
+ bldr.Grow(len(hrp) + 1 + len(data) + 6)
+ bldr.WriteString(hrp)
+ bldr.WriteString("1")
+
+ // Write the data part, using the bech32 charset.
+ for _, b := range data {
+ if int(b) >= len(charset) {
+ return "", ErrInvalidDataByte(b)
+ }
+ bldr.WriteByte(charset[b])
+ }
+
+ // Calculate and write the checksum of the data.
+ writeBech32Checksum(hrp, data, &bldr, version)
+
+ return bldr.String(), nil
+}
+
+// Encode encodes a byte slice into a bech32 string with the given
+// human-readable part (HRP). The HRP will be converted to lowercase if needed
+// since mixed cased encodings are not permitted and lowercase is used for
+// checksum purposes. Note that the bytes must each encode 5 bits (base32).
+func Encode(hrp string, data []byte) (string, error) {
+ return encodeGeneric(hrp, data, Version0)
+}
+
+// EncodeM is the exactly same as the Encode method, but it uses the new
+// bech32m constant instead of the original one. It should be used whenever one
+// attempts to encode a segwit address of v1 and beyond.
+func EncodeM(hrp string, data []byte) (string, error) {
+ return encodeGeneric(hrp, data, VersionM)
+}
+
+// ConvertBits converts a byte slice where each byte is encoding fromBits bits,
+// to a byte slice where each byte is encoding toBits bits.
+func ConvertBits(data []byte, fromBits, toBits uint8, pad bool) ([]byte, error) {
+ if fromBits < 1 || fromBits > 8 || toBits < 1 || toBits > 8 {
+ return nil, ErrInvalidBitGroups{}
+ }
+
+ // Determine the maximum size the resulting array can have after base
+ // conversion, so that we can size it a single time. This might be off
+ // by a byte depending on whether padding is used or not and if the input
+ // data is a multiple of both fromBits and toBits, but we ignore that and
+ // just size it to the maximum possible.
+ maxSize := len(data)*int(fromBits)/int(toBits) + 1
+
+ // The final bytes, each byte encoding toBits bits.
+ regrouped := make([]byte, 0, maxSize)
+
+ // Keep track of the next byte we create and how many bits we have
+ // added to it out of the toBits goal.
+ nextByte := byte(0)
+ filledBits := uint8(0)
+
+ for _, b := range data {
+
+ // Discard unused bits.
+ b <<= 8 - fromBits
+
+ // How many bits remaining to extract from the input data.
+ remFromBits := fromBits
+ for remFromBits > 0 {
+ // How many bits remaining to be added to the next byte.
+ remToBits := toBits - filledBits
+
+ // The number of bytes to next extract is the minimum of
+ // remFromBits and remToBits.
+ toExtract := remFromBits
+ if remToBits < toExtract {
+ toExtract = remToBits
+ }
+
+ // Add the next bits to nextByte, shifting the already
+ // added bits to the left.
+ nextByte = (nextByte << toExtract) | (b >> (8 - toExtract))
+
+ // Discard the bits we just extracted and get ready for
+ // next iteration.
+ b <<= toExtract
+ remFromBits -= toExtract
+ filledBits += toExtract
+
+ // If the nextByte is completely filled, we add it to
+ // our regrouped bytes and start on the next byte.
+ if filledBits == toBits {
+ regrouped = append(regrouped, nextByte)
+ filledBits = 0
+ nextByte = 0
+ }
+ }
+ }
+
+ // We pad any unfinished group if specified.
+ if pad && filledBits > 0 {
+ nextByte <<= toBits - filledBits
+ regrouped = append(regrouped, nextByte)
+ filledBits = 0
+ nextByte = 0
+ }
+
+ // Any incomplete group must be <= 4 bits, and all zeroes.
+ if filledBits > 0 && (filledBits > 4 || nextByte != 0) {
+ return nil, ErrInvalidIncompleteGroup{}
+ }
+
+ return regrouped, nil
+}
+
+// EncodeFromBase256 converts a base256-encoded byte slice into a base32-encoded
+// byte slice and then encodes it into a bech32 string with the given
+// human-readable part (HRP). The HRP will be converted to lowercase if needed
+// since mixed cased encodings are not permitted and lowercase is used for
+// checksum purposes.
+func EncodeFromBase256(hrp string, data []byte) (string, error) {
+ converted, err := ConvertBits(data, 8, 5, true)
+ if err != nil {
+ return "", err
+ }
+ return Encode(hrp, converted)
+}
+
+// DecodeToBase256 decodes a bech32-encoded string into its associated
+// human-readable part (HRP) and base32-encoded data, converts that data to a
+// base256-encoded byte slice and returns it along with the lowercase HRP.
+func DecodeToBase256(bech string) (string, []byte, error) {
+ hrp, data, err := Decode(bech)
+ if err != nil {
+ return "", nil, err
+ }
+ converted, err := ConvertBits(data, 5, 8, false)
+ if err != nil {
+ return "", nil, err
+ }
+ return hrp, converted, nil
+}
diff --git a/address/bech32/bech32_test.go b/address/bech32/bech32_test.go
new file mode 100644
index 0000000..3f637c4
--- /dev/null
+++ b/address/bech32/bech32_test.go
@@ -0,0 +1,691 @@
+// Copyright (c) 2017-2020 The btcsuite developers
+// Copyright (c) 2019 The Decred developers
+// Use of this source code is governed by an ISC
+// license that can be found in the LICENSE file.
+
+package bech32
+
+import (
+ "bytes"
+ "encoding/hex"
+ "fmt"
+ "strings"
+ "testing"
+)
+
+// TestBech32 tests whether decoding and re-encoding the valid BIP-173 test
+// vectors works and if decoding invalid test vectors fails for the correct
+// reason.
+func TestBech32(t *testing.T) {
+ tests := []struct {
+ str string
+ expectedError error
+ }{
+ {"A12UEL5L", nil},
+ {"a12uel5l", nil},
+ {"an83characterlonghumanreadablepartthatcontainsthenumber1andtheexcludedcharactersbio1tt5tgs", nil},
+ {"abcdef1qpzry9x8gf2tvdw0s3jn54khce6mua7lmqqqxw", nil},
+ {"11qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqc8247j", nil},
+ {"split1checkupstagehandshakeupstreamerranterredcaperred2y9e3w", nil},
+ {"split1checkupstagehandshakeupstreamerranterredcaperred2y9e2w", ErrInvalidChecksum{"2y9e3w", "2y9e3wlc445v", "2y9e2w"}}, // invalid checksum
+ {"s lit1checkupstagehandshakeupstreamerranterredcaperredp8hs2p", ErrInvalidCharacter(' ')}, // invalid character (space) in hrp
+ {"spl\x7Ft1checkupstagehandshakeupstreamerranterredcaperred2y9e3w", ErrInvalidCharacter(127)}, // invalid character (DEL) in hrp
+ {"split1cheo2y9e2w", ErrNonCharsetChar('o')}, // invalid character (o) in data part
+ {"split1a2y9w", ErrInvalidSeparatorIndex(5)}, // too short data part
+ {"1checkupstagehandshakeupstreamerranterredcaperred2y9e3w", ErrInvalidSeparatorIndex(0)}, // empty hrp
+ {"11qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqsqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqc8247j", ErrInvalidLength(91)}, // too long
+
+ // Additional test vectors used in bitcoin core
+ {" 1nwldj5", ErrInvalidCharacter(' ')},
+ {"\x7f" + "1axkwrx", ErrInvalidCharacter(0x7f)},
+ {"\x801eym55h", ErrInvalidCharacter(0x80)},
+ {"an84characterslonghumanreadablepartthatcontainsthenumber1andtheexcludedcharactersbio1569pvx", ErrInvalidLength(91)},
+ {"pzry9x0s0muk", ErrInvalidSeparatorIndex(-1)},
+ {"1pzry9x0s0muk", ErrInvalidSeparatorIndex(0)},
+ {"x1b4n0q5v", ErrNonCharsetChar(98)},
+ {"li1dgmt3", ErrInvalidSeparatorIndex(2)},
+ {"de1lg7wt\xff", ErrInvalidCharacter(0xff)},
+ {"A1G7SGD8", ErrInvalidChecksum{"2uel5l", "2uel5llqfn3a", "g7sgd8"}},
+ {"10a06t8", ErrInvalidLength(7)},
+ {"1qzzfhee", ErrInvalidSeparatorIndex(0)},
+ {"a12UEL5L", ErrMixedCase{}},
+ {"A12uEL5L", ErrMixedCase{}},
+ }
+
+ for i, test := range tests {
+ str := test.str
+ hrp, decoded, err := Decode(str)
+ if test.expectedError != err {
+ t.Errorf("%d: expected decoding error %v "+
+ "instead got %v", i, test.expectedError, err)
+ continue
+ }
+
+ if err != nil {
+ // End test case here if a decoding error was expected.
+ continue
+ }
+
+ // Check that it encodes to the same string
+ encoded, err := Encode(hrp, decoded)
+ if err != nil {
+ t.Errorf("encoding failed: %v", err)
+ }
+
+ if encoded != strings.ToLower(str) {
+ t.Errorf("expected data to encode to %v, but got %v",
+ str, encoded)
+ }
+
+ // Flip a bit in the string an make sure it is caught.
+ pos := strings.LastIndexAny(str, "1")
+ flipped := str[:pos+1] + string((str[pos+1] ^ 1)) + str[pos+2:]
+ _, _, err = Decode(flipped)
+ if err == nil {
+ t.Error("expected decoding to fail")
+ }
+ }
+}
+
+// TestBech32M tests that the following set of strings, based on the test
+// vectors in BIP-350 are either valid or invalid using the new bech32m
+// checksum algo. Some of these strings are similar to the set of above test
+// vectors, but end up with different checksums.
+func TestBech32M(t *testing.T) {
+ tests := []struct {
+ str string
+ expectedError error
+ }{
+ {"A1LQFN3A", nil},
+ {"a1lqfn3a", nil},
+ {"an83characterlonghumanreadablepartthatcontainsthetheexcludedcharactersbioandnumber11sg7hg6", nil},
+ {"abcdef1l7aum6echk45nj3s0wdvt2fg8x9yrzpqzd3ryx", nil},
+ {"11llllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllludsr8", nil},
+ {"split1checkupstagehandshakeupstreamerranterredcaperredlc445v", nil},
+ {"?1v759aa", nil},
+
+ // Additional test vectors used in bitcoin core
+ {"\x201xj0phk", ErrInvalidCharacter('\x20')},
+ {"\x7f1g6xzxy", ErrInvalidCharacter('\x7f')},
+ {"\x801vctc34", ErrInvalidCharacter('\x80')},
+ {"an84characterslonghumanreadablepartthatcontainsthetheexcludedcharactersbioandnumber11d6pts4", ErrInvalidLength(91)},
+ {"qyrz8wqd2c9m", ErrInvalidSeparatorIndex(-1)},
+ {"1qyrz8wqd2c9m", ErrInvalidSeparatorIndex(0)},
+ {"y1b0jsk6g", ErrNonCharsetChar(98)},
+ {"lt1igcx5c0", ErrNonCharsetChar(105)},
+ {"in1muywd", ErrInvalidSeparatorIndex(2)},
+ {"mm1crxm3i", ErrNonCharsetChar(105)},
+ {"au1s5cgom", ErrNonCharsetChar(111)},
+ {"M1VUXWEZ", ErrInvalidChecksum{"mzl49c", "mzl49cw70eq6", "vuxwez"}},
+ {"16plkw9", ErrInvalidLength(7)},
+ {"1p2gdwpf", ErrInvalidSeparatorIndex(0)},
+
+ {" 1nwldj5", ErrInvalidCharacter(' ')},
+ {"\x7f" + "1axkwrx", ErrInvalidCharacter(0x7f)},
+ {"\x801eym55h", ErrInvalidCharacter(0x80)},
+ }
+
+ for i, test := range tests {
+ str := test.str
+ hrp, decoded, err := Decode(str)
+ if test.expectedError != err {
+ t.Errorf("%d: (%v) expected decoding error %v "+
+ "instead got %v", i, str, test.expectedError,
+ err)
+ continue
+ }
+
+ if err != nil {
+ // End test case here if a decoding error was expected.
+ continue
+ }
+
+ // Check that it encodes to the same string, using bech32 m.
+ encoded, err := EncodeM(hrp, decoded)
+ if err != nil {
+ t.Errorf("encoding failed: %v", err)
+ }
+
+ if encoded != strings.ToLower(str) {
+ t.Errorf("expected data to encode to %v, but got %v",
+ str, encoded)
+ }
+
+ // Flip a bit in the string an make sure it is caught.
+ pos := strings.LastIndexAny(str, "1")
+ flipped := str[:pos+1] + string((str[pos+1] ^ 1)) + str[pos+2:]
+ _, _, err = Decode(flipped)
+ if err == nil {
+ t.Error("expected decoding to fail")
+ }
+ }
+}
+
+// TestBech32DecodeGeneric tests that given a bech32 string, or a bech32m
+// string, the proper checksum version is returned so that callers can perform
+// segwit addr validation.
+func TestBech32DecodeGeneric(t *testing.T) {
+ tests := []struct {
+ str string
+ version Version
+ }{
+ {"A1LQFN3A", VersionM},
+ {"a1lqfn3a", VersionM},
+ {"an83characterlonghumanreadablepartthatcontainsthetheexcludedcharactersbioandnumber11sg7hg6", VersionM},
+ {"abcdef1l7aum6echk45nj3s0wdvt2fg8x9yrzpqzd3ryx", VersionM},
+ {"11llllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllludsr8", VersionM},
+ {"split1checkupstagehandshakeupstreamerranterredcaperredlc445v", VersionM},
+ {"?1v759aa", VersionM},
+
+ {"A12UEL5L", Version0},
+ {"a12uel5l", Version0},
+ {"an83characterlonghumanreadablepartthatcontainsthenumber1andtheexcludedcharactersbio1tt5tgs", Version0},
+ {"abcdef1qpzry9x8gf2tvdw0s3jn54khce6mua7lmqqqxw", Version0},
+ {"11qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqc8247j", Version0},
+ {"split1checkupstagehandshakeupstreamerranterredcaperred2y9e3w", Version0},
+
+ {"BC1QW508D6QEJXTDG4Y5R3ZARVARY0C5XW7KV8F3T4", Version0},
+ {"tb1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3q0sl5k7", Version0},
+ {"bc1pw508d6qejxtdg4y5r3zarvary0c5xw7kw508d6qejxtdg4y5r3zarvary0c5xw7kt5nd6y", VersionM},
+ {"BC1SW50QGDZ25J", VersionM},
+ {"bc1zw508d6qejxtdg4y5r3zarvaryvaxxpcs", VersionM},
+ {"tb1qqqqqp399et2xygdj5xreqhjjvcmzhxw4aywxecjdzew6hylgvsesrxh6hy", Version0},
+ {"tb1pqqqqp399et2xygdj5xreqhjjvcmzhxw4aywxecjdzew6hylgvsesf3hn0c", VersionM},
+ {"bc1p0xlxvlhemja6c4dqv22uapctqupfhlxm9h8z3k2e72q4k9hcz7vqzk5jj0", VersionM},
+ }
+ for i, test := range tests {
+ _, _, version, err := DecodeGeneric(test.str)
+ if err != nil {
+ t.Errorf("%d: (%v) unexpected error during "+
+ "decoding: %v", i, test.str, err)
+ continue
+ }
+
+ if version != test.version {
+ t.Errorf("(%v): invalid version: expected %v, got %v",
+ test.str, test.version, version)
+ }
+ }
+}
+
+// TestMixedCaseEncode ensures mixed case HRPs are converted to lowercase as
+// expected when encoding and that decoding the produced encoding when converted
+// to all uppercase produces the lowercase HRP and original data.
+func TestMixedCaseEncode(t *testing.T) {
+ tests := []struct {
+ name string
+ hrp string
+ data string
+ encoded string
+ }{{
+ name: "all uppercase HRP with no data",
+ hrp: "A",
+ data: "",
+ encoded: "a12uel5l",
+ }, {
+ name: "all uppercase HRP with data",
+ hrp: "UPPERCASE",
+ data: "787878",
+ encoded: "uppercase10pu8sss7kmp",
+ }, {
+ name: "mixed case HRP even offsets uppercase",
+ hrp: "AbCdEf",
+ data: "00443214c74254b635cf84653a56d7c675be77df",
+ encoded: "abcdef1qpzry9x8gf2tvdw0s3jn54khce6mua7lmqqqxw",
+ }, {
+ name: "mixed case HRP odd offsets uppercase ",
+ hrp: "aBcDeF",
+ data: "00443214c74254b635cf84653a56d7c675be77df",
+ encoded: "abcdef1qpzry9x8gf2tvdw0s3jn54khce6mua7lmqqqxw",
+ }, {
+ name: "all lowercase HRP",
+ hrp: "abcdef",
+ data: "00443214c74254b635cf84653a56d7c675be77df",
+ encoded: "abcdef1qpzry9x8gf2tvdw0s3jn54khce6mua7lmqqqxw",
+ }}
+
+ for _, test := range tests {
+ // Convert the text hex to bytes, convert those bytes from base256 to
+ // base32, then ensure the encoded result with the HRP provided in the
+ // test data is as expected.
+ data, err := hex.DecodeString(test.data)
+ if err != nil {
+ t.Errorf("%q: invalid hex %q: %v", test.name, test.data, err)
+ continue
+ }
+ convertedData, err := ConvertBits(data, 8, 5, true)
+ if err != nil {
+ t.Errorf("%q: unexpected convert bits error: %v", test.name,
+ err)
+ continue
+ }
+ gotEncoded, err := Encode(test.hrp, convertedData)
+ if err != nil {
+ t.Errorf("%q: unexpected encode error: %v", test.name, err)
+ continue
+ }
+ if gotEncoded != test.encoded {
+ t.Errorf("%q: mismatched encoding -- got %q, want %q", test.name,
+ gotEncoded, test.encoded)
+ continue
+ }
+
+ // Ensure the decoding the expected lowercase encoding converted to all
+ // uppercase produces the lowercase HRP and original data.
+ gotHRP, gotData, err := Decode(strings.ToUpper(test.encoded))
+ if err != nil {
+ t.Errorf("%q: unexpected decode error: %v", test.name, err)
+ continue
+ }
+ wantHRP := strings.ToLower(test.hrp)
+ if gotHRP != wantHRP {
+ t.Errorf("%q: mismatched decoded HRP -- got %q, want %q", test.name,
+ gotHRP, wantHRP)
+ continue
+ }
+ convertedGotData, err := ConvertBits(gotData, 5, 8, false)
+ if err != nil {
+ t.Errorf("%q: unexpected convert bits error: %v", test.name,
+ err)
+ continue
+ }
+ if !bytes.Equal(convertedGotData, data) {
+ t.Errorf("%q: mismatched data -- got %x, want %x", test.name,
+ convertedGotData, data)
+ continue
+ }
+ }
+}
+
+// TestCanDecodeUnlimitedBech32 tests whether decoding a large bech32 string works
+// when using the DecodeNoLimit version
+func TestCanDecodeUnlimitedBech32(t *testing.T) {
+ input := "11qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqsqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq5kx0yd"
+
+ // Sanity check that an input of this length errors on regular Decode()
+ _, _, err := Decode(input)
+ if err == nil {
+ t.Fatalf("Test vector not appropriate")
+ }
+
+ // Try and decode it.
+ hrp, data, err := DecodeNoLimit(input)
+ if err != nil {
+ t.Fatalf("Expected decoding of large string to work. Got error: %v", err)
+ }
+
+ // Verify data for correctness.
+ if hrp != "1" {
+ t.Fatalf("Unexpected hrp: %v", hrp)
+ }
+ decodedHex := fmt.Sprintf("%x", data)
+ expected := "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000"
+ if decodedHex != expected {
+ t.Fatalf("Unexpected decoded data: %s", decodedHex)
+ }
+}
+
+// TestBech32Base256 ensures decoding and encoding various bech32, HRPs, and
+// data produces the expected results when using EncodeFromBase256 and
+// DecodeToBase256. It includes tests for proper handling of case
+// manipulations.
+func TestBech32Base256(t *testing.T) {
+ tests := []struct {
+ name string // test name
+ encoded string // bech32 string to decode
+ hrp string // expected human-readable part
+ data string // expected hex-encoded data
+ err error // expected error
+ }{{
+ name: "all uppercase, no data",
+ encoded: "A12UEL5L",
+ hrp: "a",
+ data: "",
+ }, {
+ name: "long hrp with separator and excluded chars, no data",
+ encoded: "an83characterlonghumanreadablepartthatcontainsthenumber1andtheexcludedcharactersbio1tt5tgs",
+ hrp: "an83characterlonghumanreadablepartthatcontainsthenumber1andtheexcludedcharactersbio",
+ data: "",
+ }, {
+ name: "6 char hrp with data with leading zero",
+ encoded: "abcdef1qpzry9x8gf2tvdw0s3jn54khce6mua7lmqqqxw",
+ hrp: "abcdef",
+ data: "00443214c74254b635cf84653a56d7c675be77df",
+ }, {
+ name: "hrp same as separator and max length encoded string",
+ encoded: "11qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqc8247j",
+ hrp: "1",
+ data: "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
+ }, {
+ name: "5 char hrp with data chosen to produce human-readable data part",
+ encoded: "split1checkupstagehandshakeupstreamerranterredcaperred2y9e3w",
+ hrp: "split",
+ data: "c5f38b70305f519bf66d85fb6cf03058f3dde463ecd7918f2dc743918f2d",
+ }, {
+ name: "same as previous but with checksum invalidated",
+ encoded: "split1checkupstagehandshakeupstreamerranterredcaperred2y9e2w",
+ err: ErrInvalidChecksum{"2y9e3w", "2y9e3wlc445v", "2y9e2w"},
+ }, {
+ name: "hrp with invalid character (space)",
+ encoded: "s lit1checkupstagehandshakeupstreamerranterredcaperredp8hs2p",
+ err: ErrInvalidCharacter(' '),
+ }, {
+ name: "hrp with invalid character (DEL)",
+ encoded: "spl\x7ft1checkupstagehandshakeupstreamerranterredcaperred2y9e3w",
+ err: ErrInvalidCharacter(127),
+ }, {
+ name: "data part with invalid character (o)",
+ encoded: "split1cheo2y9e2w",
+ err: ErrNonCharsetChar('o'),
+ }, {
+ name: "data part too short",
+ encoded: "split1a2y9w",
+ err: ErrInvalidSeparatorIndex(5),
+ }, {
+ name: "empty hrp",
+ encoded: "1checkupstagehandshakeupstreamerranterredcaperred2y9e3w",
+ err: ErrInvalidSeparatorIndex(0),
+ }, {
+ name: "no separator",
+ encoded: "pzry9x0s0muk",
+ err: ErrInvalidSeparatorIndex(-1),
+ }, {
+ name: "too long by one char",
+ encoded: "11qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqsqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqc8247j",
+ err: ErrInvalidLength(91),
+ }, {
+ name: "invalid due to mixed case in hrp",
+ encoded: "aBcdef1qpzry9x8gf2tvdw0s3jn54khce6mua7lmqqqxw",
+ err: ErrMixedCase{},
+ }, {
+ name: "invalid due to mixed case in data part",
+ encoded: "abcdef1Qpzry9x8gf2tvdw0s3jn54khce6mua7lmqqqxw",
+ err: ErrMixedCase{},
+ }}
+
+ for _, test := range tests {
+ // Ensure the decode either produces an error or not as expected.
+ str := test.encoded
+ gotHRP, gotData, err := DecodeToBase256(str)
+ if test.err != err {
+ t.Errorf("%q: unexpected decode error -- got %v, want %v",
+ test.name, err, test.err)
+ continue
+ }
+ if err != nil {
+ // End test case here if a decoding error was expected.
+ continue
+ }
+
+ // Ensure the expected HRP and original data are as expected.
+ if gotHRP != test.hrp {
+ t.Errorf("%q: mismatched decoded HRP -- got %q, want %q", test.name,
+ gotHRP, test.hrp)
+ continue
+ }
+ data, err := hex.DecodeString(test.data)
+ if err != nil {
+ t.Errorf("%q: invalid hex %q: %v", test.name, test.data, err)
+ continue
+ }
+ if !bytes.Equal(gotData, data) {
+ t.Errorf("%q: mismatched data -- got %x, want %x", test.name,
+ gotData, data)
+ continue
+ }
+
+ // Encode the same data with the HRP converted to all uppercase and
+ // ensure the result is the lowercase version of the original encoded
+ // bech32 string.
+ gotEncoded, err := EncodeFromBase256(strings.ToUpper(test.hrp), data)
+ if err != nil {
+ t.Errorf("%q: unexpected uppercase HRP encode error: %v", test.name,
+ err)
+ }
+ wantEncoded := strings.ToLower(str)
+ if gotEncoded != wantEncoded {
+ t.Errorf("%q: mismatched encoding -- got %q, want %q", test.name,
+ gotEncoded, wantEncoded)
+ }
+
+ // Encode the same data with the HRP converted to all lowercase and
+ // ensure the result is the lowercase version of the original encoded
+ // bech32 string.
+ gotEncoded, err = EncodeFromBase256(strings.ToLower(test.hrp), data)
+ if err != nil {
+ t.Errorf("%q: unexpected lowercase HRP encode error: %v", test.name,
+ err)
+ }
+ if gotEncoded != wantEncoded {
+ t.Errorf("%q: mismatched encoding -- got %q, want %q", test.name,
+ gotEncoded, wantEncoded)
+ }
+
+ // Encode the same data with the HRP converted to mixed upper and
+ // lowercase and ensure the result is the lowercase version of the
+ // original encoded bech32 string.
+ var mixedHRPBuilder strings.Builder
+ for i, r := range test.hrp {
+ if i%2 == 0 {
+ mixedHRPBuilder.WriteString(strings.ToUpper(string(r)))
+ continue
+ }
+ mixedHRPBuilder.WriteRune(r)
+ }
+ gotEncoded, err = EncodeFromBase256(mixedHRPBuilder.String(), data)
+ if err != nil {
+ t.Errorf("%q: unexpected lowercase HRP encode error: %v", test.name,
+ err)
+ }
+ if gotEncoded != wantEncoded {
+ t.Errorf("%q: mismatched encoding -- got %q, want %q", test.name,
+ gotEncoded, wantEncoded)
+ }
+
+ // Ensure a bit flip in the string is caught.
+ pos := strings.LastIndexAny(test.encoded, "1")
+ flipped := str[:pos+1] + string((str[pos+1] ^ 1)) + str[pos+2:]
+ _, _, err = DecodeToBase256(flipped)
+ if err == nil {
+ t.Error("expected decoding to fail")
+ }
+ }
+}
+
+// BenchmarkEncodeDecodeCycle performs a benchmark for a full encode/decode
+// cycle of a bech32 string. It also reports the allocation count, which we
+// expect to be 2 for a fully optimized cycle.
+func BenchmarkEncodeDecodeCycle(b *testing.B) {
+ // Use a fixed, 49-byte raw data for testing.
+ inputData, err := hex.DecodeString("cbe6365ddbcda9a9915422c3f091c13f8c7b2f263b8d34067bd12c274408473fa764871c9dd51b1bb34873b3473b633ed1")
+ if err != nil {
+ b.Fatalf("failed to initialize input data: %v", err)
+ }
+
+ // Convert this into a 79-byte, base 32 byte slice.
+ base32Input, err := ConvertBits(inputData, 8, 5, true)
+ if err != nil {
+ b.Fatalf("failed to convert input to 32 bits-per-element: %v", err)
+ }
+
+ // Use a fixed hrp for the tests. This should generate an encoded bech32
+ // string of size 90 (the maximum allowed by BIP-173).
+ hrp := "bc"
+
+ // Begin the benchmark. Given that we test one roundtrip per iteration
+ // (that is, one Encode() and one Decode() operation), we expect at most
+ // 2 allocations per reported test op.
+ b.ReportAllocs()
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ str, err := Encode(hrp, base32Input)
+ if err != nil {
+ b.Fatalf("failed to encode input: %v", err)
+ }
+
+ _, _, err = Decode(str)
+ if err != nil {
+ b.Fatalf("failed to decode string: %v", err)
+ }
+ }
+}
+
+// TestConvertBits tests whether base conversion works using TestConvertBits().
+func TestConvertBits(t *testing.T) {
+ tests := []struct {
+ input string
+ output string
+ fromBits uint8
+ toBits uint8
+ pad bool
+ }{
+ // Trivial empty conversions.
+ {"", "", 8, 5, false},
+ {"", "", 8, 5, true},
+ {"", "", 5, 8, false},
+ {"", "", 5, 8, true},
+
+ // Conversions of 0 value with/without padding.
+ {"00", "00", 8, 5, false},
+ {"00", "0000", 8, 5, true},
+ {"0000", "00", 5, 8, false},
+ {"0000", "0000", 5, 8, true},
+
+ // Testing when conversion ends exactly at the byte edge. This makes
+ // both padded and unpadded versions the same.
+ {"0000000000", "0000000000000000", 8, 5, false},
+ {"0000000000", "0000000000000000", 8, 5, true},
+ {"0000000000000000", "0000000000", 5, 8, false},
+ {"0000000000000000", "0000000000", 5, 8, true},
+
+ // Conversions of full byte sequences.
+ {"ffffff", "1f1f1f1f1e", 8, 5, true},
+ {"1f1f1f1f1e", "ffffff", 5, 8, false},
+ {"1f1f1f1f1e", "ffffff00", 5, 8, true},
+
+ // Sample random conversions.
+ {"c9ca", "190705", 8, 5, false},
+ {"c9ca", "19070500", 8, 5, true},
+ {"19070500", "c9ca", 5, 8, false},
+ {"19070500", "c9ca00", 5, 8, true},
+
+ // Test cases tested on TestConvertBitsFailures with their corresponding
+ // fixes.
+ {"ff", "1f1c", 8, 5, true},
+ {"1f1c10", "ff20", 5, 8, true},
+
+ // Large conversions.
+ {
+ "cbe6365ddbcda9a9915422c3f091c13f8c7b2f263b8d34067bd12c274408473fa764871c9dd51b1bb34873b3473b633ed1",
+ "190f13030c170e1b1916141a13040a14040b011f01040e01071e0607160b1906070e06130801131b1a0416020e110008081c1f1a0e19040703120e1d0a06181b160d0407070c1a07070d11131d1408",
+ 8, 5, true,
+ },
+ {
+ "190f13030c170e1b1916141a13040a14040b011f01040e01071e0607160b1906070e06130801131b1a0416020e110008081c1f1a0e19040703120e1d0a06181b160d0407070c1a07070d11131d1408",
+ "cbe6365ddbcda9a9915422c3f091c13f8c7b2f263b8d34067bd12c274408473fa764871c9dd51b1bb34873b3473b633ed100",
+ 5, 8, true,
+ },
+ }
+
+ for i, tc := range tests {
+ input, err := hex.DecodeString(tc.input)
+ if err != nil {
+ t.Fatalf("invalid test input data: %v", err)
+ }
+
+ expected, err := hex.DecodeString(tc.output)
+ if err != nil {
+ t.Fatalf("invalid test output data: %v", err)
+ }
+
+ actual, err := ConvertBits(input, tc.fromBits, tc.toBits, tc.pad)
+ if err != nil {
+ t.Fatalf("test case %d failed: %v", i, err)
+ }
+
+ if !bytes.Equal(actual, expected) {
+ t.Fatalf("test case %d has wrong output; expected=%x actual=%x",
+ i, expected, actual)
+ }
+ }
+}
+
+// TestConvertBitsFailures tests for the expected conversion failures of
+// ConvertBits().
+func TestConvertBitsFailures(t *testing.T) {
+ tests := []struct {
+ input string
+ fromBits uint8
+ toBits uint8
+ pad bool
+ err error
+ }{
+ // Not enough output bytes when not using padding.
+ {"ff", 8, 5, false, ErrInvalidIncompleteGroup{}},
+ {"1f1c10", 5, 8, false, ErrInvalidIncompleteGroup{}},
+
+ // Unsupported bit conversions.
+ {"", 0, 5, false, ErrInvalidBitGroups{}},
+ {"", 10, 5, false, ErrInvalidBitGroups{}},
+ {"", 5, 0, false, ErrInvalidBitGroups{}},
+ {"", 5, 10, false, ErrInvalidBitGroups{}},
+ }
+
+ for i, tc := range tests {
+ input, err := hex.DecodeString(tc.input)
+ if err != nil {
+ t.Fatalf("invalid test input data: %v", err)
+ }
+
+ _, err = ConvertBits(input, tc.fromBits, tc.toBits, tc.pad)
+ if err != tc.err {
+ t.Fatalf("test case %d failure: expected '%v' got '%v'", i,
+ tc.err, err)
+ }
+ }
+
+}
+
+// BenchmarkConvertBitsDown benchmarks the speed and memory allocation behavior
+// of ConvertBits when converting from a higher base into a lower base (e.g. 8
+// => 5).
+//
+// Only a single allocation is expected, which is used for the output array.
+func BenchmarkConvertBitsDown(b *testing.B) {
+ // Use a fixed, 49-byte raw data for testing.
+ inputData, err := hex.DecodeString("cbe6365ddbcda9a9915422c3f091c13f8c7b2f263b8d34067bd12c274408473fa764871c9dd51b1bb34873b3473b633ed1")
+ if err != nil {
+ b.Fatalf("failed to initialize input data: %v", err)
+ }
+
+ b.ReportAllocs()
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ _, err := ConvertBits(inputData, 8, 5, true)
+ if err != nil {
+ b.Fatalf("error converting bits: %v", err)
+ }
+ }
+}
+
+// BenchmarkConvertBitsUp benchmarks the speed and memory allocation behavior
+// of ConvertBits when converting from a lower base into a higher base (e.g. 5
+// => 8).
+//
+// Only a single allocation is expected, which is used for the output array.
+func BenchmarkConvertBitsUp(b *testing.B) {
+ // Use a fixed, 79-byte raw data for testing.
+ inputData, err := hex.DecodeString("190f13030c170e1b1916141a13040a14040b011f01040e01071e0607160b1906070e06130801131b1a0416020e110008081c1f1a0e19040703120e1d0a06181b160d0407070c1a07070d11131d1408")
+ if err != nil {
+ b.Fatalf("failed to initialize input data: %v", err)
+ }
+
+ b.ReportAllocs()
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ _, err := ConvertBits(inputData, 8, 5, true)
+ if err != nil {
+ b.Fatalf("error converting bits: %v", err)
+ }
+ }
+}
diff --git a/address/bech32/doc.go b/address/bech32/doc.go
new file mode 100644
index 0000000..2d64fbe
--- /dev/null
+++ b/address/bech32/doc.go
@@ -0,0 +1,15 @@
+// Copyright (c) 2017 The btcsuite developers
+// Use of this source code is governed by an ISC
+// license that can be found in the LICENSE file.
+
+/*
+Package bech32 provides a Go implementation of the bech32 format specified in
+BIP 173.
+
+Bech32 strings consist of a human-readable part (hrp), followed by the
+separator 1, then a checksummed data part encoded using the 32 characters
+"qpzry9x8gf2tvdw0s3jn54khce6mua7l".
+
+More info: https://github.com/bitcoin/bips/blob/master/bip-0173.mediawiki
+*/
+package bech32
diff --git a/address/bech32/error.go b/address/bech32/error.go
new file mode 100644
index 0000000..e8b1fe8
--- /dev/null
+++ b/address/bech32/error.go
@@ -0,0 +1,87 @@
+// Copyright (c) 2019 The Decred developers
+// Use of this source code is governed by an ISC
+// license that can be found in the LICENSE file.
+
+package bech32
+
+import (
+ "fmt"
+)
+
+// ErrMixedCase is returned when the bech32 string has both lower and uppercase
+// characters.
+type ErrMixedCase struct{}
+
+func (e ErrMixedCase) Error() string {
+ return "string not all lowercase or all uppercase"
+}
+
+// ErrInvalidBitGroups is returned when conversion is attempted between byte
+// slices using bit-per-element of unsupported value.
+type ErrInvalidBitGroups struct{}
+
+func (e ErrInvalidBitGroups) Error() string {
+ return "only bit groups between 1 and 8 allowed"
+}
+
+// ErrInvalidIncompleteGroup is returned when then byte slice used as input has
+// data of wrong length.
+type ErrInvalidIncompleteGroup struct{}
+
+func (e ErrInvalidIncompleteGroup) Error() string {
+ return "invalid incomplete group"
+}
+
+// ErrInvalidLength is returned when the bech32 string has an invalid length
+// given the BIP-173 defined restrictions.
+type ErrInvalidLength int
+
+func (e ErrInvalidLength) Error() string {
+ return fmt.Sprintf("invalid bech32 string length %d", int(e))
+}
+
+// ErrInvalidCharacter is returned when the bech32 string has a character
+// outside the range of the supported charset.
+type ErrInvalidCharacter rune
+
+func (e ErrInvalidCharacter) Error() string {
+ return fmt.Sprintf("invalid character in string: '%c'", rune(e))
+}
+
+// ErrInvalidSeparatorIndex is returned when the separator character '1' is
+// in an invalid position in the bech32 string.
+type ErrInvalidSeparatorIndex int
+
+func (e ErrInvalidSeparatorIndex) Error() string {
+ return fmt.Sprintf("invalid separator index %d", int(e))
+}
+
+// ErrNonCharsetChar is returned when a character outside of the specific
+// bech32 charset is used in the string.
+type ErrNonCharsetChar rune
+
+func (e ErrNonCharsetChar) Error() string {
+ return fmt.Sprintf("invalid character not part of charset: %v", int(e))
+}
+
+// ErrInvalidChecksum is returned when the extracted checksum of the string
+// is different than what was expected. Both the original version, as well as
+// the new bech32m checksum may be specified.
+type ErrInvalidChecksum struct {
+ Expected string
+ ExpectedM string
+ Actual string
+}
+
+func (e ErrInvalidChecksum) Error() string {
+ return fmt.Sprintf("invalid checksum (expected (bech32=%v, "+
+ "bech32m=%v), got %v)", e.Expected, e.ExpectedM, e.Actual)
+}
+
+// ErrInvalidDataByte is returned when a byte outside the range required for
+// conversion into a string was found.
+type ErrInvalidDataByte byte
+
+func (e ErrInvalidDataByte) Error() string {
+ return fmt.Sprintf("invalid data byte: %v", byte(e))
+}
diff --git a/address/bech32/example_test.go b/address/bech32/example_test.go
new file mode 100644
index 0000000..74ea4ea
--- /dev/null
+++ b/address/bech32/example_test.go
@@ -0,0 +1,49 @@
+// Copyright (c) 2017 The btcsuite developers
+// Use of this source code is governed by an ISC
+// license that can be found in the LICENSE file.
+
+package bech32_test
+
+import (
+ "encoding/hex"
+ "fmt"
+
+ "github.com/btcsuite/btcd/address/v2/bech32"
+)
+
+// This example demonstrates how to decode a bech32 encoded string.
+func ExampleDecode() {
+ encoded := "bc1pw508d6qejxtdg4y5r3zarvary0c5xw7kw508d6qejxtdg4y5r3zarvary0c5xw7k7grplx"
+ hrp, decoded, err := bech32.Decode(encoded)
+ if err != nil {
+ fmt.Println("Error:", err)
+ }
+
+ // Show the decoded data.
+ fmt.Println("Decoded human-readable part:", hrp)
+ fmt.Println("Decoded Data:", hex.EncodeToString(decoded))
+
+ // Output:
+ // Decoded human-readable part: bc
+ // Decoded Data: 010e140f070d1a001912060b0d081504140311021d030c1d03040f1814060e1e160e140f070d1a001912060b0d081504140311021d030c1d03040f1814060e1e16
+}
+
+// This example demonstrates how to encode data into a bech32 string.
+func ExampleEncode() {
+ data := []byte("Test data")
+ // Convert test data to base32:
+ conv, err := bech32.ConvertBits(data, 8, 5, true)
+ if err != nil {
+ fmt.Println("Error:", err)
+ }
+ encoded, err := bech32.Encode("customHrp!11111q", conv)
+ if err != nil {
+ fmt.Println("Error:", err)
+ }
+
+ // Show the encoded data.
+ fmt.Println("Encoded Data:", encoded)
+
+ // Output:
+ // Encoded Data: customhrp!11111q123jhxapqv3shgcgkxpuhe
+}
diff --git a/address/bech32/version.go b/address/bech32/version.go
new file mode 100644
index 0000000..147037d
--- /dev/null
+++ b/address/bech32/version.go
@@ -0,0 +1,43 @@
+package bech32
+
+// ChecksumConst is a type that represents the currently defined bech32
+// checksum constants.
+type ChecksumConst int
+
+const (
+ // Version0Const is the original constant used in the checksum
+ // verification for bech32.
+ Version0Const ChecksumConst = 1
+
+ // VersionMConst is the new constant used for bech32m checksum
+ // verification.
+ VersionMConst ChecksumConst = 0x2bc830a3
+)
+
+// Version defines the current set of bech32 versions.
+type Version uint8
+
+const (
+ // Version0 defines the original bech version.
+ Version0 Version = iota
+
+ // VersionM is the new bech32 version defined in BIP-350, also known as
+ // bech32m.
+ VersionM
+
+ // VersionUnknown denotes an unknown bech version.
+ VersionUnknown
+)
+
+// VersionToConsts maps bech32 versions to the checksum constant to be used
+// when encoding, and asserting a particular version when decoding.
+var VersionToConsts = map[Version]ChecksumConst{
+ Version0: Version0Const,
+ VersionM: VersionMConst,
+}
+
+// ConstsToVersion maps a bech32 constant to the version it's associated with.
+var ConstsToVersion = map[ChecksumConst]Version{
+ Version0Const: Version0,
+ VersionMConst: VersionM,
+}
diff --git a/address/go.mod b/address/go.mod
new file mode 100644
index 0000000..d8ffe14
--- /dev/null
+++ b/address/go.mod
@@ -0,0 +1,28 @@
+module github.com/btcsuite/btcd/address/v2
+
+go 1.23.2
+
+require (
+ github.com/btcsuite/btcd/btcec/v2 v2.3.2
+ github.com/btcsuite/btcd/chaincfg/v2 v2.0.0
+ github.com/btcsuite/btcd/wire/v2 v2.0.0
+ golang.org/x/crypto v0.40.0
+)
+
+require (
+ github.com/btcsuite/btcd/chainhash/v2 v2.0.0 // indirect
+ github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0 // indirect
+ golang.org/x/sys v0.35.0 // indirect
+)
+
+// TODO(guggero): Remove this as soon as we have a tagged version of btcec.
+replace github.com/btcsuite/btcd/btcec/v2 => ../btcec
+
+// TODO(guggero): Remove this as soon as we have a tagged version of chaincfg.
+replace github.com/btcsuite/btcd/chaincfg/v2 => ../chaincfg
+
+// TODO(guggero): Remove this as soon as we have a tagged version of chainhash.
+replace github.com/btcsuite/btcd/chainhash/v2 => ../chainhash
+
+// TODO(guggero): Remove this as soon as we have a tagged version of wire.
+replace github.com/btcsuite/btcd/wire/v2 => ../wire
diff --git a/address/go.sum b/address/go.sum
new file mode 100644
index 0000000..f00516a
--- /dev/null
+++ b/address/go.sum
@@ -0,0 +1,14 @@
+github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
+github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0 h1:NMZiJj8QnKe1LgsbDayM4UoHwbvwDRwnI3hwNaAHRnc=
+github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0/go.mod h1:ZXNYxsqcloTdSy/rNShjYzMhyjf0LaoftYK0p+A3h40=
+github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
+github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
+github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
+github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
+golang.org/x/crypto v0.40.0 h1:r4x+VvoG5Fm+eJcxMaY8CQM7Lb0l1lsmjGBQ6s8BfKM=
+golang.org/x/crypto v0.40.0/go.mod h1:Qr1vMER5WyS2dfPHAlsOj01wgLbsyWtFn/aY+5+ZdxY=
+golang.org/x/sys v0.35.0 h1:vz1N37gP5bs89s7He8XuIYXpyY0+QlsKmzipCbUtyxI=
+golang.org/x/sys v0.35.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
+gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
+gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
diff --git a/address/hash160.go b/address/hash160.go
new file mode 100644
index 0000000..0575fa7
--- /dev/null
+++ b/address/hash160.go
@@ -0,0 +1,23 @@
+// Copyright (c) 2013-2017 The btcsuite developers
+// Use of this source code is governed by an ISC
+// license that can be found in the LICENSE file.
+
+package address
+
+import (
+ "crypto/sha256"
+ "hash"
+
+ "golang.org/x/crypto/ripemd160"
+)
+
+// Calculate the hash of hasher over buf.
+func calcHash(buf []byte, hasher hash.Hash) []byte {
+ _, _ = hasher.Write(buf)
+ return hasher.Sum(nil)
+}
+
+// Hash160 calculates the hash ripemd160(sha256(b)).
+func Hash160(buf []byte) []byte {
+ return calcHash(calcHash(buf, sha256.New()), ripemd160.New())
+}
diff --git a/address/internal_test.go b/address/internal_test.go
new file mode 100644
index 0000000..39a9b88
--- /dev/null
+++ b/address/internal_test.go
@@ -0,0 +1,134 @@
+// Copyright (c) 2013-2017 The btcsuite developers
+// Use of this source code is governed by an ISC
+// license that can be found in the LICENSE file.
+
+/*
+This test file is part of the address package rather than the
+address_test package, so it can bridge access to the internals to properly test
+cases which are either not possible or can't reliably be tested via the public
+interface. The functions are only exported while the tests are being run.
+*/
+
+package address
+
+import (
+ "github.com/btcsuite/btcd/address/v2/base58"
+ "github.com/btcsuite/btcd/address/v2/bech32"
+ "github.com/btcsuite/btcd/btcec/v2"
+ "golang.org/x/crypto/ripemd160"
+)
+
+// TstAddressPubKeyHash makes an AddressPubKeyHash, setting the
+// unexported fields with the parameters hash and netID.
+func TstAddressPubKeyHash(hash [ripemd160.Size]byte,
+ netID byte) *AddressPubKeyHash {
+
+ return &AddressPubKeyHash{
+ hash: hash,
+ netID: netID,
+ }
+}
+
+// TstAddressScriptHash makes an AddressScriptHash, setting the
+// unexported fields with the parameters hash and netID.
+func TstAddressScriptHash(hash [ripemd160.Size]byte,
+ netID byte) *AddressScriptHash {
+
+ return &AddressScriptHash{
+ hash: hash,
+ netID: netID,
+ }
+}
+
+// TstAddressWitnessPubKeyHash creates an AddressWitnessPubKeyHash, initiating
+// the fields as given.
+func TstAddressWitnessPubKeyHash(version byte, program [20]byte,
+ hrp string) *AddressWitnessPubKeyHash {
+
+ return &AddressWitnessPubKeyHash{
+ AddressSegWit{
+ hrp: hrp,
+ witnessVersion: version,
+ witnessProgram: program[:],
+ },
+ }
+}
+
+// TstAddressWitnessScriptHash creates an AddressWitnessScriptHash, initiating
+// the fields as given.
+func TstAddressWitnessScriptHash(version byte, program [32]byte,
+ hrp string) *AddressWitnessScriptHash {
+
+ return &AddressWitnessScriptHash{
+ AddressSegWit{
+ hrp: hrp,
+ witnessVersion: version,
+ witnessProgram: program[:],
+ },
+ }
+}
+
+// TstAddressTaproot creates an AddressTaproot, initiating the fields as given.
+func TstAddressTaproot(version byte, program [32]byte,
+ hrp string) *AddressTaproot {
+
+ return &AddressTaproot{
+ AddressSegWit{
+ hrp: hrp,
+ witnessVersion: version,
+ witnessProgram: program[:],
+ },
+ }
+}
+
+// TstAddressPubKey makes an AddressPubKey, setting the unexported fields with
+// the parameters.
+func TstAddressPubKey(serializedPubKey []byte, pubKeyFormat PubKeyFormat,
+ netID byte) *AddressPubKey {
+
+ pubKey, _ := btcec.ParsePubKey(serializedPubKey)
+ return &AddressPubKey{
+ pubKeyFormat: pubKeyFormat,
+ pubKey: pubKey,
+ pubKeyHashID: netID,
+ }
+}
+
+// TstAddressSAddr returns the expected script address bytes for
+// P2PKH and P2SH bitcoin addresses.
+func TstAddressSAddr(addr string) []byte {
+ decoded := base58.Decode(addr)
+ return decoded[1 : 1+ripemd160.Size]
+}
+
+// TstAddressSegwitSAddr returns the expected witness program bytes for
+// bech32 encoded P2WPKH and P2WSH bitcoin addresses.
+func TstAddressSegwitSAddr(addr string) []byte {
+ _, data, err := bech32.Decode(addr)
+ if err != nil {
+ return []byte{}
+ }
+
+ // First byte is version, rest is base 32 encoded data.
+ data, err = bech32.ConvertBits(data[1:], 5, 8, false)
+ if err != nil {
+ return []byte{}
+ }
+ return data
+}
+
+// TstAddressTaprootSAddr returns the expected witness program bytes for a
+// bech32m encoded P2TR bitcoin address.
+func TstAddressTaprootSAddr(addr string) []byte {
+ _, data, err := bech32.Decode(addr)
+ if err != nil {
+ return []byte{}
+ }
+
+ // First byte is version, rest is base 32 encoded data.
+ data, err = bech32.ConvertBits(data[1:], 5, 8, false)
+ if err != nil {
+ return []byte{}
+ }
+ return data
+}
diff --git a/btcutil/address.go b/btcutil/address.go
deleted file mode 100644
index 579367d..0000000
--- a/btcutil/address.go
+++ /dev/null
@@ -1,801 +0,0 @@
-// Copyright (c) 2013-2017 The btcsuite developers
-// Use of this source code is governed by an ISC
-// license that can be found in the LICENSE file.
-
-package btcutil
-
-import (
- "bytes"
- "encoding/hex"
- "errors"
- "fmt"
- "strings"
-
- "github.com/btcsuite/btcd/btcec/v2"
- "github.com/btcsuite/btcd/btcutil/base58"
- "github.com/btcsuite/btcd/btcutil/bech32"
- "github.com/btcsuite/btcd/chaincfg"
- "golang.org/x/crypto/ripemd160"
-)
-
-// UnsupportedWitnessVerError describes an error where a segwit address being
-// decoded has an unsupported witness version.
-type UnsupportedWitnessVerError byte
-
-func (e UnsupportedWitnessVerError) Error() string {
- return fmt.Sprintf("unsupported witness version: %#x", byte(e))
-}
-
-// UnsupportedWitnessProgLenError describes an error where a segwit address
-// being decoded has an unsupported witness program length.
-type UnsupportedWitnessProgLenError int
-
-func (e UnsupportedWitnessProgLenError) Error() string {
- return fmt.Sprintf("unsupported witness program length: %d", int(e))
-}
-
-var (
- // ErrChecksumMismatch describes an error where decoding failed due
- // to a bad checksum.
- ErrChecksumMismatch = errors.New("checksum mismatch")
-
- // ErrUnknownAddressType describes an error where an address can not
- // decoded as a specific address type due to the string encoding
- // beginning with an identifier byte unknown to any standard or
- // registered (via chaincfg.Register) network.
- ErrUnknownAddressType = errors.New("unknown address type")
-
- // ErrAddressCollision describes an error where an address can not
- // be uniquely determined as either a pay-to-pubkey-hash or
- // pay-to-script-hash address since the leading identifier is used for
- // describing both address kinds, but for different networks. Rather
- // than assuming or defaulting to one or the other, this error is
- // returned and the caller must decide how to decode the address.
- ErrAddressCollision = errors.New("address collision")
-)
-
-// encodeAddress returns a human-readable payment address given a ripemd160 hash
-// and netID which encodes the bitcoin network and address type. It is used
-// in both pay-to-pubkey-hash (P2PKH) and pay-to-script-hash (P2SH) address
-// encoding.
-func encodeAddress(hash160 []byte, netID byte) string {
- // Format is 1 byte for a network and address class (i.e. P2PKH vs
- // P2SH), 20 bytes for a RIPEMD160 hash, and 4 bytes of checksum.
- return base58.CheckEncode(hash160[:ripemd160.Size], netID)
-}
-
-// encodeSegWitAddress creates a bech32 (or bech32m for SegWit v1) encoded
-// address string representation from witness version and witness program.
-func encodeSegWitAddress(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 := bech32.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)
-
- var bech string
- switch witnessVersion {
- case 0:
- bech, err = bech32.Encode(hrp, combined)
-
- case 1:
- bech, err = bech32.EncodeM(hrp, combined)
-
- default:
- return "", fmt.Errorf("unsupported witness version %d",
- witnessVersion)
- }
- if err != nil {
- return "", err
- }
-
- // Check validity by decoding the created address.
- version, program, err := decodeSegWitAddress(bech)
- if err != nil {
- return "", fmt.Errorf("invalid segwit address: %v", err)
- }
-
- if version != witnessVersion || !bytes.Equal(program, witnessProgram) {
- return "", fmt.Errorf("invalid segwit address")
- }
-
- return bech, nil
-}
-
-// Address is an interface type for any type of destination a transaction
-// output may spend to. This includes pay-to-pubkey (P2PK), pay-to-pubkey-hash
-// (P2PKH), and pay-to-script-hash (P2SH). Address is designed to be generic
-// enough that other kinds of addresses may be added in the future without
-// changing the decoding and encoding API.
-type Address interface {
- // String returns the string encoding of the transaction output
- // destination.
- //
- // Please note that String differs subtly from EncodeAddress: String
- // will return the value as a string without any conversion, while
- // EncodeAddress may convert destination types (for example,
- // converting pubkeys to P2PKH addresses) before encoding as a
- // payment address string.
- String() string
-
- // EncodeAddress returns the string encoding of the payment address
- // associated with the Address value. See the comment on String
- // for how this method differs from String.
- EncodeAddress() string
-
- // ScriptAddress returns the raw bytes of the address to be used
- // when inserting the address into a txout's script.
- ScriptAddress() []byte
-
- // IsForNet returns whether or not the address is associated with the
- // passed bitcoin network.
- IsForNet(*chaincfg.Params) bool
-}
-
-// DecodeAddress decodes the string encoding of an address and returns
-// the Address if addr is a valid encoding for a known address type.
-//
-// The bitcoin network the address is associated with is extracted if possible.
-// When the address does not encode the network, such as in the case of a raw
-// public key, the address will be associated with the passed defaultNet.
-func DecodeAddress(addr string, defaultNet *chaincfg.Params) (Address, error) {
- // Bech32 encoded segwit addresses start with a human-readable part
- // (hrp) followed by '1'. For Bitcoin mainnet the hrp is "bc", and for
- // testnet it is "tb". If the address string has a prefix that matches
- // one of the prefixes for the known networks, we try to decode it as
- // a segwit address.
- oneIndex := strings.LastIndexByte(addr, '1')
- if oneIndex > 1 {
- prefix := addr[:oneIndex+1]
- if chaincfg.IsBech32SegwitPrefix(prefix) {
- witnessVer, witnessProg, err := decodeSegWitAddress(addr)
- if err != nil {
- return nil, err
- }
-
- // We currently only support P2WPKH and P2WSH, which is
- // witness version 0 and P2TR which is witness version
- // 1.
- if witnessVer != 0 && witnessVer != 1 {
- return nil, UnsupportedWitnessVerError(witnessVer)
- }
-
- // The HRP is everything before the found '1'.
- hrp := prefix[:len(prefix)-1]
-
- switch len(witnessProg) {
- case 2:
- // Check if it's a P2A address (witness version
- // 1, program 0x4e73).
- if witnessVer == 1 && bytes.Equal(
- witnessProg, []byte{0x4e, 0x73},
- ) {
- return newAddressPayToAnchor(hrp), nil
- }
-
- return nil, UnsupportedWitnessProgLenError(len(witnessProg))
-
- case 20:
- return newAddressWitnessPubKeyHash(hrp, witnessProg)
-
- case 32:
- if witnessVer == 1 {
- return newAddressTaproot(hrp, witnessProg)
- }
-
- return newAddressWitnessScriptHash(hrp, witnessProg)
- default:
- return nil, UnsupportedWitnessProgLenError(len(witnessProg))
- }
- }
- }
-
- // Serialized public keys are either 65 bytes (130 hex chars) if
- // uncompressed/hybrid or 33 bytes (66 hex chars) if compressed.
- if len(addr) == 130 || len(addr) == 66 {
- serializedPubKey, err := hex.DecodeString(addr)
- if err != nil {
- return nil, err
- }
- return NewAddressPubKey(serializedPubKey, defaultNet)
- }
-
- // Switch on decoded length to determine the type.
- decoded, netID, err := base58.CheckDecode(addr)
- if err != nil {
- if err == base58.ErrChecksum {
- return nil, ErrChecksumMismatch
- }
- return nil, errors.New("decoded address is of unknown format")
- }
- switch len(decoded) {
- case ripemd160.Size: // P2PKH or P2SH
- isP2PKH := netID == defaultNet.PubKeyHashAddrID
- isP2SH := netID == defaultNet.ScriptHashAddrID
- switch hash160 := decoded; {
- case isP2PKH && isP2SH:
- return nil, ErrAddressCollision
- case isP2PKH:
- return newAddressPubKeyHash(hash160, netID)
- case isP2SH:
- return newAddressScriptHashFromHash(hash160, netID)
- default:
- return nil, ErrUnknownAddressType
- }
-
- default:
- return nil, errors.New("decoded address is of unknown size")
- }
-}
-
-// decodeSegWitAddress parses a bech32 encoded segwit address string and
-// returns the witness version and witness program byte representation.
-func decodeSegWitAddress(address string) (byte, []byte, error) {
- // Decode the bech32 encoded address.
- _, data, bech32version, err := bech32.DecodeGeneric(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: %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 := bech32.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))
- }
-
- // For witness version 0, the bech32 encoding must be used.
- if version == 0 && bech32version != bech32.Version0 {
- return 0, nil, fmt.Errorf("invalid checksum expected bech32 " +
- "encoding for address with witness version 0")
- }
-
- // For witness version 1, the bech32m encoding must be used.
- if version == 1 && bech32version != bech32.VersionM {
- return 0, nil, fmt.Errorf("invalid checksum expected bech32m " +
- "encoding for address with witness version 1")
- }
-
- return version, regrouped, nil
-}
-
-// AddressPubKeyHash is an Address for a pay-to-pubkey-hash (P2PKH)
-// transaction.
-type AddressPubKeyHash struct {
- hash [ripemd160.Size]byte
- netID byte
-}
-
-// NewAddressPubKeyHash returns a new AddressPubKeyHash. pkHash mustbe 20
-// bytes.
-func NewAddressPubKeyHash(pkHash []byte, net *chaincfg.Params) (*AddressPubKeyHash, error) {
- return newAddressPubKeyHash(pkHash, net.PubKeyHashAddrID)
-}
-
-// newAddressPubKeyHash is the internal API to create a pubkey hash address
-// with a known leading identifier byte for a network, rather than looking
-// it up through its parameters. This is useful when creating a new address
-// structure from a string encoding where the identifier byte is already
-// known.
-func newAddressPubKeyHash(pkHash []byte, netID byte) (*AddressPubKeyHash, error) {
- // Check for a valid pubkey hash length.
- if len(pkHash) != ripemd160.Size {
- return nil, errors.New("pkHash must be 20 bytes")
- }
-
- addr := &AddressPubKeyHash{netID: netID}
- copy(addr.hash[:], pkHash)
- return addr, nil
-}
-
-// EncodeAddress returns the string encoding of a pay-to-pubkey-hash
-// address. Part of the Address interface.
-func (a *AddressPubKeyHash) EncodeAddress() string {
- return encodeAddress(a.hash[:], a.netID)
-}
-
-// ScriptAddress returns the bytes to be included in a txout script to pay
-// to a pubkey hash. Part of the Address interface.
-func (a *AddressPubKeyHash) ScriptAddress() []byte {
- return a.hash[:]
-}
-
-// IsForNet returns whether or not the pay-to-pubkey-hash address is associated
-// with the passed bitcoin network.
-func (a *AddressPubKeyHash) IsForNet(net *chaincfg.Params) bool {
- return a.netID == net.PubKeyHashAddrID
-}
-
-// String returns a human-readable string for the pay-to-pubkey-hash address.
-// This is equivalent to calling EncodeAddress, but is provided so the type can
-// be used as a fmt.Stringer.
-func (a *AddressPubKeyHash) String() string {
- return a.EncodeAddress()
-}
-
-// Hash160 returns the underlying array of the pubkey hash. This can be useful
-// when an array is more appropriate than a slice (for example, when used as map
-// keys).
-func (a *AddressPubKeyHash) Hash160() *[ripemd160.Size]byte {
- return &a.hash
-}
-
-// AddressScriptHash is an Address for a pay-to-script-hash (P2SH)
-// transaction.
-type AddressScriptHash struct {
- hash [ripemd160.Size]byte
- netID byte
-}
-
-// NewAddressScriptHash returns a new AddressScriptHash.
-func NewAddressScriptHash(serializedScript []byte, net *chaincfg.Params) (*AddressScriptHash, error) {
- scriptHash := Hash160(serializedScript)
- return newAddressScriptHashFromHash(scriptHash, net.ScriptHashAddrID)
-}
-
-// NewAddressScriptHashFromHash returns a new AddressScriptHash. scriptHash
-// must be 20 bytes.
-func NewAddressScriptHashFromHash(scriptHash []byte, net *chaincfg.Params) (*AddressScriptHash, error) {
- return newAddressScriptHashFromHash(scriptHash, net.ScriptHashAddrID)
-}
-
-// newAddressScriptHashFromHash is the internal API to create a script hash
-// address with a known leading identifier byte for a network, rather than
-// looking it up through its parameters. This is useful when creating a new
-// address structure from a string encoding where the identifier byte is already
-// known.
-func newAddressScriptHashFromHash(scriptHash []byte, netID byte) (*AddressScriptHash, error) {
- // Check for a valid script hash length.
- if len(scriptHash) != ripemd160.Size {
- return nil, errors.New("scriptHash must be 20 bytes")
- }
-
- addr := &AddressScriptHash{netID: netID}
- copy(addr.hash[:], scriptHash)
- return addr, nil
-}
-
-// EncodeAddress returns the string encoding of a pay-to-script-hash
-// address. Part of the Address interface.
-func (a *AddressScriptHash) EncodeAddress() string {
- return encodeAddress(a.hash[:], a.netID)
-}
-
-// ScriptAddress returns the bytes to be included in a txout script to pay
-// to a script hash. Part of the Address interface.
-func (a *AddressScriptHash) ScriptAddress() []byte {
- return a.hash[:]
-}
-
-// IsForNet returns whether or not the pay-to-script-hash address is associated
-// with the passed bitcoin network.
-func (a *AddressScriptHash) IsForNet(net *chaincfg.Params) bool {
- return a.netID == net.ScriptHashAddrID
-}
-
-// String returns a human-readable string for the pay-to-script-hash address.
-// This is equivalent to calling EncodeAddress, but is provided so the type can
-// be used as a fmt.Stringer.
-func (a *AddressScriptHash) String() string {
- return a.EncodeAddress()
-}
-
-// Hash160 returns the underlying array of the script hash. This can be useful
-// when an array is more appropriate than a slice (for example, when used as map
-// keys).
-func (a *AddressScriptHash) Hash160() *[ripemd160.Size]byte {
- return &a.hash
-}
-
-// PubKeyFormat describes what format to use for a pay-to-pubkey address.
-type PubKeyFormat int
-
-const (
- // PKFUncompressed indicates the pay-to-pubkey address format is an
- // uncompressed public key.
- PKFUncompressed PubKeyFormat = iota
-
- // PKFCompressed indicates the pay-to-pubkey address format is a
- // compressed public key.
- PKFCompressed
-)
-
-// AddressPubKey is an Address for a pay-to-pubkey transaction.
-type AddressPubKey struct {
- pubKeyFormat PubKeyFormat
- pubKey *btcec.PublicKey
- pubKeyHashID byte
-}
-
-// NewAddressPubKey returns a new AddressPubKey which represents a pay-to-pubkey
-// address. The serializedPubKey parameter must be a valid pubkey and can be
-// uncompressed, compressed, or hybrid.
-func NewAddressPubKey(serializedPubKey []byte, net *chaincfg.Params) (*AddressPubKey, error) {
- pubKey, err := btcec.ParsePubKey(serializedPubKey)
- if err != nil {
- return nil, err
- }
-
- // Set the format of the pubkey. This probably should be returned
- // from btcec, but do it here to avoid API churn. We already know the
- // pubkey is valid since it parsed above, so it's safe to simply examine
- // the leading byte to get the format.
- pkFormat := PKFUncompressed
- switch serializedPubKey[0] {
- case 0x02, 0x03:
- pkFormat = PKFCompressed
- }
-
- return &AddressPubKey{
- pubKeyFormat: pkFormat,
- pubKey: pubKey,
- pubKeyHashID: net.PubKeyHashAddrID,
- }, nil
-}
-
-// serialize returns the serialization of the public key according to the
-// format associated with the address.
-func (a *AddressPubKey) serialize() []byte {
- switch a.pubKeyFormat {
- default:
- fallthrough
- case PKFUncompressed:
- return a.pubKey.SerializeUncompressed()
-
- case PKFCompressed:
- return a.pubKey.SerializeCompressed()
- }
-}
-
-// EncodeAddress returns the string encoding of the public key as a
-// pay-to-pubkey-hash. Note that the public key format (uncompressed,
-// compressed, etc) will change the resulting address. This is expected since
-// pay-to-pubkey-hash is a hash of the serialized public key which obviously
-// differs with the format. At the time of this writing, most Bitcoin addresses
-// are pay-to-pubkey-hash constructed from the uncompressed public key.
-//
-// Part of the Address interface.
-func (a *AddressPubKey) EncodeAddress() string {
- return encodeAddress(Hash160(a.serialize()), a.pubKeyHashID)
-}
-
-// ScriptAddress returns the bytes to be included in a txout script to pay
-// to a public key. Setting the public key format will affect the output of
-// this function accordingly. Part of the Address interface.
-func (a *AddressPubKey) ScriptAddress() []byte {
- return a.serialize()
-}
-
-// IsForNet returns whether or not the pay-to-pubkey address is associated
-// with the passed bitcoin network.
-func (a *AddressPubKey) IsForNet(net *chaincfg.Params) bool {
- return a.pubKeyHashID == net.PubKeyHashAddrID
-}
-
-// String returns the hex-encoded human-readable string for the pay-to-pubkey
-// address. This is not the same as calling EncodeAddress.
-func (a *AddressPubKey) String() string {
- return hex.EncodeToString(a.serialize())
-}
-
-// Format returns the format (uncompressed, compressed, etc) of the
-// pay-to-pubkey address.
-func (a *AddressPubKey) Format() PubKeyFormat {
- return a.pubKeyFormat
-}
-
-// SetFormat sets the format (uncompressed, compressed, etc) of the
-// pay-to-pubkey address.
-func (a *AddressPubKey) SetFormat(pkFormat PubKeyFormat) {
- a.pubKeyFormat = pkFormat
-}
-
-// AddressPubKeyHash returns the pay-to-pubkey address converted to a
-// pay-to-pubkey-hash address. Note that the public key format (uncompressed,
-// compressed, etc) will change the resulting address. This is expected since
-// pay-to-pubkey-hash is a hash of the serialized public key which obviously
-// differs with the format. At the time of this writing, most Bitcoin addresses
-// are pay-to-pubkey-hash constructed from the uncompressed public key.
-func (a *AddressPubKey) AddressPubKeyHash() *AddressPubKeyHash {
- addr := &AddressPubKeyHash{netID: a.pubKeyHashID}
- copy(addr.hash[:], Hash160(a.serialize()))
- return addr
-}
-
-// PubKey returns the underlying public key for the address.
-func (a *AddressPubKey) PubKey() *btcec.PublicKey {
- return a.pubKey
-}
-
-// AddressSegWit is the base address type for all SegWit addresses.
-type AddressSegWit struct {
- hrp string
- witnessVersion byte
- witnessProgram []byte
-}
-
-// EncodeAddress returns the bech32 (or bech32m for SegWit v1) string encoding
-// of an AddressSegWit.
-//
-// NOTE: This method is part of the Address interface.
-func (a *AddressSegWit) EncodeAddress() string {
- str, err := encodeSegWitAddress(
- a.hrp, a.witnessVersion, a.witnessProgram[:],
- )
- if err != nil {
- return ""
- }
- return str
-}
-
-// ScriptAddress returns the witness program for this address.
-//
-// NOTE: This method is part of the Address interface.
-func (a *AddressSegWit) ScriptAddress() []byte {
- return a.witnessProgram[:]
-}
-
-// IsForNet returns whether the AddressSegWit is associated with the passed
-// bitcoin network.
-//
-// NOTE: This method is part of the Address interface.
-func (a *AddressSegWit) IsForNet(net *chaincfg.Params) bool {
- return a.hrp == net.Bech32HRPSegwit
-}
-
-// String returns a human-readable string for the AddressWitnessPubKeyHash.
-// This is equivalent to calling EncodeAddress, but is provided so the type
-// can be used as a fmt.Stringer.
-//
-// NOTE: This method is part of the Address interface.
-func (a *AddressSegWit) String() string {
- return a.EncodeAddress()
-}
-
-// Hrp returns the human-readable part of the bech32 (or bech32m for SegWit v1)
-// encoded AddressSegWit.
-func (a *AddressSegWit) Hrp() string {
- return a.hrp
-}
-
-// WitnessVersion returns the witness version of the AddressSegWit.
-func (a *AddressSegWit) WitnessVersion() byte {
- return a.witnessVersion
-}
-
-// WitnessProgram returns the witness program of the AddressSegWit.
-func (a *AddressSegWit) WitnessProgram() []byte {
- return a.witnessProgram[:]
-}
-
-// AddressWitnessPubKeyHash is an Address for a pay-to-witness-pubkey-hash
-// (P2WPKH) output. See BIP 173 for further details regarding native segregated
-// witness address encoding:
-// https://github.com/bitcoin/bips/blob/master/bip-0173.mediawiki
-type AddressWitnessPubKeyHash struct {
- AddressSegWit
-}
-
-// NewAddressWitnessPubKeyHash returns a new AddressWitnessPubKeyHash.
-func NewAddressWitnessPubKeyHash(witnessProg []byte,
- net *chaincfg.Params) (*AddressWitnessPubKeyHash, error) {
-
- return newAddressWitnessPubKeyHash(net.Bech32HRPSegwit, witnessProg)
-}
-
-// newAddressWitnessPubKeyHash is an internal helper function to create an
-// AddressWitnessPubKeyHash with a known human-readable part, rather than
-// looking it up through its parameters.
-func newAddressWitnessPubKeyHash(hrp string,
- witnessProg []byte) (*AddressWitnessPubKeyHash, error) {
-
- // Check for valid program length for witness version 0, which is 20
- // for P2WPKH.
- if len(witnessProg) != 20 {
- return nil, errors.New("witness program must be 20 " +
- "bytes for p2wpkh")
- }
-
- addr := &AddressWitnessPubKeyHash{
- AddressSegWit{
- hrp: strings.ToLower(hrp),
- witnessVersion: 0x00,
- witnessProgram: witnessProg,
- },
- }
-
- return addr, nil
-}
-
-// Hash160 returns the witness program of the AddressWitnessPubKeyHash as a
-// byte array.
-func (a *AddressWitnessPubKeyHash) Hash160() *[20]byte {
- var pubKeyHashWitnessProgram [20]byte
- copy(pubKeyHashWitnessProgram[:], a.witnessProgram)
- return &pubKeyHashWitnessProgram
-}
-
-// AddressWitnessScriptHash is an Address for a pay-to-witness-script-hash
-// (P2WSH) output. See BIP 173 for further details regarding native segregated
-// witness address encoding:
-// https://github.com/bitcoin/bips/blob/master/bip-0173.mediawiki
-type AddressWitnessScriptHash struct {
- AddressSegWit
-}
-
-// NewAddressWitnessScriptHash returns a new AddressWitnessPubKeyHash.
-func NewAddressWitnessScriptHash(witnessProg []byte,
- net *chaincfg.Params) (*AddressWitnessScriptHash, error) {
-
- return newAddressWitnessScriptHash(net.Bech32HRPSegwit, witnessProg)
-}
-
-// newAddressWitnessScriptHash is an internal helper function to create an
-// AddressWitnessScriptHash with a known human-readable part, rather than
-// looking it up through its parameters.
-func newAddressWitnessScriptHash(hrp string,
- witnessProg []byte) (*AddressWitnessScriptHash, error) {
-
- // Check for valid program length for witness version 0, which is 32
- // for P2WSH.
- if len(witnessProg) != 32 {
- return nil, errors.New("witness program must be 32 " +
- "bytes for p2wsh")
- }
-
- addr := &AddressWitnessScriptHash{
- AddressSegWit{
- hrp: strings.ToLower(hrp),
- witnessVersion: 0x00,
- witnessProgram: witnessProg,
- },
- }
-
- return addr, nil
-}
-
-// AddressTaproot is an Address for a pay-to-taproot (P2TR) output. See BIP 341
-// for further details.
-type AddressTaproot struct {
- AddressSegWit
-}
-
-// NewAddressTaproot returns a new AddressTaproot.
-func NewAddressTaproot(witnessProg []byte,
- net *chaincfg.Params) (*AddressTaproot, error) {
-
- return newAddressTaproot(net.Bech32HRPSegwit, witnessProg)
-}
-
-// newAddressTaproot is an internal helper function to create an
-// AddressTaproot with a known human-readable part, rather than
-// looking it up through its parameters.
-func newAddressTaproot(hrp string,
- witnessProg []byte) (*AddressTaproot, error) {
-
- // Check for valid program length for witness version 1, which is 32
- // for P2TR.
- if len(witnessProg) != 32 {
- return nil, errors.New("witness program must be 32 bytes for " +
- "p2tr")
- }
-
- addr := &AddressTaproot{
- AddressSegWit{
- hrp: strings.ToLower(hrp),
- witnessVersion: 0x01,
- witnessProgram: witnessProg,
- },
- }
-
- return addr, nil
-}
-
-// payToAnchorScript is the fixed script bytes for a pay-to-anchor output:
-// OP_1 OP_DATA_2 0x4e73. This is defined here to avoid an import cycle with
-// txscript. The same constant is exported as txscript.PayToAnchorScript;
-// keep both definitions in sync.
-var payToAnchorScript = []byte{0x51, 0x02, 0x4e, 0x73}
-
-// payToAnchorWitnessProgram is the 2-byte witness program portion of a P2A
-// output (i.e. the bytes that follow the OP_1 / OP_DATA_2 prefix in
-// payToAnchorScript).
-var payToAnchorWitnessProgram = []byte{0x4e, 0x73}
-
-// AddressPayToAnchor is an Address for a pay-to-anchor (P2A) output. P2A
-// outputs use the fixed script OP_1 <0x4e73> and have specific bech32
-// addresses for each network.
-type AddressPayToAnchor struct {
- hrp string
-}
-
-// NewAddressPayToAnchor returns a new AddressPayToAnchor for the given network.
-func NewAddressPayToAnchor(net *chaincfg.Params) (*AddressPayToAnchor, error) {
- if net == nil {
- return nil, errors.New("nil network")
- }
-
- return newAddressPayToAnchor(net.Bech32HRPSegwit), nil
-}
-
-// newAddressPayToAnchor is an internal helper function to create an
-// AddressPayToAnchor with a known human-readable part, rather than looking it
-// up through its parameters. The HRP is normalized to lowercase so that
-// addresses decoded from all-uppercase bech32 strings (which BIP 173 allows)
-// still compare equal to the lowercase network HRP in IsForNet.
-func newAddressPayToAnchor(hrp string) *AddressPayToAnchor {
- return &AddressPayToAnchor{
- hrp: strings.ToLower(hrp),
- }
-}
-
-// String returns a human-readable string for the pay-to-anchor address. This
-// is equivalent to EncodeAddress, but is provided to satisfy the Stringer
-// interface.
-func (a *AddressPayToAnchor) String() string {
- return a.EncodeAddress()
-}
-
-// EncodeAddress returns the bech32m string encoding of the pay-to-anchor
-// address. P2A addresses are encoded using witness version 1 with the program
-// bytes 0x4e73, resulting in these addresses per network:
-//
-// - Mainnet: bc1pfeessrawgf
-// - Testnet: tb1pfees9rn5nz
-// - Regtest: bcrt1pfeesnyr2tx
-// - Simnet: sb1pfeesxv0pfa
-func (a *AddressPayToAnchor) EncodeAddress() string {
- // For unknown networks, generate the address from the anchor data.
- // This shouldn't happen in practice.
- anchorData := []byte{0x4e, 0x73}
- addr, err := encodeSegWitAddress(a.hrp, 1, anchorData)
- if err != nil {
- return ""
- }
- return addr
-}
-
-// ScriptAddress returns the witness program portion of the P2A address (the
-// 2-byte program 0x4e73). This matches the convention used by other segwit
-// address types, where ScriptAddress returns the witness program and the
-// outer script wrapping (OP_1 OP_DATA_2 ...) is added by PayToAddrScript.
-func (a *AddressPayToAnchor) ScriptAddress() []byte {
- return payToAnchorWitnessProgram
-}
-
-// IsForNet returns whether the address is associated with the passed
-// bitcoin network.
-func (a *AddressPayToAnchor) IsForNet(net *chaincfg.Params) bool {
- return a.hrp == net.Bech32HRPSegwit
-}
diff --git a/btcutil/address_test.go b/btcutil/address_test.go
deleted file mode 100644
index f5ae2ac..0000000
--- a/btcutil/address_test.go
+++ /dev/null
@@ -1,896 +0,0 @@
-// Copyright (c) 2013-2017 The btcsuite developers
-// Use of this source code is governed by an ISC
-// license that can be found in the LICENSE file.
-
-package btcutil_test
-
-import (
- "bytes"
- "encoding/hex"
- "fmt"
- "reflect"
- "strings"
- "testing"
-
- "github.com/btcsuite/btcd/btcutil"
- "github.com/btcsuite/btcd/chaincfg"
- "github.com/btcsuite/btcd/wire"
- "golang.org/x/crypto/ripemd160"
-)
-
-type CustomParamStruct struct {
- Net wire.BitcoinNet
- PubKeyHashAddrID byte
- ScriptHashAddrID byte
- Bech32HRPSegwit string
-}
-
-var CustomParams = CustomParamStruct{
- Net: 0xdbb6c0fb, // litecoin mainnet HD version bytes
- PubKeyHashAddrID: 0x30, // starts with L
- ScriptHashAddrID: 0x32, // starts with M
- Bech32HRPSegwit: "ltc", // starts with ltc
-}
-
-// We use this function to be able to test functionality in DecodeAddress for
-// defaultNet addresses
-func applyCustomParams(params chaincfg.Params, customParams CustomParamStruct) chaincfg.Params {
- params.Net = customParams.Net
- params.PubKeyHashAddrID = customParams.PubKeyHashAddrID
- params.ScriptHashAddrID = customParams.ScriptHashAddrID
- params.Bech32HRPSegwit = customParams.Bech32HRPSegwit
- return params
-}
-
-var customParams = applyCustomParams(chaincfg.MainNetParams, CustomParams)
-
-func TestAddresses(t *testing.T) {
- tests := []struct {
- name string
- addr string
- encoded string
- valid bool
- result btcutil.Address
- f func() (btcutil.Address, error)
- net *chaincfg.Params
- }{
- // Positive P2PKH tests.
- {
- name: "mainnet p2pkh",
- addr: "1MirQ9bwyQcGVJPwKUgapu5ouK2E2Ey4gX",
- encoded: "1MirQ9bwyQcGVJPwKUgapu5ouK2E2Ey4gX",
- valid: true,
- result: btcutil.TstAddressPubKeyHash(
- [ripemd160.Size]byte{
- 0xe3, 0x4c, 0xce, 0x70, 0xc8, 0x63, 0x73, 0x27, 0x3e, 0xfc,
- 0xc5, 0x4c, 0xe7, 0xd2, 0xa4, 0x91, 0xbb, 0x4a, 0x0e, 0x84},
- chaincfg.MainNetParams.PubKeyHashAddrID),
- f: func() (btcutil.Address, error) {
- pkHash := []byte{
- 0xe3, 0x4c, 0xce, 0x70, 0xc8, 0x63, 0x73, 0x27, 0x3e, 0xfc,
- 0xc5, 0x4c, 0xe7, 0xd2, 0xa4, 0x91, 0xbb, 0x4a, 0x0e, 0x84}
- return btcutil.NewAddressPubKeyHash(pkHash, &chaincfg.MainNetParams)
- },
- net: &chaincfg.MainNetParams,
- },
- {
- name: "mainnet p2pkh 2",
- addr: "12MzCDwodF9G1e7jfwLXfR164RNtx4BRVG",
- encoded: "12MzCDwodF9G1e7jfwLXfR164RNtx4BRVG",
- valid: true,
- result: btcutil.TstAddressPubKeyHash(
- [ripemd160.Size]byte{
- 0x0e, 0xf0, 0x30, 0x10, 0x7f, 0xd2, 0x6e, 0x0b, 0x6b, 0xf4,
- 0x05, 0x12, 0xbc, 0xa2, 0xce, 0xb1, 0xdd, 0x80, 0xad, 0xaa},
- chaincfg.MainNetParams.PubKeyHashAddrID),
- f: func() (btcutil.Address, error) {
- pkHash := []byte{
- 0x0e, 0xf0, 0x30, 0x10, 0x7f, 0xd2, 0x6e, 0x0b, 0x6b, 0xf4,
- 0x05, 0x12, 0xbc, 0xa2, 0xce, 0xb1, 0xdd, 0x80, 0xad, 0xaa}
- return btcutil.NewAddressPubKeyHash(pkHash, &chaincfg.MainNetParams)
- },
- net: &chaincfg.MainNetParams,
- },
- {
- name: "litecoin mainnet p2pkh",
- addr: "LM2WMpR1Rp6j3Sa59cMXMs1SPzj9eXpGc1",
- encoded: "LM2WMpR1Rp6j3Sa59cMXMs1SPzj9eXpGc1",
- valid: true,
- result: btcutil.TstAddressPubKeyHash(
- [ripemd160.Size]byte{
- 0x13, 0xc6, 0x0d, 0x8e, 0x68, 0xd7, 0x34, 0x9f, 0x5b, 0x4c,
- 0xa3, 0x62, 0xc3, 0x95, 0x4b, 0x15, 0x04, 0x50, 0x61, 0xb1},
- CustomParams.PubKeyHashAddrID),
- f: func() (btcutil.Address, error) {
- pkHash := []byte{
- 0x13, 0xc6, 0x0d, 0x8e, 0x68, 0xd7, 0x34, 0x9f, 0x5b, 0x4c,
- 0xa3, 0x62, 0xc3, 0x95, 0x4b, 0x15, 0x04, 0x50, 0x61, 0xb1}
- return btcutil.NewAddressPubKeyHash(pkHash, &customParams)
- },
- net: &customParams,
- },
- {
- name: "testnet p2pkh",
- addr: "mrX9vMRYLfVy1BnZbc5gZjuyaqH3ZW2ZHz",
- encoded: "mrX9vMRYLfVy1BnZbc5gZjuyaqH3ZW2ZHz",
- valid: true,
- result: btcutil.TstAddressPubKeyHash(
- [ripemd160.Size]byte{
- 0x78, 0xb3, 0x16, 0xa0, 0x86, 0x47, 0xd5, 0xb7, 0x72, 0x83,
- 0xe5, 0x12, 0xd3, 0x60, 0x3f, 0x1f, 0x1c, 0x8d, 0xe6, 0x8f},
- chaincfg.TestNet3Params.PubKeyHashAddrID),
- f: func() (btcutil.Address, error) {
- pkHash := []byte{
- 0x78, 0xb3, 0x16, 0xa0, 0x86, 0x47, 0xd5, 0xb7, 0x72, 0x83,
- 0xe5, 0x12, 0xd3, 0x60, 0x3f, 0x1f, 0x1c, 0x8d, 0xe6, 0x8f}
- return btcutil.NewAddressPubKeyHash(pkHash, &chaincfg.TestNet3Params)
- },
- net: &chaincfg.TestNet3Params,
- },
-
- // Negative P2PKH tests.
- {
- name: "p2pkh wrong hash length",
- addr: "",
- valid: false,
- f: func() (btcutil.Address, error) {
- pkHash := []byte{
- 0x00, 0x0e, 0xf0, 0x30, 0x10, 0x7f, 0xd2, 0x6e, 0x0b, 0x6b,
- 0xf4, 0x05, 0x12, 0xbc, 0xa2, 0xce, 0xb1, 0xdd, 0x80, 0xad,
- 0xaa}
- return btcutil.NewAddressPubKeyHash(pkHash, &chaincfg.MainNetParams)
- },
- net: &chaincfg.MainNetParams,
- },
- {
- name: "p2pkh bad checksum",
- addr: "1MirQ9bwyQcGVJPwKUgapu5ouK2E2Ey4gY",
- valid: false,
- net: &chaincfg.MainNetParams,
- },
-
- // Positive P2SH tests.
- {
- // Taken from transactions:
- // output: 3c9018e8d5615c306d72397f8f5eef44308c98fb576a88e030c25456b4f3a7ac
- // input: 837dea37ddc8b1e3ce646f1a656e79bbd8cc7f558ac56a169626d649ebe2a3ba.
- name: "mainnet p2sh",
- addr: "3QJmV3qfvL9SuYo34YihAf3sRCW3qSinyC",
- encoded: "3QJmV3qfvL9SuYo34YihAf3sRCW3qSinyC",
- valid: true,
- result: btcutil.TstAddressScriptHash(
- [ripemd160.Size]byte{
- 0xf8, 0x15, 0xb0, 0x36, 0xd9, 0xbb, 0xbc, 0xe5, 0xe9, 0xf2,
- 0xa0, 0x0a, 0xbd, 0x1b, 0xf3, 0xdc, 0x91, 0xe9, 0x55, 0x10},
- chaincfg.MainNetParams.ScriptHashAddrID),
- f: func() (btcutil.Address, error) {
- script := []byte{
- 0x52, 0x41, 0x04, 0x91, 0xbb, 0xa2, 0x51, 0x09, 0x12, 0xa5,
- 0xbd, 0x37, 0xda, 0x1f, 0xb5, 0xb1, 0x67, 0x30, 0x10, 0xe4,
- 0x3d, 0x2c, 0x6d, 0x81, 0x2c, 0x51, 0x4e, 0x91, 0xbf, 0xa9,
- 0xf2, 0xeb, 0x12, 0x9e, 0x1c, 0x18, 0x33, 0x29, 0xdb, 0x55,
- 0xbd, 0x86, 0x8e, 0x20, 0x9a, 0xac, 0x2f, 0xbc, 0x02, 0xcb,
- 0x33, 0xd9, 0x8f, 0xe7, 0x4b, 0xf2, 0x3f, 0x0c, 0x23, 0x5d,
- 0x61, 0x26, 0xb1, 0xd8, 0x33, 0x4f, 0x86, 0x41, 0x04, 0x86,
- 0x5c, 0x40, 0x29, 0x3a, 0x68, 0x0c, 0xb9, 0xc0, 0x20, 0xe7,
- 0xb1, 0xe1, 0x06, 0xd8, 0xc1, 0x91, 0x6d, 0x3c, 0xef, 0x99,
- 0xaa, 0x43, 0x1a, 0x56, 0xd2, 0x53, 0xe6, 0x92, 0x56, 0xda,
- 0xc0, 0x9e, 0xf1, 0x22, 0xb1, 0xa9, 0x86, 0x81, 0x8a, 0x7c,
- 0xb6, 0x24, 0x53, 0x2f, 0x06, 0x2c, 0x1d, 0x1f, 0x87, 0x22,
- 0x08, 0x48, 0x61, 0xc5, 0xc3, 0x29, 0x1c, 0xcf, 0xfe, 0xf4,
- 0xec, 0x68, 0x74, 0x41, 0x04, 0x8d, 0x24, 0x55, 0xd2, 0x40,
- 0x3e, 0x08, 0x70, 0x8f, 0xc1, 0xf5, 0x56, 0x00, 0x2f, 0x1b,
- 0x6c, 0xd8, 0x3f, 0x99, 0x2d, 0x08, 0x50, 0x97, 0xf9, 0x97,
- 0x4a, 0xb0, 0x8a, 0x28, 0x83, 0x8f, 0x07, 0x89, 0x6f, 0xba,
- 0xb0, 0x8f, 0x39, 0x49, 0x5e, 0x15, 0xfa, 0x6f, 0xad, 0x6e,
- 0xdb, 0xfb, 0x1e, 0x75, 0x4e, 0x35, 0xfa, 0x1c, 0x78, 0x44,
- 0xc4, 0x1f, 0x32, 0x2a, 0x18, 0x63, 0xd4, 0x62, 0x13, 0x53,
- 0xae}
- return btcutil.NewAddressScriptHash(script, &chaincfg.MainNetParams)
- },
- net: &chaincfg.MainNetParams,
- },
- {
- name: "litecoin mainnet P2SH ",
- addr: "MVcg9uEvtWuP5N6V48EHfEtbz48qR8TKZ9",
- encoded: "MVcg9uEvtWuP5N6V48EHfEtbz48qR8TKZ9",
- valid: true,
- result: btcutil.TstAddressScriptHash(
- [ripemd160.Size]byte{
- 0xee, 0x34, 0xac, 0x67, 0x6b, 0xda, 0xf6, 0xe3, 0x70, 0xc8,
- 0xc8, 0x20, 0xb9, 0x48, 0xed, 0xfa, 0xd3, 0xa8, 0x73, 0xd8},
- CustomParams.ScriptHashAddrID),
- f: func() (btcutil.Address, error) {
- pkHash := []byte{
- 0xEE, 0x34, 0xAC, 0x67, 0x6B, 0xDA, 0xF6, 0xE3, 0x70, 0xC8,
- 0xC8, 0x20, 0xB9, 0x48, 0xED, 0xFA, 0xD3, 0xA8, 0x73, 0xD8}
- return btcutil.NewAddressScriptHashFromHash(pkHash, &customParams)
- },
- net: &customParams,
- },
- {
- // Taken from transactions:
- // output: b0539a45de13b3e0403909b8bd1a555b8cbe45fd4e3f3fda76f3a5f52835c29d
- // input: (not yet redeemed at time test was written)
- name: "mainnet p2sh 2",
- addr: "3NukJ6fYZJ5Kk8bPjycAnruZkE5Q7UW7i8",
- encoded: "3NukJ6fYZJ5Kk8bPjycAnruZkE5Q7UW7i8",
- valid: true,
- result: btcutil.TstAddressScriptHash(
- [ripemd160.Size]byte{
- 0xe8, 0xc3, 0x00, 0xc8, 0x79, 0x86, 0xef, 0xa8, 0x4c, 0x37,
- 0xc0, 0x51, 0x99, 0x29, 0x01, 0x9e, 0xf8, 0x6e, 0xb5, 0xb4},
- chaincfg.MainNetParams.ScriptHashAddrID),
- f: func() (btcutil.Address, error) {
- hash := []byte{
- 0xe8, 0xc3, 0x00, 0xc8, 0x79, 0x86, 0xef, 0xa8, 0x4c, 0x37,
- 0xc0, 0x51, 0x99, 0x29, 0x01, 0x9e, 0xf8, 0x6e, 0xb5, 0xb4}
- return btcutil.NewAddressScriptHashFromHash(hash, &chaincfg.MainNetParams)
- },
- net: &chaincfg.MainNetParams,
- },
- {
- // Taken from bitcoind base58_keys_valid.
- name: "testnet p2sh",
- addr: "2NBFNJTktNa7GZusGbDbGKRZTxdK9VVez3n",
- encoded: "2NBFNJTktNa7GZusGbDbGKRZTxdK9VVez3n",
- valid: true,
- result: btcutil.TstAddressScriptHash(
- [ripemd160.Size]byte{
- 0xc5, 0x79, 0x34, 0x2c, 0x2c, 0x4c, 0x92, 0x20, 0x20, 0x5e,
- 0x2c, 0xdc, 0x28, 0x56, 0x17, 0x04, 0x0c, 0x92, 0x4a, 0x0a},
- chaincfg.TestNet3Params.ScriptHashAddrID),
- f: func() (btcutil.Address, error) {
- hash := []byte{
- 0xc5, 0x79, 0x34, 0x2c, 0x2c, 0x4c, 0x92, 0x20, 0x20, 0x5e,
- 0x2c, 0xdc, 0x28, 0x56, 0x17, 0x04, 0x0c, 0x92, 0x4a, 0x0a}
- return btcutil.NewAddressScriptHashFromHash(hash, &chaincfg.TestNet3Params)
- },
- net: &chaincfg.TestNet3Params,
- },
-
- // Negative P2SH tests.
- {
- name: "p2sh wrong hash length",
- addr: "",
- valid: false,
- f: func() (btcutil.Address, error) {
- hash := []byte{
- 0x00, 0xf8, 0x15, 0xb0, 0x36, 0xd9, 0xbb, 0xbc, 0xe5, 0xe9,
- 0xf2, 0xa0, 0x0a, 0xbd, 0x1b, 0xf3, 0xdc, 0x91, 0xe9, 0x55,
- 0x10}
- return btcutil.NewAddressScriptHashFromHash(hash, &chaincfg.MainNetParams)
- },
- net: &chaincfg.MainNetParams,
- },
-
- // Positive P2PK tests.
- {
- name: "mainnet p2pk compressed (0x02)",
- addr: "02192d74d0cb94344c9569c2e77901573d8d7903c3ebec3a957724895dca52c6b4",
- encoded: "13CG6SJ3yHUXo4Cr2RY4THLLJrNFuG3gUg",
- valid: true,
- result: btcutil.TstAddressPubKey(
- []byte{
- 0x02, 0x19, 0x2d, 0x74, 0xd0, 0xcb, 0x94, 0x34, 0x4c, 0x95,
- 0x69, 0xc2, 0xe7, 0x79, 0x01, 0x57, 0x3d, 0x8d, 0x79, 0x03,
- 0xc3, 0xeb, 0xec, 0x3a, 0x95, 0x77, 0x24, 0x89, 0x5d, 0xca,
- 0x52, 0xc6, 0xb4},
- btcutil.PKFCompressed, chaincfg.MainNetParams.PubKeyHashAddrID),
- f: func() (btcutil.Address, error) {
- serializedPubKey := []byte{
- 0x02, 0x19, 0x2d, 0x74, 0xd0, 0xcb, 0x94, 0x34, 0x4c, 0x95,
- 0x69, 0xc2, 0xe7, 0x79, 0x01, 0x57, 0x3d, 0x8d, 0x79, 0x03,
- 0xc3, 0xeb, 0xec, 0x3a, 0x95, 0x77, 0x24, 0x89, 0x5d, 0xca,
- 0x52, 0xc6, 0xb4}
- return btcutil.NewAddressPubKey(serializedPubKey, &chaincfg.MainNetParams)
- },
- net: &chaincfg.MainNetParams,
- },
- {
- name: "mainnet p2pk compressed (0x03)",
- addr: "03b0bd634234abbb1ba1e986e884185c61cf43e001f9137f23c2c409273eb16e65",
- encoded: "15sHANNUBSh6nDp8XkDPmQcW6n3EFwmvE6",
- valid: true,
- result: btcutil.TstAddressPubKey(
- []byte{
- 0x03, 0xb0, 0xbd, 0x63, 0x42, 0x34, 0xab, 0xbb, 0x1b, 0xa1,
- 0xe9, 0x86, 0xe8, 0x84, 0x18, 0x5c, 0x61, 0xcf, 0x43, 0xe0,
- 0x01, 0xf9, 0x13, 0x7f, 0x23, 0xc2, 0xc4, 0x09, 0x27, 0x3e,
- 0xb1, 0x6e, 0x65},
- btcutil.PKFCompressed, chaincfg.MainNetParams.PubKeyHashAddrID),
- f: func() (btcutil.Address, error) {
- serializedPubKey := []byte{
- 0x03, 0xb0, 0xbd, 0x63, 0x42, 0x34, 0xab, 0xbb, 0x1b, 0xa1,
- 0xe9, 0x86, 0xe8, 0x84, 0x18, 0x5c, 0x61, 0xcf, 0x43, 0xe0,
- 0x01, 0xf9, 0x13, 0x7f, 0x23, 0xc2, 0xc4, 0x09, 0x27, 0x3e,
- 0xb1, 0x6e, 0x65}
- return btcutil.NewAddressPubKey(serializedPubKey, &chaincfg.MainNetParams)
- },
- net: &chaincfg.MainNetParams,
- },
- {
- name: "mainnet p2pk uncompressed (0x04)",
- addr: "0411db93e1dcdb8a016b49840f8c53bc1eb68a382e97b1482ecad7b148a6909a5cb2" +
- "e0eaddfb84ccf9744464f82e160bfa9b8b64f9d4c03f999b8643f656b412a3",
- encoded: "12cbQLTFMXRnSzktFkuoG3eHoMeFtpTu3S",
- valid: true,
- result: btcutil.TstAddressPubKey(
- []byte{
- 0x04, 0x11, 0xdb, 0x93, 0xe1, 0xdc, 0xdb, 0x8a, 0x01, 0x6b,
- 0x49, 0x84, 0x0f, 0x8c, 0x53, 0xbc, 0x1e, 0xb6, 0x8a, 0x38,
- 0x2e, 0x97, 0xb1, 0x48, 0x2e, 0xca, 0xd7, 0xb1, 0x48, 0xa6,
- 0x90, 0x9a, 0x5c, 0xb2, 0xe0, 0xea, 0xdd, 0xfb, 0x84, 0xcc,
- 0xf9, 0x74, 0x44, 0x64, 0xf8, 0x2e, 0x16, 0x0b, 0xfa, 0x9b,
- 0x8b, 0x64, 0xf9, 0xd4, 0xc0, 0x3f, 0x99, 0x9b, 0x86, 0x43,
- 0xf6, 0x56, 0xb4, 0x12, 0xa3},
- btcutil.PKFUncompressed, chaincfg.MainNetParams.PubKeyHashAddrID),
- f: func() (btcutil.Address, error) {
- serializedPubKey := []byte{
- 0x04, 0x11, 0xdb, 0x93, 0xe1, 0xdc, 0xdb, 0x8a, 0x01, 0x6b,
- 0x49, 0x84, 0x0f, 0x8c, 0x53, 0xbc, 0x1e, 0xb6, 0x8a, 0x38,
- 0x2e, 0x97, 0xb1, 0x48, 0x2e, 0xca, 0xd7, 0xb1, 0x48, 0xa6,
- 0x90, 0x9a, 0x5c, 0xb2, 0xe0, 0xea, 0xdd, 0xfb, 0x84, 0xcc,
- 0xf9, 0x74, 0x44, 0x64, 0xf8, 0x2e, 0x16, 0x0b, 0xfa, 0x9b,
- 0x8b, 0x64, 0xf9, 0xd4, 0xc0, 0x3f, 0x99, 0x9b, 0x86, 0x43,
- 0xf6, 0x56, 0xb4, 0x12, 0xa3}
- return btcutil.NewAddressPubKey(serializedPubKey, &chaincfg.MainNetParams)
- },
- net: &chaincfg.MainNetParams,
- },
- {
- name: "testnet p2pk compressed (0x02)",
- addr: "02192d74d0cb94344c9569c2e77901573d8d7903c3ebec3a957724895dca52c6b4",
- encoded: "mhiDPVP2nJunaAgTjzWSHCYfAqxxrxzjmo",
- valid: true,
- result: btcutil.TstAddressPubKey(
- []byte{
- 0x02, 0x19, 0x2d, 0x74, 0xd0, 0xcb, 0x94, 0x34, 0x4c, 0x95,
- 0x69, 0xc2, 0xe7, 0x79, 0x01, 0x57, 0x3d, 0x8d, 0x79, 0x03,
- 0xc3, 0xeb, 0xec, 0x3a, 0x95, 0x77, 0x24, 0x89, 0x5d, 0xca,
- 0x52, 0xc6, 0xb4},
- btcutil.PKFCompressed, chaincfg.TestNet3Params.PubKeyHashAddrID),
- f: func() (btcutil.Address, error) {
- serializedPubKey := []byte{
- 0x02, 0x19, 0x2d, 0x74, 0xd0, 0xcb, 0x94, 0x34, 0x4c, 0x95,
- 0x69, 0xc2, 0xe7, 0x79, 0x01, 0x57, 0x3d, 0x8d, 0x79, 0x03,
- 0xc3, 0xeb, 0xec, 0x3a, 0x95, 0x77, 0x24, 0x89, 0x5d, 0xca,
- 0x52, 0xc6, 0xb4}
- return btcutil.NewAddressPubKey(serializedPubKey, &chaincfg.TestNet3Params)
- },
- net: &chaincfg.TestNet3Params,
- },
- {
- name: "testnet p2pk compressed (0x03)",
- addr: "03b0bd634234abbb1ba1e986e884185c61cf43e001f9137f23c2c409273eb16e65",
- encoded: "mkPETRTSzU8MZLHkFKBmbKppxmdw9qT42t",
- valid: true,
- result: btcutil.TstAddressPubKey(
- []byte{
- 0x03, 0xb0, 0xbd, 0x63, 0x42, 0x34, 0xab, 0xbb, 0x1b, 0xa1,
- 0xe9, 0x86, 0xe8, 0x84, 0x18, 0x5c, 0x61, 0xcf, 0x43, 0xe0,
- 0x01, 0xf9, 0x13, 0x7f, 0x23, 0xc2, 0xc4, 0x09, 0x27, 0x3e,
- 0xb1, 0x6e, 0x65},
- btcutil.PKFCompressed, chaincfg.TestNet3Params.PubKeyHashAddrID),
- f: func() (btcutil.Address, error) {
- serializedPubKey := []byte{
- 0x03, 0xb0, 0xbd, 0x63, 0x42, 0x34, 0xab, 0xbb, 0x1b, 0xa1,
- 0xe9, 0x86, 0xe8, 0x84, 0x18, 0x5c, 0x61, 0xcf, 0x43, 0xe0,
- 0x01, 0xf9, 0x13, 0x7f, 0x23, 0xc2, 0xc4, 0x09, 0x27, 0x3e,
- 0xb1, 0x6e, 0x65}
- return btcutil.NewAddressPubKey(serializedPubKey, &chaincfg.TestNet3Params)
- },
- net: &chaincfg.TestNet3Params,
- },
- {
- name: "testnet p2pk uncompressed (0x04)",
- addr: "0411db93e1dcdb8a016b49840f8c53bc1eb68a382e97b1482ecad7b148a6909a5" +
- "cb2e0eaddfb84ccf9744464f82e160bfa9b8b64f9d4c03f999b8643f656b412a3",
- encoded: "mh8YhPYEAYs3E7EVyKtB5xrcfMExkkdEMF",
- valid: true,
- result: btcutil.TstAddressPubKey(
- []byte{
- 0x04, 0x11, 0xdb, 0x93, 0xe1, 0xdc, 0xdb, 0x8a, 0x01, 0x6b,
- 0x49, 0x84, 0x0f, 0x8c, 0x53, 0xbc, 0x1e, 0xb6, 0x8a, 0x38,
- 0x2e, 0x97, 0xb1, 0x48, 0x2e, 0xca, 0xd7, 0xb1, 0x48, 0xa6,
- 0x90, 0x9a, 0x5c, 0xb2, 0xe0, 0xea, 0xdd, 0xfb, 0x84, 0xcc,
- 0xf9, 0x74, 0x44, 0x64, 0xf8, 0x2e, 0x16, 0x0b, 0xfa, 0x9b,
- 0x8b, 0x64, 0xf9, 0xd4, 0xc0, 0x3f, 0x99, 0x9b, 0x86, 0x43,
- 0xf6, 0x56, 0xb4, 0x12, 0xa3},
- btcutil.PKFUncompressed, chaincfg.TestNet3Params.PubKeyHashAddrID),
- f: func() (btcutil.Address, error) {
- serializedPubKey := []byte{
- 0x04, 0x11, 0xdb, 0x93, 0xe1, 0xdc, 0xdb, 0x8a, 0x01, 0x6b,
- 0x49, 0x84, 0x0f, 0x8c, 0x53, 0xbc, 0x1e, 0xb6, 0x8a, 0x38,
- 0x2e, 0x97, 0xb1, 0x48, 0x2e, 0xca, 0xd7, 0xb1, 0x48, 0xa6,
- 0x90, 0x9a, 0x5c, 0xb2, 0xe0, 0xea, 0xdd, 0xfb, 0x84, 0xcc,
- 0xf9, 0x74, 0x44, 0x64, 0xf8, 0x2e, 0x16, 0x0b, 0xfa, 0x9b,
- 0x8b, 0x64, 0xf9, 0xd4, 0xc0, 0x3f, 0x99, 0x9b, 0x86, 0x43,
- 0xf6, 0x56, 0xb4, 0x12, 0xa3}
- return btcutil.NewAddressPubKey(serializedPubKey, &chaincfg.TestNet3Params)
- },
- net: &chaincfg.TestNet3Params,
- },
- // Segwit address tests.
- {
- name: "segwit mainnet p2wpkh v0",
- addr: "BC1QW508D6QEJXTDG4Y5R3ZARVARY0C5XW7KV8F3T4",
- encoded: "bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4",
- valid: true,
- result: btcutil.TstAddressWitnessPubKeyHash(
- 0,
- [20]byte{
- 0x75, 0x1e, 0x76, 0xe8, 0x19, 0x91, 0x96, 0xd4, 0x54, 0x94,
- 0x1c, 0x45, 0xd1, 0xb3, 0xa3, 0x23, 0xf1, 0x43, 0x3b, 0xd6},
- chaincfg.MainNetParams.Bech32HRPSegwit),
- f: func() (btcutil.Address, error) {
- pkHash := []byte{
- 0x75, 0x1e, 0x76, 0xe8, 0x19, 0x91, 0x96, 0xd4, 0x54, 0x94,
- 0x1c, 0x45, 0xd1, 0xb3, 0xa3, 0x23, 0xf1, 0x43, 0x3b, 0xd6}
- return btcutil.NewAddressWitnessPubKeyHash(pkHash, &chaincfg.MainNetParams)
- },
- net: &chaincfg.MainNetParams,
- },
- {
- name: "segwit mainnet p2wsh v0",
- addr: "bc1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3qccfmv3",
- encoded: "bc1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3qccfmv3",
- valid: true,
- result: btcutil.TstAddressWitnessScriptHash(
- 0,
- [32]byte{
- 0x18, 0x63, 0x14, 0x3c, 0x14, 0xc5, 0x16, 0x68,
- 0x04, 0xbd, 0x19, 0x20, 0x33, 0x56, 0xda, 0x13,
- 0x6c, 0x98, 0x56, 0x78, 0xcd, 0x4d, 0x27, 0xa1,
- 0xb8, 0xc6, 0x32, 0x96, 0x04, 0x90, 0x32, 0x62},
- chaincfg.MainNetParams.Bech32HRPSegwit),
- f: func() (btcutil.Address, error) {
- scriptHash := []byte{
- 0x18, 0x63, 0x14, 0x3c, 0x14, 0xc5, 0x16, 0x68,
- 0x04, 0xbd, 0x19, 0x20, 0x33, 0x56, 0xda, 0x13,
- 0x6c, 0x98, 0x56, 0x78, 0xcd, 0x4d, 0x27, 0xa1,
- 0xb8, 0xc6, 0x32, 0x96, 0x04, 0x90, 0x32, 0x62}
- return btcutil.NewAddressWitnessScriptHash(scriptHash, &chaincfg.MainNetParams)
- },
- net: &chaincfg.MainNetParams,
- },
- {
- name: "segwit testnet p2wpkh v0",
- addr: "tb1qw508d6qejxtdg4y5r3zarvary0c5xw7kxpjzsx",
- encoded: "tb1qw508d6qejxtdg4y5r3zarvary0c5xw7kxpjzsx",
- valid: true,
- result: btcutil.TstAddressWitnessPubKeyHash(
- 0,
- [20]byte{
- 0x75, 0x1e, 0x76, 0xe8, 0x19, 0x91, 0x96, 0xd4, 0x54, 0x94,
- 0x1c, 0x45, 0xd1, 0xb3, 0xa3, 0x23, 0xf1, 0x43, 0x3b, 0xd6},
- chaincfg.TestNet3Params.Bech32HRPSegwit),
- f: func() (btcutil.Address, error) {
- pkHash := []byte{
- 0x75, 0x1e, 0x76, 0xe8, 0x19, 0x91, 0x96, 0xd4, 0x54, 0x94,
- 0x1c, 0x45, 0xd1, 0xb3, 0xa3, 0x23, 0xf1, 0x43, 0x3b, 0xd6}
- return btcutil.NewAddressWitnessPubKeyHash(pkHash, &chaincfg.TestNet3Params)
- },
- net: &chaincfg.TestNet3Params,
- },
- {
- name: "segwit testnet p2wsh v0",
- addr: "tb1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3q0sl5k7",
- encoded: "tb1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3q0sl5k7",
- valid: true,
- result: btcutil.TstAddressWitnessScriptHash(
- 0,
- [32]byte{
- 0x18, 0x63, 0x14, 0x3c, 0x14, 0xc5, 0x16, 0x68,
- 0x04, 0xbd, 0x19, 0x20, 0x33, 0x56, 0xda, 0x13,
- 0x6c, 0x98, 0x56, 0x78, 0xcd, 0x4d, 0x27, 0xa1,
- 0xb8, 0xc6, 0x32, 0x96, 0x04, 0x90, 0x32, 0x62},
- chaincfg.TestNet3Params.Bech32HRPSegwit),
- f: func() (btcutil.Address, error) {
- scriptHash := []byte{
- 0x18, 0x63, 0x14, 0x3c, 0x14, 0xc5, 0x16, 0x68,
- 0x04, 0xbd, 0x19, 0x20, 0x33, 0x56, 0xda, 0x13,
- 0x6c, 0x98, 0x56, 0x78, 0xcd, 0x4d, 0x27, 0xa1,
- 0xb8, 0xc6, 0x32, 0x96, 0x04, 0x90, 0x32, 0x62}
- return btcutil.NewAddressWitnessScriptHash(scriptHash, &chaincfg.TestNet3Params)
- },
- net: &chaincfg.TestNet3Params,
- },
- {
- name: "segwit testnet p2wsh witness v0",
- addr: "tb1qqqqqp399et2xygdj5xreqhjjvcmzhxw4aywxecjdzew6hylgvsesrxh6hy",
- encoded: "tb1qqqqqp399et2xygdj5xreqhjjvcmzhxw4aywxecjdzew6hylgvsesrxh6hy",
- valid: true,
- result: btcutil.TstAddressWitnessScriptHash(
- 0,
- [32]byte{
- 0x00, 0x00, 0x00, 0xc4, 0xa5, 0xca, 0xd4, 0x62,
- 0x21, 0xb2, 0xa1, 0x87, 0x90, 0x5e, 0x52, 0x66,
- 0x36, 0x2b, 0x99, 0xd5, 0xe9, 0x1c, 0x6c, 0xe2,
- 0x4d, 0x16, 0x5d, 0xab, 0x93, 0xe8, 0x64, 0x33},
- chaincfg.TestNet3Params.Bech32HRPSegwit),
- f: func() (btcutil.Address, error) {
- scriptHash := []byte{
- 0x00, 0x00, 0x00, 0xc4, 0xa5, 0xca, 0xd4, 0x62,
- 0x21, 0xb2, 0xa1, 0x87, 0x90, 0x5e, 0x52, 0x66,
- 0x36, 0x2b, 0x99, 0xd5, 0xe9, 0x1c, 0x6c, 0xe2,
- 0x4d, 0x16, 0x5d, 0xab, 0x93, 0xe8, 0x64, 0x33}
- return btcutil.NewAddressWitnessScriptHash(scriptHash, &chaincfg.TestNet3Params)
- },
- net: &chaincfg.TestNet3Params,
- },
- {
- name: "segwit litecoin mainnet p2wpkh v0",
- addr: "LTC1QW508D6QEJXTDG4Y5R3ZARVARY0C5XW7KGMN4N9",
- encoded: "ltc1qw508d6qejxtdg4y5r3zarvary0c5xw7kgmn4n9",
- valid: true,
- result: btcutil.TstAddressWitnessPubKeyHash(
- 0,
- [20]byte{
- 0x75, 0x1e, 0x76, 0xe8, 0x19, 0x91, 0x96, 0xd4, 0x54, 0x94,
- 0x1c, 0x45, 0xd1, 0xb3, 0xa3, 0x23, 0xf1, 0x43, 0x3b, 0xd6},
- CustomParams.Bech32HRPSegwit,
- ),
- f: func() (btcutil.Address, error) {
- pkHash := []byte{
- 0x75, 0x1e, 0x76, 0xe8, 0x19, 0x91, 0x96, 0xd4, 0x54, 0x94,
- 0x1c, 0x45, 0xd1, 0xb3, 0xa3, 0x23, 0xf1, 0x43, 0x3b, 0xd6}
- return btcutil.NewAddressWitnessPubKeyHash(pkHash, &customParams)
- },
- net: &customParams,
- },
-
- // P2TR address tests.
- {
- name: "segwit v1 mainnet p2tr",
- addr: "bc1paardr2nczq0rx5rqpfwnvpzm497zvux64y0f7wjgcs7xuuuh2nnqwr2d5c",
- encoded: "bc1paardr2nczq0rx5rqpfwnvpzm497zvux64y0f7wjgcs7xuuuh2nnqwr2d5c",
- valid: true,
- result: btcutil.TstAddressTaproot(
- 1, [32]byte{
- 0xef, 0x46, 0xd1, 0xaa, 0x78, 0x10, 0x1e, 0x33,
- 0x50, 0x60, 0x0a, 0x5d, 0x36, 0x04, 0x5b, 0xa9,
- 0x7c, 0x26, 0x70, 0xda, 0xa9, 0x1e, 0x9f, 0x3a,
- 0x48, 0xc4, 0x3c, 0x6e, 0x73, 0x97, 0x54, 0xe6,
- }, chaincfg.MainNetParams.Bech32HRPSegwit,
- ),
- f: func() (btcutil.Address, error) {
- scriptHash := []byte{
- 0xef, 0x46, 0xd1, 0xaa, 0x78, 0x10, 0x1e, 0x33,
- 0x50, 0x60, 0x0a, 0x5d, 0x36, 0x04, 0x5b, 0xa9,
- 0x7c, 0x26, 0x70, 0xda, 0xa9, 0x1e, 0x9f, 0x3a,
- 0x48, 0xc4, 0x3c, 0x6e, 0x73, 0x97, 0x54, 0xe6,
- }
- return btcutil.NewAddressTaproot(
- scriptHash, &chaincfg.MainNetParams,
- )
- },
- net: &chaincfg.MainNetParams,
- },
-
- // Invalid bech32m tests. Source:
- // https://github.com/bitcoin/bips/blob/master/bip-0350.mediawiki
- {
- name: "segwit v1 invalid human-readable part",
- addr: "tc1p0xlxvlhemja6c4dqv22uapctqupfhlxm9h8z3k2e72q4k9hcz7vq5zuyut",
- valid: false,
- net: &chaincfg.MainNetParams,
- },
- {
- name: "segwit v1 mainnet bech32 instead of bech32m",
- addr: "bc1p0xlxvlhemja6c4dqv22uapctqupfhlxm9h8z3k2e72q4k9hcz7vqh2y7hd",
- valid: false,
- net: &chaincfg.MainNetParams,
- },
- {
- name: "segwit v1 testnet bech32 instead of bech32m",
- addr: "tb1z0xlxvlhemja6c4dqv22uapctqupfhlxm9h8z3k2e72q4k9hcz7vqglt7rf",
- valid: false,
- net: &chaincfg.TestNet3Params,
- },
- {
- name: "segwit v1 mainnet bech32 instead of bech32m upper case",
- addr: "BC1S0XLXVLHEMJA6C4DQV22UAPCTQUPFHLXM9H8Z3K2E72Q4K9HCZ7VQ54WELL",
- valid: false,
- net: &chaincfg.MainNetParams,
- },
- {
- name: "segwit v0 mainnet bech32m instead of bech32",
- addr: "bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kemeawh",
- valid: false,
- net: &chaincfg.MainNetParams,
- },
- {
- name: "segwit v1 testnet bech32 instead of bech32m second test",
- addr: "tb1q0xlxvlhemja6c4dqv22uapctqupfhlxm9h8z3k2e72q4k9hcz7vq24jc47",
- valid: false,
- net: &chaincfg.TestNet3Params,
- },
- {
- name: "segwit v1 mainnet bech32m invalid character in checksum",
- addr: "bc1p38j9r5y49hruaue7wxjce0updqjuyyx0kh56v8s25huc6995vvpql3jow4",
- valid: false,
- net: &chaincfg.MainNetParams,
- },
- {
- name: "segwit mainnet witness v17",
- addr: "BC130XLXVLHEMJA6C4DQV22UAPCTQUPFHLXM9H8Z3K2E72Q4K9HCZ7VQ7ZWS8R",
- valid: false,
- net: &chaincfg.MainNetParams,
- },
- {
- name: "segwit v1 mainnet bech32m invalid program length (1 byte)",
- addr: "bc1pw5dgrnzv",
- valid: false,
- net: &chaincfg.MainNetParams,
- },
- {
- name: "segwit v1 mainnet bech32m invalid program length (41 bytes)",
- addr: "bc1p0xlxvlhemja6c4dqv22uapctqupfhlxm9h8z3k2e72q4k9hcz7v8n0nx0muaewav253zgeav",
- valid: false,
- net: &chaincfg.MainNetParams,
- },
- {
- name: "segwit v1 testnet bech32m mixed case",
- addr: "tb1p0xlxvlhemja6c4dqv22uapctqupfhlxm9h8z3k2e72q4k9hcz7vq47Zagq",
- valid: false,
- net: &chaincfg.TestNet3Params,
- },
- {
- name: "segwit v1 mainnet bech32m zero padding of more than 4 bits",
- addr: "bc1p0xlxvlhemja6c4dqv22uapctqupfhlxm9h8z3k2e72q4k9hcz7v07qwwzcrf",
- valid: false,
- net: &chaincfg.MainNetParams,
- },
- {
- name: "segwit v1 mainnet bech32m non-zero padding in 8-to-5-conversion",
- addr: "tb1p0xlxvlhemja6c4dqv22uapctqupfhlxm9h8z3k2e72q4k9hcz7vpggkg4j",
- valid: false,
- net: &chaincfg.TestNet3Params,
- },
- {
- name: "segwit v1 mainnet bech32m empty data section",
- addr: "bc1gmk9yu",
- valid: false,
- net: &chaincfg.MainNetParams,
- },
-
- // Unsupported witness versions (version 0 and 1 only supported at this point)
- {
- name: "segwit mainnet witness v16",
- addr: "BC1SW50QA3JX3S",
- valid: false,
- net: &chaincfg.MainNetParams,
- },
- {
- name: "segwit mainnet witness v2",
- addr: "bc1zw508d6qejxtdg4y5r3zarvaryvg6kdaj",
- valid: false,
- net: &chaincfg.MainNetParams,
- },
- // Invalid segwit addresses
- {
- name: "segwit invalid hrp",
- addr: "tc1qw508d6qejxtdg4y5r3zarvary0c5xw7kg3g4ty",
- valid: false,
- net: &chaincfg.TestNet3Params,
- },
- {
- name: "segwit invalid checksum",
- addr: "bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t5",
- valid: false,
- net: &chaincfg.MainNetParams,
- },
- {
- name: "segwit invalid witness version",
- addr: "BC13W508D6QEJXTDG4Y5R3ZARVARY0C5XW7KN40WF2",
- valid: false,
- net: &chaincfg.MainNetParams,
- },
- {
- name: "segwit invalid program length",
- addr: "bc1rw5uspcuh",
- valid: false,
- net: &chaincfg.MainNetParams,
- },
- {
- name: "segwit invalid program length",
- addr: "bc10w508d6qejxtdg4y5r3zarvary0c5xw7kw508d6qejxtdg4y5r3zarvary0c5xw7kw5rljs90",
- valid: false,
- net: &chaincfg.MainNetParams,
- },
- {
- name: "segwit invalid program length for witness version 0 (per BIP141)",
- addr: "BC1QR508D6QEJXTDG4Y5R3ZARVARYV98GJ9P",
- valid: false,
- net: &chaincfg.MainNetParams,
- },
- {
- name: "segwit mixed case",
- addr: "tb1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3q0sL5k7",
- valid: false,
- net: &chaincfg.TestNet3Params,
- },
- {
- name: "segwit zero padding of more than 4 bits",
- addr: "tb1pw508d6qejxtdg4y5r3zarqfsj6c3",
- valid: false,
- net: &chaincfg.TestNet3Params,
- },
- {
- name: "segwit non-zero padding in 8-to-5 conversion",
- addr: "tb1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3pjxtptv",
- valid: false,
- net: &chaincfg.TestNet3Params,
- },
- }
-
- if err := chaincfg.Register(&customParams); err != nil {
- panic(err)
- }
-
- for _, test := range tests {
- // Decode addr and compare error against valid.
- decoded, err := btcutil.DecodeAddress(test.addr, test.net)
- if (err == nil) != test.valid {
- t.Errorf("%v: decoding test failed: %v", test.name, err)
- return
- }
-
- if err == nil {
- // Ensure the stringer returns the same address as the
- // original.
- if decodedStringer, ok := decoded.(fmt.Stringer); ok {
- addr := test.addr
-
- // For Segwit addresses the string representation
- // will always be lower case, so in that case we
- // convert the original to lower case first.
- if strings.Contains(test.name, "segwit") {
- addr = strings.ToLower(addr)
- }
-
- if addr != decodedStringer.String() {
- t.Errorf("%v: String on decoded value does not match expected value: %v != %v",
- test.name, test.addr, decodedStringer.String())
- return
- }
- }
-
- // Encode again and compare against the original.
- encoded := decoded.EncodeAddress()
- if test.encoded != encoded {
- t.Errorf("%v: decoding and encoding produced different addresses: %v != %v",
- test.name, test.encoded, encoded)
- return
- }
-
- // Perform type-specific calculations.
- var saddr []byte
- switch d := decoded.(type) {
- case *btcutil.AddressPubKeyHash:
- saddr = btcutil.TstAddressSAddr(encoded)
-
- case *btcutil.AddressScriptHash:
- saddr = btcutil.TstAddressSAddr(encoded)
-
- case *btcutil.AddressPubKey:
- // Ignore the error here since the script
- // address is checked below.
- saddr, _ = hex.DecodeString(d.String())
- case *btcutil.AddressWitnessPubKeyHash:
- saddr = btcutil.TstAddressSegwitSAddr(encoded)
- case *btcutil.AddressWitnessScriptHash:
- saddr = btcutil.TstAddressSegwitSAddr(encoded)
- case *btcutil.AddressTaproot:
- saddr = btcutil.TstAddressTaprootSAddr(encoded)
- }
-
- // Check script address, as well as the Hash160 method for P2PKH and
- // P2SH addresses.
- if !bytes.Equal(saddr, decoded.ScriptAddress()) {
- t.Errorf("%v: script addresses do not match:\n%x != \n%x",
- test.name, saddr, decoded.ScriptAddress())
- return
- }
- switch a := decoded.(type) {
- case *btcutil.AddressPubKeyHash:
- if h := a.Hash160()[:]; !bytes.Equal(saddr, h) {
- t.Errorf("%v: hashes do not match:\n%x != \n%x",
- test.name, saddr, h)
- return
- }
-
- case *btcutil.AddressScriptHash:
- if h := a.Hash160()[:]; !bytes.Equal(saddr, h) {
- t.Errorf("%v: hashes do not match:\n%x != \n%x",
- test.name, saddr, h)
- return
- }
-
- case *btcutil.AddressWitnessPubKeyHash:
- if hrp := a.Hrp(); test.net.Bech32HRPSegwit != hrp {
- t.Errorf("%v: hrps do not match:\n%x != \n%x",
- test.name, test.net.Bech32HRPSegwit, hrp)
- return
- }
-
- expVer := test.result.(*btcutil.AddressWitnessPubKeyHash).WitnessVersion()
- if v := a.WitnessVersion(); v != expVer {
- t.Errorf("%v: witness versions do not match:\n%x != \n%x",
- test.name, expVer, v)
- return
- }
-
- if p := a.WitnessProgram(); !bytes.Equal(saddr, p) {
- t.Errorf("%v: witness programs do not match:\n%x != \n%x",
- test.name, saddr, p)
- return
- }
-
- case *btcutil.AddressWitnessScriptHash:
- if hrp := a.Hrp(); test.net.Bech32HRPSegwit != hrp {
- t.Errorf("%v: hrps do not match:\n%x != \n%x",
- test.name, test.net.Bech32HRPSegwit, hrp)
- return
- }
-
- expVer := test.result.(*btcutil.AddressWitnessScriptHash).WitnessVersion()
- if v := a.WitnessVersion(); v != expVer {
- t.Errorf("%v: witness versions do not match:\n%x != \n%x",
- test.name, expVer, v)
- return
- }
-
- if p := a.WitnessProgram(); !bytes.Equal(saddr, p) {
- t.Errorf("%v: witness programs do not match:\n%x != \n%x",
- test.name, saddr, p)
- return
- }
- }
-
- // Ensure the address is for the expected network.
- if !decoded.IsForNet(test.net) {
- t.Errorf("%v: calculated network does not match expected",
- test.name)
- return
- }
- } else {
- // If there is an error, make sure we can print it
- // correctly.
- errStr := err.Error()
- if errStr == "" {
- t.Errorf("%v: error was non-nil but message is"+
- "empty: %v", test.name, err)
- }
- }
-
- if !test.valid {
- // If address is invalid, but a creation function exists,
- // verify that it returns a nil addr and non-nil error.
- if test.f != nil {
- _, err := test.f()
- if err == nil {
- t.Errorf("%v: address is invalid but creating new address succeeded",
- test.name)
- return
- }
- }
- continue
- }
-
- // Valid test, compare address created with f against expected result.
- addr, err := test.f()
- if err != nil {
- t.Errorf("%v: address is valid but creating new address failed with error %v",
- test.name, err)
- return
- }
-
- if !reflect.DeepEqual(addr, test.result) {
- t.Errorf("%v: created address does not match expected result",
- test.name)
- return
- }
- }
-}
diff --git a/btcutil/base58/README.md b/btcutil/base58/README.md
deleted file mode 100644
index abdb781..0000000
--- a/btcutil/base58/README.md
+++ /dev/null
@@ -1,34 +0,0 @@
-base58
-==========
-
-[](https://travis-ci.org/btcsuite/btcutil)
-[](http://copyfree.org)
-[](http://godoc.org/github.com/btcsuite/btcd/btcutil/base58)
-
-Package base58 provides an API for encoding and decoding to and from the
-modified base58 encoding. It also provides an API to do Base58Check encoding,
-as described [here](https://en.bitcoin.it/wiki/Base58Check_encoding).
-
-A comprehensive suite of tests is provided to ensure proper functionality.
-
-## Installation and Updating
-
-```bash
-$ go get -u github.com/btcsuite/btcd/btcutil/base58
-```
-
-## Examples
-
-* [Decode Example](http://godoc.org/github.com/btcsuite/btcd/btcutil/base58#example-Decode)
- Demonstrates how to decode modified base58 encoded data.
-* [Encode Example](http://godoc.org/github.com/btcsuite/btcd/btcutil/base58#example-Encode)
- Demonstrates how to encode data using the modified base58 encoding scheme.
-* [CheckDecode Example](http://godoc.org/github.com/btcsuite/btcd/btcutil/base58#example-CheckDecode)
- Demonstrates how to decode Base58Check encoded data.
-* [CheckEncode Example](http://godoc.org/github.com/btcsuite/btcd/btcutil/base58#example-CheckEncode)
- Demonstrates how to encode data using the Base58Check encoding scheme.
-
-## License
-
-Package base58 is licensed under the [copyfree](http://copyfree.org) ISC
-License.
diff --git a/btcutil/base58/alphabet.go b/btcutil/base58/alphabet.go
deleted file mode 100644
index 6bb39fe..0000000
--- a/btcutil/base58/alphabet.go
+++ /dev/null
@@ -1,49 +0,0 @@
-// Copyright (c) 2015 The btcsuite developers
-// Use of this source code is governed by an ISC
-// license that can be found in the LICENSE file.
-
-// AUTOGENERATED by genalphabet.go; do not edit.
-
-package base58
-
-const (
- // alphabet is the modified base58 alphabet used by Bitcoin.
- alphabet = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"
-
- alphabetIdx0 = '1'
-)
-
-var b58 = [256]byte{
- 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 0, 1, 2, 3, 4, 5, 6,
- 7, 8, 255, 255, 255, 255, 255, 255,
- 255, 9, 10, 11, 12, 13, 14, 15,
- 16, 255, 17, 18, 19, 20, 21, 255,
- 22, 23, 24, 25, 26, 27, 28, 29,
- 30, 31, 32, 255, 255, 255, 255, 255,
- 255, 33, 34, 35, 36, 37, 38, 39,
- 40, 41, 42, 43, 255, 44, 45, 46,
- 47, 48, 49, 50, 51, 52, 53, 54,
- 55, 56, 57, 255, 255, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 255,
-}
diff --git a/btcutil/base58/base58.go b/btcutil/base58/base58.go
deleted file mode 100644
index bd0ea47..0000000
--- a/btcutil/base58/base58.go
+++ /dev/null
@@ -1,142 +0,0 @@
-// Copyright (c) 2013-2015 The btcsuite developers
-// Use of this source code is governed by an ISC
-// license that can be found in the LICENSE file.
-
-package base58
-
-import (
- "math/big"
-)
-
-//go:generate go run genalphabet.go
-
-var bigRadix = [...]*big.Int{
- big.NewInt(0),
- big.NewInt(58),
- big.NewInt(58 * 58),
- big.NewInt(58 * 58 * 58),
- big.NewInt(58 * 58 * 58 * 58),
- big.NewInt(58 * 58 * 58 * 58 * 58),
- big.NewInt(58 * 58 * 58 * 58 * 58 * 58),
- big.NewInt(58 * 58 * 58 * 58 * 58 * 58 * 58),
- big.NewInt(58 * 58 * 58 * 58 * 58 * 58 * 58 * 58),
- big.NewInt(58 * 58 * 58 * 58 * 58 * 58 * 58 * 58 * 58),
- bigRadix10,
-}
-
-var bigRadix10 = big.NewInt(58 * 58 * 58 * 58 * 58 * 58 * 58 * 58 * 58 * 58) // 58^10
-
-// Decode decodes a modified base58 string to a byte slice.
-func Decode(b string) []byte {
- answer := big.NewInt(0)
- scratch := new(big.Int)
-
- // Calculating with big.Int is slow for each iteration.
- // x += b58[b[i]] * j
- // j *= 58
- //
- // Instead we can try to do as much calculations on int64.
- // We can represent a 10 digit base58 number using an int64.
- //
- // Hence we'll try to convert 10, base58 digits at a time.
- // The rough idea is to calculate `t`, such that:
- //
- // t := b58[b[i+9]] * 58^9 ... + b58[b[i+1]] * 58^1 + b58[b[i]] * 58^0
- // x *= 58^10
- // x += t
- //
- // Of course, in addition, we'll need to handle boundary condition when `b` is not multiple of 58^10.
- // In that case we'll use the bigRadix[n] lookup for the appropriate power.
- for t := b; len(t) > 0; {
- n := len(t)
- if n > 10 {
- n = 10
- }
-
- total := uint64(0)
- for _, v := range t[:n] {
- if v > 255 {
- return []byte("")
- }
-
- tmp := b58[v]
- if tmp == 255 {
- return []byte("")
- }
- total = total*58 + uint64(tmp)
- }
-
- answer.Mul(answer, bigRadix[n])
- scratch.SetUint64(total)
- answer.Add(answer, scratch)
-
- t = t[n:]
- }
-
- tmpval := answer.Bytes()
-
- var numZeros int
- for numZeros = 0; numZeros < len(b); numZeros++ {
- if b[numZeros] != alphabetIdx0 {
- break
- }
- }
- flen := numZeros + len(tmpval)
- val := make([]byte, flen)
- copy(val[numZeros:], tmpval)
-
- return val
-}
-
-// Encode encodes a byte slice to a modified base58 string.
-func Encode(b []byte) string {
- x := new(big.Int)
- x.SetBytes(b)
-
- // maximum length of output is log58(2^(8*len(b))) == len(b) * 8 / log(58)
- maxlen := int(float64(len(b))*1.365658237309761) + 1
- answer := make([]byte, 0, maxlen)
- mod := new(big.Int)
- for x.Sign() > 0 {
- // Calculating with big.Int is slow for each iteration.
- // x, mod = x / 58, x % 58
- //
- // Instead we can try to do as much calculations on int64.
- // x, mod = x / 58^10, x % 58^10
- //
- // Which will give us mod, which is 10 digit base58 number.
- // We'll loop that 10 times to convert to the answer.
-
- x.DivMod(x, bigRadix10, mod)
- if x.Sign() == 0 {
- // When x = 0, we need to ensure we don't add any extra zeros.
- m := mod.Int64()
- for m > 0 {
- answer = append(answer, alphabet[m%58])
- m /= 58
- }
- } else {
- m := mod.Int64()
- for i := 0; i < 10; i++ {
- answer = append(answer, alphabet[m%58])
- m /= 58
- }
- }
- }
-
- // leading zero bytes
- for _, i := range b {
- if i != 0 {
- break
- }
- answer = append(answer, alphabetIdx0)
- }
-
- // reverse
- alen := len(answer)
- for i := 0; i < alen/2; i++ {
- answer[i], answer[alen-1-i] = answer[alen-1-i], answer[i]
- }
-
- return string(answer)
-}
diff --git a/btcutil/base58/base58_test.go b/btcutil/base58/base58_test.go
deleted file mode 100644
index eb7e4d4..0000000
--- a/btcutil/base58/base58_test.go
+++ /dev/null
@@ -1,103 +0,0 @@
-// Copyright (c) 2013-2017 The btcsuite developers
-// Use of this source code is governed by an ISC
-// license that can be found in the LICENSE file.
-
-package base58_test
-
-import (
- "bytes"
- "encoding/hex"
- "testing"
-
- "github.com/btcsuite/btcd/btcutil/base58"
-)
-
-var stringTests = []struct {
- in string
- out string
-}{
- {"", ""},
- {" ", "Z"},
- {"-", "n"},
- {"0", "q"},
- {"1", "r"},
- {"-1", "4SU"},
- {"11", "4k8"},
- {"abc", "ZiCa"},
- {"1234598760", "3mJr7AoUXx2Wqd"},
- {"abcdefghijklmnopqrstuvwxyz", "3yxU3u1igY8WkgtjK92fbJQCd4BZiiT1v25f"},
- {"00000000000000000000000000000000000000000000000000000000000000", "3sN2THZeE9Eh9eYrwkvZqNstbHGvrxSAM7gXUXvyFQP8XvQLUqNCS27icwUeDT7ckHm4FUHM2mTVh1vbLmk7y"},
-}
-
-var invalidStringTests = []struct {
- in string
- out string
-}{
- {"0", ""},
- {"O", ""},
- {"I", ""},
- {"l", ""},
- {"3mJr0", ""},
- {"O3yxU", ""},
- {"3sNI", ""},
- {"4kl8", ""},
- {"0OIl", ""},
- {"!@#$%^&*()-_=+~`", ""},
- {"abcd\xd80", ""},
- {"abcd\U000020BF", ""},
-}
-
-var hexTests = []struct {
- in string
- out string
-}{
- {"", ""},
- {"61", "2g"},
- {"626262", "a3gV"},
- {"636363", "aPEr"},
- {"73696d706c792061206c6f6e6720737472696e67", "2cFupjhnEsSn59qHXstmK2ffpLv2"},
- {"00eb15231dfceb60925886b67d065299925915aeb172c06647", "1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L"},
- {"516b6fcd0f", "ABnLTmg"},
- {"bf4f89001e670274dd", "3SEo3LWLoPntC"},
- {"572e4794", "3EFU7m"},
- {"ecac89cad93923c02321", "EJDM8drfXA6uyA"},
- {"10c8511e", "Rt5zm"},
- {"00000000000000000000", "1111111111"},
- {"000111d38e5fc9071ffcd20b4a763cc9ae4f252bb4e48fd66a835e252ada93ff480d6dd43dc62a641155a5", "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"},
- {"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", "1cWB5HCBdLjAuqGGReWE3R3CguuwSjw6RHn39s2yuDRTS5NsBgNiFpWgAnEx6VQi8csexkgYw3mdYrMHr8x9i7aEwP8kZ7vccXWqKDvGv3u1GxFKPuAkn8JCPPGDMf3vMMnbzm6Nh9zh1gcNsMvH3ZNLmP5fSG6DGbbi2tuwMWPthr4boWwCxf7ewSgNQeacyozhKDDQQ1qL5fQFUW52QKUZDZ5fw3KXNQJMcNTcaB723LchjeKun7MuGW5qyCBZYzA1KjofN1gYBV3NqyhQJ3Ns746GNuf9N2pQPmHz4xpnSrrfCvy6TVVz5d4PdrjeshsWQwpZsZGzvbdAdN8MKV5QsBDY"},
-}
-
-func TestBase58(t *testing.T) {
- // Encode tests
- for x, test := range stringTests {
- tmp := []byte(test.in)
- if res := base58.Encode(tmp); res != test.out {
- t.Errorf("Encode test #%d failed: got: %s want: %s",
- x, res, test.out)
- continue
- }
- }
-
- // Decode tests
- for x, test := range hexTests {
- b, err := hex.DecodeString(test.in)
- if err != nil {
- t.Errorf("hex.DecodeString failed failed #%d: got: %s", x, test.in)
- continue
- }
- if res := base58.Decode(test.out); !bytes.Equal(res, b) {
- t.Errorf("Decode test #%d failed: got: %q want: %q",
- x, res, test.in)
- continue
- }
- }
-
- // Decode with invalid input
- for x, test := range invalidStringTests {
- if res := base58.Decode(test.in); string(res) != test.out {
- t.Errorf("Decode invalidString test #%d failed: got: %q want: %q",
- x, res, test.out)
- continue
- }
- }
-}
diff --git a/btcutil/base58/base58bench_test.go b/btcutil/base58/base58bench_test.go
deleted file mode 100644
index c7286e5..0000000
--- a/btcutil/base58/base58bench_test.go
+++ /dev/null
@@ -1,47 +0,0 @@
-// Copyright (c) 2013-2014 The btcsuite developers
-// Use of this source code is governed by an ISC
-// license that can be found in the LICENSE file.
-
-package base58_test
-
-import (
- "bytes"
- "testing"
-
- "github.com/btcsuite/btcd/btcutil/base58"
-)
-
-var (
- raw5k = bytes.Repeat([]byte{0xff}, 5000)
- raw100k = bytes.Repeat([]byte{0xff}, 100*1000)
- encoded5k = base58.Encode(raw5k)
- encoded100k = base58.Encode(raw100k)
-)
-
-func BenchmarkBase58Encode_5K(b *testing.B) {
- b.SetBytes(int64(len(raw5k)))
- for i := 0; i < b.N; i++ {
- base58.Encode(raw5k)
- }
-}
-
-func BenchmarkBase58Encode_100K(b *testing.B) {
- b.SetBytes(int64(len(raw100k)))
- for i := 0; i < b.N; i++ {
- base58.Encode(raw100k)
- }
-}
-
-func BenchmarkBase58Decode_5K(b *testing.B) {
- b.SetBytes(int64(len(encoded5k)))
- for i := 0; i < b.N; i++ {
- base58.Decode(encoded5k)
- }
-}
-
-func BenchmarkBase58Decode_100K(b *testing.B) {
- b.SetBytes(int64(len(encoded100k)))
- for i := 0; i < b.N; i++ {
- base58.Decode(encoded100k)
- }
-}
diff --git a/btcutil/base58/base58check.go b/btcutil/base58/base58check.go
deleted file mode 100644
index 402c323..0000000
--- a/btcutil/base58/base58check.go
+++ /dev/null
@@ -1,52 +0,0 @@
-// Copyright (c) 2013-2014 The btcsuite developers
-// Use of this source code is governed by an ISC
-// license that can be found in the LICENSE file.
-
-package base58
-
-import (
- "crypto/sha256"
- "errors"
-)
-
-// ErrChecksum indicates that the checksum of a check-encoded string does not verify against
-// the checksum.
-var ErrChecksum = errors.New("checksum error")
-
-// ErrInvalidFormat indicates that the check-encoded string has an invalid format.
-var ErrInvalidFormat = errors.New("invalid format: version and/or checksum bytes missing")
-
-// checksum: first four bytes of sha256^2
-func checksum(input []byte) (cksum [4]byte) {
- h := sha256.Sum256(input)
- h2 := sha256.Sum256(h[:])
- copy(cksum[:], h2[:4])
- return
-}
-
-// CheckEncode prepends a version byte and appends a four byte checksum.
-func CheckEncode(input []byte, version byte) string {
- b := make([]byte, 0, 1+len(input)+4)
- b = append(b, version)
- b = append(b, input...)
- cksum := checksum(b)
- b = append(b, cksum[:]...)
- return Encode(b)
-}
-
-// CheckDecode decodes a string that was encoded with CheckEncode and verifies the checksum.
-func CheckDecode(input string) (result []byte, version byte, err error) {
- decoded := Decode(input)
- if len(decoded) < 5 {
- return nil, 0, ErrInvalidFormat
- }
- version = decoded[0]
- var cksum [4]byte
- copy(cksum[:], decoded[len(decoded)-4:])
- if checksum(decoded[:len(decoded)-4]) != cksum {
- return nil, 0, ErrChecksum
- }
- payload := decoded[1 : len(decoded)-4]
- result = append(result, payload...)
- return
-}
diff --git a/btcutil/base58/base58check_test.go b/btcutil/base58/base58check_test.go
deleted file mode 100644
index e180b16..0000000
--- a/btcutil/base58/base58check_test.go
+++ /dev/null
@@ -1,69 +0,0 @@
-// Copyright (c) 2013-2014 The btcsuite developers
-// Use of this source code is governed by an ISC
-// license that can be found in the LICENSE file.
-
-package base58_test
-
-import (
- "testing"
-
- "github.com/btcsuite/btcd/btcutil/base58"
-)
-
-var checkEncodingStringTests = []struct {
- version byte
- in string
- out string
-}{
- {20, "", "3MNQE1X"},
- {20, " ", "B2Kr6dBE"},
- {20, "-", "B3jv1Aft"},
- {20, "0", "B482yuaX"},
- {20, "1", "B4CmeGAC"},
- {20, "-1", "mM7eUf6kB"},
- {20, "11", "mP7BMTDVH"},
- {20, "abc", "4QiVtDjUdeq"},
- {20, "1234598760", "ZmNb8uQn5zvnUohNCEPP"},
- {20, "abcdefghijklmnopqrstuvwxyz", "K2RYDcKfupxwXdWhSAxQPCeiULntKm63UXyx5MvEH2"},
- {20, "00000000000000000000000000000000000000000000000000000000000000", "bi1EWXwJay2udZVxLJozuTb8Meg4W9c6xnmJaRDjg6pri5MBAxb9XwrpQXbtnqEoRV5U2pixnFfwyXC8tRAVC8XxnjK"},
-}
-
-func TestBase58Check(t *testing.T) {
- for x, test := range checkEncodingStringTests {
- // test encoding
- if res := base58.CheckEncode([]byte(test.in), test.version); res != test.out {
- t.Errorf("CheckEncode test #%d failed: got %s, want: %s", x, res, test.out)
- }
-
- // test decoding
- res, version, err := base58.CheckDecode(test.out)
- switch {
- case err != nil:
- t.Errorf("CheckDecode test #%d failed with err: %v", x, err)
-
- case version != test.version:
- t.Errorf("CheckDecode test #%d failed: got version: %d want: %d", x, version, test.version)
-
- case string(res) != test.in:
- t.Errorf("CheckDecode test #%d failed: got: %s want: %s", x, res, test.in)
- }
- }
-
- // test the two decoding failure cases
- // case 1: checksum error
- _, _, err := base58.CheckDecode("3MNQE1Y")
- if err != base58.ErrChecksum {
- t.Error("Checkdecode test failed, expected ErrChecksum")
- }
- // case 2: invalid formats (string lengths below 5 mean the version byte and/or the checksum
- // bytes are missing).
- testString := ""
- for len := 0; len < 4; len++ {
- testString += "x"
- _, _, err = base58.CheckDecode(testString)
- if err != base58.ErrInvalidFormat {
- t.Error("Checkdecode test failed, expected ErrInvalidFormat")
- }
- }
-
-}
diff --git a/btcutil/base58/cov_report.sh b/btcutil/base58/cov_report.sh
deleted file mode 100644
index e41c928..0000000
--- a/btcutil/base58/cov_report.sh
+++ /dev/null
@@ -1,9 +0,0 @@
-#!/bin/sh
-
-# This script uses the standard Go test coverage tools to generate a test coverage report.
-
-# Run tests with coverage enabled and generate coverage profile.
-go test -cover -coverprofile=coverage.txt ./...
-
-# Display function-level coverage statistics.
-go tool cover -func=coverage.txt
diff --git a/btcutil/base58/doc.go b/btcutil/base58/doc.go
deleted file mode 100644
index d657f05..0000000
--- a/btcutil/base58/doc.go
+++ /dev/null
@@ -1,29 +0,0 @@
-// Copyright (c) 2014 The btcsuite developers
-// Use of this source code is governed by an ISC
-// license that can be found in the LICENSE file.
-
-/*
-Package base58 provides an API for working with modified base58 and Base58Check
-encodings.
-
-# Modified Base58 Encoding
-
-Standard base58 encoding is similar to standard base64 encoding except, as the
-name implies, it uses a 58 character alphabet which results in an alphanumeric
-string and allows some characters which are problematic for humans to be
-excluded. Due to this, there can be various base58 alphabets.
-
-The modified base58 alphabet used by Bitcoin, and hence this package, omits the
-0, O, I, and l characters that look the same in many fonts and are therefore
-hard to humans to distinguish.
-
-# Base58Check Encoding Scheme
-
-The Base58Check encoding scheme is primarily used for Bitcoin addresses at the
-time of this writing, however it can be used to generically encode arbitrary
-byte arrays into human-readable strings along with a version byte that can be
-used to differentiate the same payload. For Bitcoin addresses, the extra
-version is used to differentiate the network of otherwise identical public keys
-which helps prevent using an address intended for one network on another.
-*/
-package base58
diff --git a/btcutil/base58/example_test.go b/btcutil/base58/example_test.go
deleted file mode 100644
index babb35d..0000000
--- a/btcutil/base58/example_test.go
+++ /dev/null
@@ -1,71 +0,0 @@
-// Copyright (c) 2014 The btcsuite developers
-// Use of this source code is governed by an ISC
-// license that can be found in the LICENSE file.
-
-package base58_test
-
-import (
- "fmt"
-
- "github.com/btcsuite/btcd/btcutil/base58"
-)
-
-// This example demonstrates how to decode modified base58 encoded data.
-func ExampleDecode() {
- // Decode example modified base58 encoded data.
- encoded := "25JnwSn7XKfNQ"
- decoded := base58.Decode(encoded)
-
- // Show the decoded data.
- fmt.Println("Decoded Data:", string(decoded))
-
- // Output:
- // Decoded Data: Test data
-}
-
-// This example demonstrates how to encode data using the modified base58
-// encoding scheme.
-func ExampleEncode() {
- // Encode example data with the modified base58 encoding scheme.
- data := []byte("Test data")
- encoded := base58.Encode(data)
-
- // Show the encoded data.
- fmt.Println("Encoded Data:", encoded)
-
- // Output:
- // Encoded Data: 25JnwSn7XKfNQ
-}
-
-// This example demonstrates how to decode Base58Check encoded data.
-func ExampleCheckDecode() {
- // Decode an example Base58Check encoded data.
- encoded := "1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa"
- decoded, version, err := base58.CheckDecode(encoded)
- if err != nil {
- fmt.Println(err)
- return
- }
-
- // Show the decoded data.
- fmt.Printf("Decoded data: %x\n", decoded)
- fmt.Println("Version Byte:", version)
-
- // Output:
- // Decoded data: 62e907b15cbf27d5425399ebf6f0fb50ebb88f18
- // Version Byte: 0
-}
-
-// This example demonstrates how to encode data using the Base58Check encoding
-// scheme.
-func ExampleCheckEncode() {
- // Encode example data with the Base58Check encoding scheme.
- data := []byte("Test data")
- encoded := base58.CheckEncode(data, 0)
-
- // Show the encoded data.
- fmt.Println("Encoded Data:", encoded)
-
- // Output:
- // Encoded Data: 182iP79GRURMp7oMHDU
-}
diff --git a/btcutil/base58/genalphabet.go b/btcutil/base58/genalphabet.go
deleted file mode 100644
index 959f34d..0000000
--- a/btcutil/base58/genalphabet.go
+++ /dev/null
@@ -1,80 +0,0 @@
-// Copyright (c) 2015 The btcsuite developers
-// Use of this source code is governed by an ISC
-// license that can be found in the LICENSE file.
-
-//go:build ignore
-// +build ignore
-
-package main
-
-import (
- "bytes"
- "io"
- "log"
- "os"
- "strconv"
-)
-
-var (
- start = []byte(`// Copyright (c) 2015 The btcsuite developers
-// Use of this source code is governed by an ISC
-// license that can be found in the LICENSE file.
-
-// AUTOGENERATED by genalphabet.go; do not edit.
-
-package base58
-
-const (
- // alphabet is the modified base58 alphabet used by Bitcoin.
- alphabet = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"
-
- alphabetIdx0 = '1'
-)
-
-var b58 = [256]byte{`)
-
- end = []byte(`}`)
-
- alphabet = []byte("123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz")
- tab = []byte("\t")
- invalid = []byte("255")
- comma = []byte(",")
- space = []byte(" ")
- nl = []byte("\n")
-)
-
-func write(w io.Writer, b []byte) {
- _, err := w.Write(b)
- if err != nil {
- log.Fatal(err)
- }
-}
-
-func main() {
- fi, err := os.Create("alphabet.go")
- if err != nil {
- log.Fatal(err)
- }
- defer fi.Close()
-
- write(fi, start)
- write(fi, nl)
- for i := byte(0); i < 32; i++ {
- write(fi, tab)
- for j := byte(0); j < 8; j++ {
- idx := bytes.IndexByte(alphabet, i*8+j)
- if idx == -1 {
- write(fi, invalid)
- } else {
- write(fi, strconv.AppendInt(nil, int64(idx), 10))
- }
- write(fi, comma)
- if j != 7 {
- write(fi, space)
- }
- }
- write(fi, nl)
- }
- write(fi, end)
- write(fi, nl)
-}
diff --git a/btcutil/bech32/README.md b/btcutil/bech32/README.md
deleted file mode 100644
index 471cd50..0000000
--- a/btcutil/bech32/README.md
+++ /dev/null
@@ -1,29 +0,0 @@
-bech32
-==========
-
-[](https://travis-ci.org/btcsuite/btcutil)
-[](http://copyfree.org)
-[](http://godoc.org/github.com/btcsuite/btcd/btcutil/bech32)
-
-Package bech32 provides a Go implementation of the bech32 format specified in
-[BIP 173](https://github.com/bitcoin/bips/blob/master/bip-0173.mediawiki).
-
-Test vectors from BIP 173 are added to ensure compatibility with the BIP.
-
-## Installation and Updating
-
-```bash
-$ go get -u github.com/btcsuite/btcd/btcutil/bech32
-```
-
-## Examples
-
-* [Bech32 decode Example](http://godoc.org/github.com/btcsuite/btcd/btcutil/bech32#example-Bech32Decode)
- Demonstrates how to decode a bech32 encoded string.
-* [Bech32 encode Example](http://godoc.org/github.com/btcsuite/btcd/btcutil/bech32#example-BechEncode)
- Demonstrates how to encode data into a bech32 string.
-
-## License
-
-Package bech32 is licensed under the [copyfree](http://copyfree.org) ISC
-License.
diff --git a/btcutil/bech32/bech32.go b/btcutil/bech32/bech32.go
deleted file mode 100644
index 92994b2..0000000
--- a/btcutil/bech32/bech32.go
+++ /dev/null
@@ -1,445 +0,0 @@
-// Copyright (c) 2017 The btcsuite developers
-// Copyright (c) 2019 The Decred developers
-// Use of this source code is governed by an ISC
-// license that can be found in the LICENSE file.
-
-package bech32
-
-import (
- "strings"
-)
-
-// charset is the set of characters used in the data section of bech32 strings.
-// Note that this is ordered, such that for a given charset[i], i is the binary
-// value of the character.
-const charset = "qpzry9x8gf2tvdw0s3jn54khce6mua7l"
-
-// gen encodes the generator polynomial for the bech32 BCH checksum.
-var gen = []int{0x3b6a57b2, 0x26508e6d, 0x1ea119fa, 0x3d4233dd, 0x2a1462b3}
-
-// toBytes converts each character in the string 'chars' to the value of the
-// index of the corresponding character in 'charset'.
-func toBytes(chars string) ([]byte, error) {
- decoded := make([]byte, 0, len(chars))
- for i := 0; i < len(chars); i++ {
- index := strings.IndexByte(charset, chars[i])
- if index < 0 {
- return nil, ErrNonCharsetChar(chars[i])
- }
- decoded = append(decoded, byte(index))
- }
- return decoded, nil
-}
-
-// bech32Polymod calculates the BCH checksum for a given hrp, values and
-// checksum data. Checksum is optional, and if nil a 0 checksum is assumed.
-//
-// Values and checksum (if provided) MUST be encoded as 5 bits per element (base
-// 32), otherwise the results are undefined.
-//
-// For more details on the polymod calculation, please refer to BIP 173.
-func bech32Polymod(hrp string, values, checksum []byte) int {
- chk := 1
-
- // Account for the high bits of the HRP in the checksum.
- for i := 0; i < len(hrp); i++ {
- b := chk >> 25
- hiBits := int(hrp[i]) >> 5
- chk = (chk&0x1ffffff)<<5 ^ hiBits
- for i := 0; i < 5; i++ {
- if (b>>uint(i))&1 == 1 {
- chk ^= gen[i]
- }
- }
- }
-
- // Account for the separator (0) between high and low bits of the HRP.
- // x^0 == x, so we eliminate the redundant xor used in the other rounds.
- b := chk >> 25
- chk = (chk & 0x1ffffff) << 5
- for i := 0; i < 5; i++ {
- if (b>>uint(i))&1 == 1 {
- chk ^= gen[i]
- }
- }
-
- // Account for the low bits of the HRP.
- for i := 0; i < len(hrp); i++ {
- b := chk >> 25
- loBits := int(hrp[i]) & 31
- chk = (chk&0x1ffffff)<<5 ^ loBits
- for i := 0; i < 5; i++ {
- if (b>>uint(i))&1 == 1 {
- chk ^= gen[i]
- }
- }
- }
-
- // Account for the values.
- for _, v := range values {
- b := chk >> 25
- chk = (chk&0x1ffffff)<<5 ^ int(v)
- for i := 0; i < 5; i++ {
- if (b>>uint(i))&1 == 1 {
- chk ^= gen[i]
- }
- }
- }
-
- if checksum == nil {
- // A nil checksum is used during encoding, so assume all bytes are zero.
- // x^0 == x, so we eliminate the redundant xor used in the other rounds.
- for v := 0; v < 6; v++ {
- b := chk >> 25
- chk = (chk & 0x1ffffff) << 5
- for i := 0; i < 5; i++ {
- if (b>>uint(i))&1 == 1 {
- chk ^= gen[i]
- }
- }
- }
- } else {
- // Checksum is provided during decoding, so use it.
- for _, v := range checksum {
- b := chk >> 25
- chk = (chk&0x1ffffff)<<5 ^ int(v)
- for i := 0; i < 5; i++ {
- if (b>>uint(i))&1 == 1 {
- chk ^= gen[i]
- }
- }
- }
- }
-
- return chk
-}
-
-// writeBech32Checksum calculates the checksum data expected for a string that
-// will have the given hrp and payload data and writes it to the provided string
-// builder.
-//
-// The payload data MUST be encoded as a base 32 (5 bits per element) byte slice
-// and the hrp MUST only use the allowed character set (ascii chars between 33
-// and 126), otherwise the results are undefined.
-//
-// For more details on the checksum calculation, please refer to BIP 173.
-func writeBech32Checksum(hrp string, data []byte, bldr *strings.Builder,
- version Version) {
-
- bech32Const := int(VersionToConsts[version])
- polymod := bech32Polymod(hrp, data, nil) ^ bech32Const
- for i := 0; i < 6; i++ {
- b := byte((polymod >> uint(5*(5-i))) & 31)
-
- // This can't fail, given we explicitly cap the previous b byte by the
- // first 31 bits.
- c := charset[b]
- bldr.WriteByte(c)
- }
-}
-
-// bech32VerifyChecksum verifies whether the bech32 string specified by the
-// provided hrp and payload data (encoded as 5 bits per element byte slice) has
-// the correct checksum suffix. The version of bech32 used (bech32 OG, or
-// bech32m) is also returned to allow the caller to perform proper address
-// validation (segwitv0 should use bech32, v1+ should use bech32m).
-//
-// Data MUST have more than 6 elements, otherwise this function panics.
-//
-// For more details on the checksum verification, please refer to BIP 173.
-func bech32VerifyChecksum(hrp string, data []byte) (Version, bool) {
- checksum := data[len(data)-6:]
- values := data[:len(data)-6]
- polymod := bech32Polymod(hrp, values, checksum)
-
- // Before BIP-350, we'd always check this against a static constant of
- // 1 to know if the checksum was computed properly. As we want to
- // generically support decoding for bech32m as well as bech32, we'll
- // look up the returned value and compare it to the set of defined
- // constants.
- bech32Version, ok := ConstsToVersion[ChecksumConst(polymod)]
- if ok {
- return bech32Version, true
- }
-
- return VersionUnknown, false
-}
-
-// DecodeNoLimitWithVersion is a bech32 checksum version aware arbitrary string
-// length decoder. This function will return the version of the decoded
-// checksum constant so higher level validation can be performed to ensure the
-// correct version of bech32 was used when encoding.
-//
-// Note that the returned data is 5-bit (base32) encoded and the human-readable
-// part will be lowercase.
-func DecodeNoLimitWithVersion(bech string) (string, []byte, Version, error) {
- // The minimum allowed size of a bech32 string is 8 characters, since it
- // needs a non-empty HRP, a separator, and a 6 character checksum.
- if len(bech) < 8 {
- return "", nil, VersionUnknown, ErrInvalidLength(len(bech))
- }
-
- // Only ASCII characters between 33 and 126 are allowed.
- var hasLower, hasUpper bool
- for i := 0; i < len(bech); i++ {
- if bech[i] < 33 || bech[i] > 126 {
- return "", nil, VersionUnknown, ErrInvalidCharacter(bech[i])
- }
-
- // The characters must be either all lowercase or all uppercase. Testing
- // directly with ascii codes is safe here, given the previous test.
- hasLower = hasLower || (bech[i] >= 97 && bech[i] <= 122)
- hasUpper = hasUpper || (bech[i] >= 65 && bech[i] <= 90)
- if hasLower && hasUpper {
- return "", nil, VersionUnknown, ErrMixedCase{}
- }
- }
-
- // Bech32 standard uses only the lowercase for of strings for checksum
- // calculation.
- if hasUpper {
- bech = strings.ToLower(bech)
- }
-
- // The string is invalid if the last '1' is non-existent, it is the
- // first character of the string (no human-readable part) or one of the
- // last 6 characters of the string (since checksum cannot contain '1').
- one := strings.LastIndexByte(bech, '1')
- if one < 1 || one+7 > len(bech) {
- return "", nil, VersionUnknown, ErrInvalidSeparatorIndex(one)
- }
-
- // The human-readable part is everything before the last '1'.
- hrp := bech[:one]
- data := bech[one+1:]
-
- // Each character corresponds to the byte with value of the index in
- // 'charset'.
- decoded, err := toBytes(data)
- if err != nil {
- return "", nil, VersionUnknown, err
- }
-
- // Verify if the checksum (stored inside decoded[:]) is valid, given the
- // previously decoded hrp.
- bech32Version, ok := bech32VerifyChecksum(hrp, decoded)
- if !ok {
- // Invalid checksum. Calculate what it should have been, so that the
- // error contains this information.
-
- // Extract the payload bytes and actual checksum in the string.
- actual := bech[len(bech)-6:]
- payload := decoded[:len(decoded)-6]
-
- // Calculate the expected checksum, given the hrp and payload
- // data. We'll actually compute _both_ possibly valid checksum
- // to further aide in debugging.
- var expectedBldr strings.Builder
- expectedBldr.Grow(6)
- writeBech32Checksum(hrp, payload, &expectedBldr, Version0)
- expectedVersion0 := expectedBldr.String()
-
- var b strings.Builder
- b.Grow(6)
- writeBech32Checksum(hrp, payload, &expectedBldr, VersionM)
- expectedVersionM := expectedBldr.String()
-
- err = ErrInvalidChecksum{
- Expected: expectedVersion0,
- ExpectedM: expectedVersionM,
- Actual: actual,
- }
- return "", nil, VersionUnknown, err
- }
-
- // We exclude the last 6 bytes, which is the checksum.
- return hrp, decoded[:len(decoded)-6], bech32Version, nil
-}
-
-// DecodeNoLimit decodes a bech32 encoded string, returning the human-readable
-// part and the data part excluding the checksum. This function does NOT
-// validate against the BIP-173 maximum length allowed for bech32 strings and
-// is meant for use in custom applications (such as lightning network payment
-// requests), NOT on-chain addresses.
-//
-// Note that the returned data is 5-bit (base32) encoded and the human-readable
-// part will be lowercase.
-func DecodeNoLimit(bech string) (string, []byte, error) {
- hrp, data, _, err := DecodeNoLimitWithVersion(bech)
- return hrp, data, err
-}
-
-// Decode decodes a bech32 encoded string, returning the human-readable part and
-// the data part excluding the checksum.
-//
-// Note that the returned data is 5-bit (base32) encoded and the human-readable
-// part will be lowercase.
-func Decode(bech string) (string, []byte, error) {
- // The maximum allowed length for a bech32 string is 90.
- if len(bech) > 90 {
- return "", nil, ErrInvalidLength(len(bech))
- }
-
- hrp, data, _, err := DecodeNoLimitWithVersion(bech)
- return hrp, data, err
-}
-
-// DecodeGeneric is identical to the existing Decode method, but will also
-// return bech32 version that matches the decoded checksum. This method should
-// be used when decoding segwit addresses, as it enables additional
-// verification to ensure the proper checksum is used.
-func DecodeGeneric(bech string) (string, []byte, Version, error) {
- // The maximum allowed length for a bech32 string is 90.
- if len(bech) > 90 {
- return "", nil, VersionUnknown, ErrInvalidLength(len(bech))
- }
-
- return DecodeNoLimitWithVersion(bech)
-}
-
-// encodeGeneric is the base bech32 encoding function that is aware of the
-// existence of the checksum versions. This method is private, as the Encode
-// and EncodeM methods are intended to be used instead.
-func encodeGeneric(hrp string, data []byte,
- version Version) (string, error) {
-
- // The resulting bech32 string is the concatenation of the lowercase
- // hrp, the separator 1, data and the 6-byte checksum.
- hrp = strings.ToLower(hrp)
- var bldr strings.Builder
- bldr.Grow(len(hrp) + 1 + len(data) + 6)
- bldr.WriteString(hrp)
- bldr.WriteString("1")
-
- // Write the data part, using the bech32 charset.
- for _, b := range data {
- if int(b) >= len(charset) {
- return "", ErrInvalidDataByte(b)
- }
- bldr.WriteByte(charset[b])
- }
-
- // Calculate and write the checksum of the data.
- writeBech32Checksum(hrp, data, &bldr, version)
-
- return bldr.String(), nil
-}
-
-// Encode encodes a byte slice into a bech32 string with the given
-// human-readable part (HRP). The HRP will be converted to lowercase if needed
-// since mixed cased encodings are not permitted and lowercase is used for
-// checksum purposes. Note that the bytes must each encode 5 bits (base32).
-func Encode(hrp string, data []byte) (string, error) {
- return encodeGeneric(hrp, data, Version0)
-}
-
-// EncodeM is the exactly same as the Encode method, but it uses the new
-// bech32m constant instead of the original one. It should be used whenever one
-// attempts to encode a segwit address of v1 and beyond.
-func EncodeM(hrp string, data []byte) (string, error) {
- return encodeGeneric(hrp, data, VersionM)
-}
-
-// ConvertBits converts a byte slice where each byte is encoding fromBits bits,
-// to a byte slice where each byte is encoding toBits bits.
-func ConvertBits(data []byte, fromBits, toBits uint8, pad bool) ([]byte, error) {
- if fromBits < 1 || fromBits > 8 || toBits < 1 || toBits > 8 {
- return nil, ErrInvalidBitGroups{}
- }
-
- // Determine the maximum size the resulting array can have after base
- // conversion, so that we can size it a single time. This might be off
- // by a byte depending on whether padding is used or not and if the input
- // data is a multiple of both fromBits and toBits, but we ignore that and
- // just size it to the maximum possible.
- maxSize := len(data)*int(fromBits)/int(toBits) + 1
-
- // The final bytes, each byte encoding toBits bits.
- regrouped := make([]byte, 0, maxSize)
-
- // Keep track of the next byte we create and how many bits we have
- // added to it out of the toBits goal.
- nextByte := byte(0)
- filledBits := uint8(0)
-
- for _, b := range data {
-
- // Discard unused bits.
- b <<= 8 - fromBits
-
- // How many bits remaining to extract from the input data.
- remFromBits := fromBits
- for remFromBits > 0 {
- // How many bits remaining to be added to the next byte.
- remToBits := toBits - filledBits
-
- // The number of bytes to next extract is the minimum of
- // remFromBits and remToBits.
- toExtract := remFromBits
- if remToBits < toExtract {
- toExtract = remToBits
- }
-
- // Add the next bits to nextByte, shifting the already
- // added bits to the left.
- nextByte = (nextByte << toExtract) | (b >> (8 - toExtract))
-
- // Discard the bits we just extracted and get ready for
- // next iteration.
- b <<= toExtract
- remFromBits -= toExtract
- filledBits += toExtract
-
- // If the nextByte is completely filled, we add it to
- // our regrouped bytes and start on the next byte.
- if filledBits == toBits {
- regrouped = append(regrouped, nextByte)
- filledBits = 0
- nextByte = 0
- }
- }
- }
-
- // We pad any unfinished group if specified.
- if pad && filledBits > 0 {
- nextByte <<= toBits - filledBits
- regrouped = append(regrouped, nextByte)
- filledBits = 0
- nextByte = 0
- }
-
- // Any incomplete group must be <= 4 bits, and all zeroes.
- if filledBits > 0 && (filledBits > 4 || nextByte != 0) {
- return nil, ErrInvalidIncompleteGroup{}
- }
-
- return regrouped, nil
-}
-
-// EncodeFromBase256 converts a base256-encoded byte slice into a base32-encoded
-// byte slice and then encodes it into a bech32 string with the given
-// human-readable part (HRP). The HRP will be converted to lowercase if needed
-// since mixed cased encodings are not permitted and lowercase is used for
-// checksum purposes.
-func EncodeFromBase256(hrp string, data []byte) (string, error) {
- converted, err := ConvertBits(data, 8, 5, true)
- if err != nil {
- return "", err
- }
- return Encode(hrp, converted)
-}
-
-// DecodeToBase256 decodes a bech32-encoded string into its associated
-// human-readable part (HRP) and base32-encoded data, converts that data to a
-// base256-encoded byte slice and returns it along with the lowercase HRP.
-func DecodeToBase256(bech string) (string, []byte, error) {
- hrp, data, err := Decode(bech)
- if err != nil {
- return "", nil, err
- }
- converted, err := ConvertBits(data, 5, 8, false)
- if err != nil {
- return "", nil, err
- }
- return hrp, converted, nil
-}
diff --git a/btcutil/bech32/bech32_test.go b/btcutil/bech32/bech32_test.go
deleted file mode 100644
index 3f637c4..0000000
--- a/btcutil/bech32/bech32_test.go
+++ /dev/null
@@ -1,691 +0,0 @@
-// Copyright (c) 2017-2020 The btcsuite developers
-// Copyright (c) 2019 The Decred developers
-// Use of this source code is governed by an ISC
-// license that can be found in the LICENSE file.
-
-package bech32
-
-import (
- "bytes"
- "encoding/hex"
- "fmt"
- "strings"
- "testing"
-)
-
-// TestBech32 tests whether decoding and re-encoding the valid BIP-173 test
-// vectors works and if decoding invalid test vectors fails for the correct
-// reason.
-func TestBech32(t *testing.T) {
- tests := []struct {
- str string
- expectedError error
- }{
- {"A12UEL5L", nil},
- {"a12uel5l", nil},
- {"an83characterlonghumanreadablepartthatcontainsthenumber1andtheexcludedcharactersbio1tt5tgs", nil},
- {"abcdef1qpzry9x8gf2tvdw0s3jn54khce6mua7lmqqqxw", nil},
- {"11qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqc8247j", nil},
- {"split1checkupstagehandshakeupstreamerranterredcaperred2y9e3w", nil},
- {"split1checkupstagehandshakeupstreamerranterredcaperred2y9e2w", ErrInvalidChecksum{"2y9e3w", "2y9e3wlc445v", "2y9e2w"}}, // invalid checksum
- {"s lit1checkupstagehandshakeupstreamerranterredcaperredp8hs2p", ErrInvalidCharacter(' ')}, // invalid character (space) in hrp
- {"spl\x7Ft1checkupstagehandshakeupstreamerranterredcaperred2y9e3w", ErrInvalidCharacter(127)}, // invalid character (DEL) in hrp
- {"split1cheo2y9e2w", ErrNonCharsetChar('o')}, // invalid character (o) in data part
- {"split1a2y9w", ErrInvalidSeparatorIndex(5)}, // too short data part
- {"1checkupstagehandshakeupstreamerranterredcaperred2y9e3w", ErrInvalidSeparatorIndex(0)}, // empty hrp
- {"11qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqsqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqc8247j", ErrInvalidLength(91)}, // too long
-
- // Additional test vectors used in bitcoin core
- {" 1nwldj5", ErrInvalidCharacter(' ')},
- {"\x7f" + "1axkwrx", ErrInvalidCharacter(0x7f)},
- {"\x801eym55h", ErrInvalidCharacter(0x80)},
- {"an84characterslonghumanreadablepartthatcontainsthenumber1andtheexcludedcharactersbio1569pvx", ErrInvalidLength(91)},
- {"pzry9x0s0muk", ErrInvalidSeparatorIndex(-1)},
- {"1pzry9x0s0muk", ErrInvalidSeparatorIndex(0)},
- {"x1b4n0q5v", ErrNonCharsetChar(98)},
- {"li1dgmt3", ErrInvalidSeparatorIndex(2)},
- {"de1lg7wt\xff", ErrInvalidCharacter(0xff)},
- {"A1G7SGD8", ErrInvalidChecksum{"2uel5l", "2uel5llqfn3a", "g7sgd8"}},
- {"10a06t8", ErrInvalidLength(7)},
- {"1qzzfhee", ErrInvalidSeparatorIndex(0)},
- {"a12UEL5L", ErrMixedCase{}},
- {"A12uEL5L", ErrMixedCase{}},
- }
-
- for i, test := range tests {
- str := test.str
- hrp, decoded, err := Decode(str)
- if test.expectedError != err {
- t.Errorf("%d: expected decoding error %v "+
- "instead got %v", i, test.expectedError, err)
- continue
- }
-
- if err != nil {
- // End test case here if a decoding error was expected.
- continue
- }
-
- // Check that it encodes to the same string
- encoded, err := Encode(hrp, decoded)
- if err != nil {
- t.Errorf("encoding failed: %v", err)
- }
-
- if encoded != strings.ToLower(str) {
- t.Errorf("expected data to encode to %v, but got %v",
- str, encoded)
- }
-
- // Flip a bit in the string an make sure it is caught.
- pos := strings.LastIndexAny(str, "1")
- flipped := str[:pos+1] + string((str[pos+1] ^ 1)) + str[pos+2:]
- _, _, err = Decode(flipped)
- if err == nil {
- t.Error("expected decoding to fail")
- }
- }
-}
-
-// TestBech32M tests that the following set of strings, based on the test
-// vectors in BIP-350 are either valid or invalid using the new bech32m
-// checksum algo. Some of these strings are similar to the set of above test
-// vectors, but end up with different checksums.
-func TestBech32M(t *testing.T) {
- tests := []struct {
- str string
- expectedError error
- }{
- {"A1LQFN3A", nil},
- {"a1lqfn3a", nil},
- {"an83characterlonghumanreadablepartthatcontainsthetheexcludedcharactersbioandnumber11sg7hg6", nil},
- {"abcdef1l7aum6echk45nj3s0wdvt2fg8x9yrzpqzd3ryx", nil},
- {"11llllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllludsr8", nil},
- {"split1checkupstagehandshakeupstreamerranterredcaperredlc445v", nil},
- {"?1v759aa", nil},
-
- // Additional test vectors used in bitcoin core
- {"\x201xj0phk", ErrInvalidCharacter('\x20')},
- {"\x7f1g6xzxy", ErrInvalidCharacter('\x7f')},
- {"\x801vctc34", ErrInvalidCharacter('\x80')},
- {"an84characterslonghumanreadablepartthatcontainsthetheexcludedcharactersbioandnumber11d6pts4", ErrInvalidLength(91)},
- {"qyrz8wqd2c9m", ErrInvalidSeparatorIndex(-1)},
- {"1qyrz8wqd2c9m", ErrInvalidSeparatorIndex(0)},
- {"y1b0jsk6g", ErrNonCharsetChar(98)},
- {"lt1igcx5c0", ErrNonCharsetChar(105)},
- {"in1muywd", ErrInvalidSeparatorIndex(2)},
- {"mm1crxm3i", ErrNonCharsetChar(105)},
- {"au1s5cgom", ErrNonCharsetChar(111)},
- {"M1VUXWEZ", ErrInvalidChecksum{"mzl49c", "mzl49cw70eq6", "vuxwez"}},
- {"16plkw9", ErrInvalidLength(7)},
- {"1p2gdwpf", ErrInvalidSeparatorIndex(0)},
-
- {" 1nwldj5", ErrInvalidCharacter(' ')},
- {"\x7f" + "1axkwrx", ErrInvalidCharacter(0x7f)},
- {"\x801eym55h", ErrInvalidCharacter(0x80)},
- }
-
- for i, test := range tests {
- str := test.str
- hrp, decoded, err := Decode(str)
- if test.expectedError != err {
- t.Errorf("%d: (%v) expected decoding error %v "+
- "instead got %v", i, str, test.expectedError,
- err)
- continue
- }
-
- if err != nil {
- // End test case here if a decoding error was expected.
- continue
- }
-
- // Check that it encodes to the same string, using bech32 m.
- encoded, err := EncodeM(hrp, decoded)
- if err != nil {
- t.Errorf("encoding failed: %v", err)
- }
-
- if encoded != strings.ToLower(str) {
- t.Errorf("expected data to encode to %v, but got %v",
- str, encoded)
- }
-
- // Flip a bit in the string an make sure it is caught.
- pos := strings.LastIndexAny(str, "1")
- flipped := str[:pos+1] + string((str[pos+1] ^ 1)) + str[pos+2:]
- _, _, err = Decode(flipped)
- if err == nil {
- t.Error("expected decoding to fail")
- }
- }
-}
-
-// TestBech32DecodeGeneric tests that given a bech32 string, or a bech32m
-// string, the proper checksum version is returned so that callers can perform
-// segwit addr validation.
-func TestBech32DecodeGeneric(t *testing.T) {
- tests := []struct {
- str string
- version Version
- }{
- {"A1LQFN3A", VersionM},
- {"a1lqfn3a", VersionM},
- {"an83characterlonghumanreadablepartthatcontainsthetheexcludedcharactersbioandnumber11sg7hg6", VersionM},
- {"abcdef1l7aum6echk45nj3s0wdvt2fg8x9yrzpqzd3ryx", VersionM},
- {"11llllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllludsr8", VersionM},
- {"split1checkupstagehandshakeupstreamerranterredcaperredlc445v", VersionM},
- {"?1v759aa", VersionM},
-
- {"A12UEL5L", Version0},
- {"a12uel5l", Version0},
- {"an83characterlonghumanreadablepartthatcontainsthenumber1andtheexcludedcharactersbio1tt5tgs", Version0},
- {"abcdef1qpzry9x8gf2tvdw0s3jn54khce6mua7lmqqqxw", Version0},
- {"11qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqc8247j", Version0},
- {"split1checkupstagehandshakeupstreamerranterredcaperred2y9e3w", Version0},
-
- {"BC1QW508D6QEJXTDG4Y5R3ZARVARY0C5XW7KV8F3T4", Version0},
- {"tb1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3q0sl5k7", Version0},
- {"bc1pw508d6qejxtdg4y5r3zarvary0c5xw7kw508d6qejxtdg4y5r3zarvary0c5xw7kt5nd6y", VersionM},
- {"BC1SW50QGDZ25J", VersionM},
- {"bc1zw508d6qejxtdg4y5r3zarvaryvaxxpcs", VersionM},
- {"tb1qqqqqp399et2xygdj5xreqhjjvcmzhxw4aywxecjdzew6hylgvsesrxh6hy", Version0},
- {"tb1pqqqqp399et2xygdj5xreqhjjvcmzhxw4aywxecjdzew6hylgvsesf3hn0c", VersionM},
- {"bc1p0xlxvlhemja6c4dqv22uapctqupfhlxm9h8z3k2e72q4k9hcz7vqzk5jj0", VersionM},
- }
- for i, test := range tests {
- _, _, version, err := DecodeGeneric(test.str)
- if err != nil {
- t.Errorf("%d: (%v) unexpected error during "+
- "decoding: %v", i, test.str, err)
- continue
- }
-
- if version != test.version {
- t.Errorf("(%v): invalid version: expected %v, got %v",
- test.str, test.version, version)
- }
- }
-}
-
-// TestMixedCaseEncode ensures mixed case HRPs are converted to lowercase as
-// expected when encoding and that decoding the produced encoding when converted
-// to all uppercase produces the lowercase HRP and original data.
-func TestMixedCaseEncode(t *testing.T) {
- tests := []struct {
- name string
- hrp string
- data string
- encoded string
- }{{
- name: "all uppercase HRP with no data",
- hrp: "A",
- data: "",
- encoded: "a12uel5l",
- }, {
- name: "all uppercase HRP with data",
- hrp: "UPPERCASE",
- data: "787878",
- encoded: "uppercase10pu8sss7kmp",
- }, {
- name: "mixed case HRP even offsets uppercase",
- hrp: "AbCdEf",
- data: "00443214c74254b635cf84653a56d7c675be77df",
- encoded: "abcdef1qpzry9x8gf2tvdw0s3jn54khce6mua7lmqqqxw",
- }, {
- name: "mixed case HRP odd offsets uppercase ",
- hrp: "aBcDeF",
- data: "00443214c74254b635cf84653a56d7c675be77df",
- encoded: "abcdef1qpzry9x8gf2tvdw0s3jn54khce6mua7lmqqqxw",
- }, {
- name: "all lowercase HRP",
- hrp: "abcdef",
- data: "00443214c74254b635cf84653a56d7c675be77df",
- encoded: "abcdef1qpzry9x8gf2tvdw0s3jn54khce6mua7lmqqqxw",
- }}
-
- for _, test := range tests {
- // Convert the text hex to bytes, convert those bytes from base256 to
- // base32, then ensure the encoded result with the HRP provided in the
- // test data is as expected.
- data, err := hex.DecodeString(test.data)
- if err != nil {
- t.Errorf("%q: invalid hex %q: %v", test.name, test.data, err)
- continue
- }
- convertedData, err := ConvertBits(data, 8, 5, true)
- if err != nil {
- t.Errorf("%q: unexpected convert bits error: %v", test.name,
- err)
- continue
- }
- gotEncoded, err := Encode(test.hrp, convertedData)
- if err != nil {
- t.Errorf("%q: unexpected encode error: %v", test.name, err)
- continue
- }
- if gotEncoded != test.encoded {
- t.Errorf("%q: mismatched encoding -- got %q, want %q", test.name,
- gotEncoded, test.encoded)
- continue
- }
-
- // Ensure the decoding the expected lowercase encoding converted to all
- // uppercase produces the lowercase HRP and original data.
- gotHRP, gotData, err := Decode(strings.ToUpper(test.encoded))
- if err != nil {
- t.Errorf("%q: unexpected decode error: %v", test.name, err)
- continue
- }
- wantHRP := Why this scored 16/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.