diff --git a/blockchain/go.mod b/blockchain/go.mod index 070d57e580..327f4a0540 100644 --- a/blockchain/go.mod +++ b/blockchain/go.mod @@ -13,7 +13,7 @@ require ( github.com/decred/dcrd/dcrutil/v4 v4.0.0-20210129181600-6ae0142d3b28 github.com/decred/dcrd/gcs/v3 v3.0.0-20210129195202-a4265d63b619 github.com/decred/dcrd/lru v1.1.0 - github.com/decred/dcrd/txscript/v4 v4.0.0-20210330065944-a2366e6e0b3b + github.com/decred/dcrd/txscript/v4 v4.0.0-20210415215133-96b98390a9a9 github.com/decred/dcrd/wire v1.4.0 github.com/decred/slog v1.1.0 ) diff --git a/blockchain/stake/go.mod b/blockchain/stake/go.mod index 31cf94e64f..3130683707 100644 --- a/blockchain/stake/go.mod +++ b/blockchain/stake/go.mod @@ -8,7 +8,7 @@ require ( github.com/decred/dcrd/database/v2 v2.0.3-0.20210129190127-4ebd135a82f1 github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.0-20210127014238-b33b46cf1a24 github.com/decred/dcrd/dcrutil/v4 v4.0.0-20210129181600-6ae0142d3b28 - github.com/decred/dcrd/txscript/v4 v4.0.0-20210330065944-a2366e6e0b3b + github.com/decred/dcrd/txscript/v4 v4.0.0-20210415215133-96b98390a9a9 github.com/decred/dcrd/wire v1.4.0 github.com/decred/slog v1.1.0 ) diff --git a/database/go.mod b/database/go.mod index 292e7f5958..c67f14bd19 100644 --- a/database/go.mod +++ b/database/go.mod @@ -15,4 +15,5 @@ require ( replace ( github.com/decred/dcrd/dcrec/secp256k1/v4 => ../dcrec/secp256k1 github.com/decred/dcrd/dcrutil/v4 => ../dcrutil + github.com/decred/dcrd/txscript/v4 => ../txscript ) diff --git a/database/go.sum b/database/go.sum index 09026645a2..48cc2df132 100644 --- a/database/go.sum +++ b/database/go.sum @@ -2,6 +2,7 @@ github.com/agl/ed25519 v0.0.0-20170116200512-5312a6153412 h1:w1UutsfOrms1J05zt7I github.com/agl/ed25519 v0.0.0-20170116200512-5312a6153412/go.mod h1:WPjqKcmVOxf0XSf3YxCJs6N6AOSrOx3obionmG7T0y0= 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/dchest/siphash v1.2.2/go.mod h1:q+IRvb2gOSrUnYoPqHiyHXS0FOBBOdl6tONBlVnOnt4= github.com/decred/base58 v1.0.3 h1:KGZuh8d1WEMIrK0leQRM47W85KqCAdl2N+uagbctdDI= github.com/decred/base58 v1.0.3/go.mod h1:pXP9cXCfM2sFLb2viz2FNIdeMWmZDBKG3ZBYbiSM78E= github.com/decred/dcrd/chaincfg/chainhash v1.0.2 h1:rt5Vlq/jM3ZawwiacWjPa+smINyLRN07EO0cNBV6DGU= diff --git a/dcrutil/address.go b/dcrutil/address.go deleted file mode 100644 index 934a266f12..0000000000 --- a/dcrutil/address.go +++ /dev/null @@ -1,629 +0,0 @@ -// Copyright (c) 2013, 2014 The btcsuite developers -// Copyright (c) 2015-2020 The Decred developers -// Use of this source code is governed by an ISC -// license that can be found in the LICENSE file. - -package dcrutil - -import ( - "errors" - "fmt" - - "github.com/decred/base58" - "github.com/decred/dcrd/crypto/ripemd160" - "github.com/decred/dcrd/dcrec" - "github.com/decred/dcrd/dcrec/edwards/v2" - "github.com/decred/dcrd/dcrec/secp256k1/v4" - "github.com/decred/dcrd/dcrec/secp256k1/v4/schnorr" -) - -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 be - // decoded as a specific address type due to the string encoding - // beginning with unrecognized values that identify the network, type, - // and signature algorithm. - ErrUnknownAddressType = errors.New("unknown address type") -) - -// encodeAddress returns a human-readable payment address given a ripemd160 hash -// and netID which encodes the 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 [2]byte) string { - // Format is 2 bytes 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) -} - -// encodePKAddress returns a human-readable payment address to a public key -// given a serialized public key, a netID, and a signature suite. -func encodePKAddress(serializedPK []byte, netID [2]byte, algo dcrec.SignatureType) string { - pubKeyBytes := []byte{0x00} - - switch algo { - case dcrec.STEcdsaSecp256k1: - pubKeyBytes[0] = byte(dcrec.STEcdsaSecp256k1) - case dcrec.STEd25519: - pubKeyBytes[0] = byte(dcrec.STEd25519) - case dcrec.STSchnorrSecp256k1: - pubKeyBytes[0] = byte(dcrec.STSchnorrSecp256k1) - } - - // Pubkeys are encoded as [0] = type/ybit, [1:33] = serialized pubkey - compressed := serializedPK - if algo == dcrec.STEcdsaSecp256k1 || algo == dcrec.STSchnorrSecp256k1 { - pub, err := secp256k1.ParsePubKey(serializedPK) - if err != nil { - return "" - } - pubSerComp := pub.SerializeCompressed() - - // Set the y-bit if needed. - if pubSerComp[0] == 0x03 { - pubKeyBytes[0] |= (1 << 7) - } - - compressed = pubSerComp[1:] - } - - pubKeyBytes = append(pubKeyBytes, compressed...) - return base58.CheckEncode(pubKeyBytes, netID) -} - -// AddressParams defines an interface that is used to provide the parameters -// required when encoding and decoding addresses. These values are typically -// well-defined and unique per network. -type AddressParams interface { - // AddrIDPubKeyV0 returns the magic prefix bytes for version 0 pay-to-pubkey - // addresses. - AddrIDPubKeyV0() [2]byte - - // AddrIDPubKeyHashECDSAV0 returns the magic prefix bytes for version 0 - // pay-to-pubkey-hash addresses where the underlying pubkey is secp256k1 and - // the signature algorithm is ECDSA. - AddrIDPubKeyHashECDSAV0() [2]byte - - // AddrIDPubKeyHashEd25519V0 returns the magic prefix bytes for version 0 - // pay-to-pubkey-hash addresses where the underlying pubkey and signature - // algorithm are Ed25519. - AddrIDPubKeyHashEd25519V0() [2]byte - - // AddrIDPubKeyHashSchnorrV0 returns the magic prefix bytes for version 0 - // pay-to-pubkey-hash addresses where the underlying pubkey is secp256k1 and - // the signature algorithm is Schnorr. - AddrIDPubKeyHashSchnorrV0() [2]byte - - // AddrIDScriptHashV0 returns the magic prefix bytes for version 0 - // pay-to-script-hash addresses. - AddrIDScriptHashV0() [2]byte -} - -// 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 Address: String will - // return the value as a string without any conversion, while Address - // may convert destination types (for example, converting pubkeys to - // P2PKH addresses) before encoding as a payment address string. - String() string - - // Address 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. - Address() string - - // ScriptAddress returns the raw bytes of the address to be used - // when inserting the address into a txout's script. - ScriptAddress() []byte - - // Hash160 returns the Hash160(data) where data is the data normally - // hashed to 160 bits from the respective address type. - Hash160() *[ripemd160.Size]byte -} - -// NewAddressPubKey returns a new Address. decoded must -// be 33 bytes. -func NewAddressPubKey(decoded []byte, net AddressParams) (Address, error) { - if len(decoded) == 33 { - // First byte is the signature suite and ybit. - suite := decoded[0] - suite &= ^uint8(1 << 7) - ybit := !(decoded[0]&(1<<7) == 0) - toAppend := uint8(0x02) - if ybit { - toAppend = 0x03 - } - - switch dcrec.SignatureType(suite) { - case dcrec.STEcdsaSecp256k1: - return NewAddressSecpPubKey( - append([]byte{toAppend}, decoded[1:]...), - net) - case dcrec.STEd25519: - return NewAddressEdwardsPubKey(decoded[1:], net) - case dcrec.STSchnorrSecp256k1: - return NewAddressSecSchnorrPubKey( - append([]byte{toAppend}, decoded[1:]...), - net) - } - return nil, ErrUnknownAddressType - } - return nil, ErrUnknownAddressType -} - -// DecodeAddress decodes the string encoding of an address and returns the -// Address if it is a valid encoding for a known address type and is for the -// provided network. -func DecodeAddress(addr string, net AddressParams) (Address, error) { - // Switch on decoded length to determine the type. - decoded, netID, err := base58.CheckDecode(addr) - if err != nil { - if errors.Is(err, base58.ErrChecksum) { - return nil, ErrChecksumMismatch - } - return nil, fmt.Errorf("decoded address is of unknown format: %v", err) - } - - switch netID { - case net.AddrIDPubKeyV0(): - return NewAddressPubKey(decoded, net) - - case net.AddrIDPubKeyHashECDSAV0(): - return NewAddressPubKeyHash(decoded, net, dcrec.STEcdsaSecp256k1) - - case net.AddrIDPubKeyHashEd25519V0(): - return NewAddressPubKeyHash(decoded, net, dcrec.STEd25519) - - case net.AddrIDPubKeyHashSchnorrV0(): - return NewAddressPubKeyHash(decoded, net, dcrec.STSchnorrSecp256k1) - - case net.AddrIDScriptHashV0(): - return NewAddressScriptHashFromHash(decoded, net) - - default: - return nil, ErrUnknownAddressType - } -} - -// AddressPubKeyHash is an Address for a pay-to-pubkey-hash (P2PKH) -// transaction. -type AddressPubKeyHash struct { - hash [ripemd160.Size]byte - netID [2]byte - dsa dcrec.SignatureType -} - -// NewAddressPubKeyHash returns a new AddressPubKeyHash. pkHash must -// be 20 bytes. -func NewAddressPubKeyHash(pkHash []byte, net AddressParams, algo dcrec.SignatureType) (*AddressPubKeyHash, error) { - // Ensure the provided signature algo is supported. - var addrID [2]byte - switch algo { - case dcrec.STEcdsaSecp256k1: - addrID = net.AddrIDPubKeyHashECDSAV0() - case dcrec.STEd25519: - addrID = net.AddrIDPubKeyHashEd25519V0() - case dcrec.STSchnorrSecp256k1: - addrID = net.AddrIDPubKeyHashSchnorrV0() - default: - return nil, errors.New("unknown signature algorithm") - } - - // Ensure the provided pubkey hash length is valid. - if len(pkHash) != ripemd160.Size { - return nil, errors.New("pkHash must be 20 bytes") - } - addr := &AddressPubKeyHash{netID: addrID, dsa: algo} - copy(addr.hash[:], pkHash) - return addr, nil -} - -// Address returns the string encoding of a pay-to-pubkey-hash address. -// -// Part of the Address interface. -func (a *AddressPubKeyHash) Address() 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[:] -} - -// String returns a human-readable string for the pay-to-pubkey-hash address. -// This is equivalent to calling Address, but is provided so the type can be -// used as a fmt.Stringer. -func (a *AddressPubKeyHash) String() string { - return a.Address() -} - -// 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 -} - -// DSA returns the digital signature algorithm for the associated public key -// hash. -func (a *AddressPubKeyHash) DSA() dcrec.SignatureType { - return a.dsa -} - -// AddressScriptHash is an Address for a pay-to-script-hash (P2SH) -// transaction. -type AddressScriptHash struct { - hash [ripemd160.Size]byte - netID [2]byte -} - -// NewAddressScriptHash returns a new AddressScriptHash. -func NewAddressScriptHash(serializedScript []byte, net AddressParams) (*AddressScriptHash, error) { - scriptHash := Hash160(serializedScript) - return newAddressScriptHashFromHash(scriptHash, net.AddrIDScriptHashV0()) -} - -// NewAddressScriptHashFromHash returns a new AddressScriptHash. scriptHash -// must be 20 bytes. -func NewAddressScriptHashFromHash(scriptHash []byte, net AddressParams) (*AddressScriptHash, error) { - ash, err := newAddressScriptHashFromHash(scriptHash, net.AddrIDScriptHashV0()) - if err != nil { - return nil, err - } - - return ash, nil -} - -// 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 [2]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 -} - -// Address returns the string encoding of a pay-to-script-hash address. -// -// Part of the Address interface. -func (a *AddressScriptHash) Address() 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[:] -} - -// String returns a human-readable string for the pay-to-script-hash address. -// This is equivalent to calling Address, but is provided so the type can be -// used as a fmt.Stringer. -func (a *AddressScriptHash) String() string { - return a.Address() -} - -// 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 -) - -// ErrInvalidPubKeyFormat indicates that a serialized pubkey is unusable as it -// is neither in the uncompressed or compressed format. -var ErrInvalidPubKeyFormat = errors.New("invalid pubkey format") - -// AddressSecpPubKey is an Address for a secp256k1 pay-to-pubkey transaction. -type AddressSecpPubKey struct { - pubKeyFormat PubKeyFormat - pubKey *secp256k1.PublicKey - pubKeyID [2]byte - pubKeyHashID [2]byte -} - -// NewAddressSecpPubKey returns a new AddressSecpPubKey which represents a -// pay-to-pubkey address, using a secp256k1 pubkey. The serializedPubKey -// parameter must be a valid pubkey and must be uncompressed or compressed. -func NewAddressSecpPubKey(serializedPubKey []byte, net AddressParams) (*AddressSecpPubKey, error) { - pubKey, err := secp256k1.ParsePubKey(serializedPubKey) - if err != nil { - return nil, err - } - - // Set the format of the pubkey. This probably should be returned - // from dcrec, 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. - var pkFormat PubKeyFormat - switch serializedPubKey[0] { - case 0x02, 0x03: - pkFormat = PKFCompressed - case 0x04: - pkFormat = PKFUncompressed - default: - return nil, ErrInvalidPubKeyFormat - } - - return &AddressSecpPubKey{ - pubKeyFormat: pkFormat, - pubKey: pubKey, - pubKeyID: net.AddrIDPubKeyV0(), - pubKeyHashID: net.AddrIDPubKeyHashECDSAV0(), - }, nil -} - -// serialize returns the serialization of the public key according to the -// format associated with the address. -func (a *AddressSecpPubKey) serialize() []byte { - switch a.pubKeyFormat { - default: - fallthrough - case PKFUncompressed: - return a.pubKey.SerializeUncompressed() - - case PKFCompressed: - return a.pubKey.SerializeCompressed() - } -} - -// Address 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 Decred addresses -// are pay-to-pubkey-hash constructed from the compressed public key. -// -// Part of the Address interface. -func (a *AddressSecpPubKey) Address() 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 *AddressSecpPubKey) ScriptAddress() []byte { - return a.serialize() -} - -// 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 *AddressSecpPubKey) Hash160() *[ripemd160.Size]byte { - h160 := Hash160(a.pubKey.SerializeCompressed()) - array := new([ripemd160.Size]byte) - copy(array[:], h160) - - return array -} - -// String returns the hex-encoded human-readable string for the pay-to-pubkey -// address. This is not the same as calling Address. -func (a *AddressSecpPubKey) String() string { - return encodePKAddress(a.serialize(), a.pubKeyID, dcrec.STEcdsaSecp256k1) -} - -// Format returns the format (uncompressed, compressed, etc) of the -// pay-to-pubkey address. -func (a *AddressSecpPubKey) Format() PubKeyFormat { - return a.pubKeyFormat -} - -// 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 Decred addresses -// are pay-to-pubkey-hash constructed from the uncompressed public key. -func (a *AddressSecpPubKey) AddressPubKeyHash() *AddressPubKeyHash { - addr := &AddressPubKeyHash{netID: a.pubKeyHashID, - dsa: dcrec.STEcdsaSecp256k1} - copy(addr.hash[:], Hash160(a.serialize())) - return addr -} - -// PubKey returns the underlying public key for the address. -func (a *AddressSecpPubKey) PubKey() *secp256k1.PublicKey { - return a.pubKey -} - -// DSA returns the underlying digital signature algorithm for the -// address. -func (a *AddressSecpPubKey) DSA() dcrec.SignatureType { - return dcrec.STEcdsaSecp256k1 -} - -// NewAddressSecpPubKeyCompressed creates a new address using a compressed public key -func NewAddressSecpPubKeyCompressed(pubkey *secp256k1.PublicKey, params AddressParams) (*AddressSecpPubKey, error) { - return NewAddressSecpPubKey(pubkey.SerializeCompressed(), params) -} - -// AddressEdwardsPubKey is an Address for an Ed25519 pay-to-pubkey transaction. -type AddressEdwardsPubKey struct { - pubKey *edwards.PublicKey - pubKeyID [2]byte - pubKeyHashID [2]byte -} - -// NewAddressEdwardsPubKey returns a new AddressEdwardsPubKey which represents a -// pay-to-pubkey address, using an Ed25519 pubkey. The serializedPubKey -// parameter must be a valid 32 byte serialized public key. -func NewAddressEdwardsPubKey(serializedPubKey []byte, net AddressParams) (*AddressEdwardsPubKey, error) { - pubKey, err := edwards.ParsePubKey(serializedPubKey) - if err != nil { - return nil, err - } - - return &AddressEdwardsPubKey{ - pubKey: pubKey, - pubKeyID: net.AddrIDPubKeyV0(), - pubKeyHashID: net.AddrIDPubKeyHashEd25519V0(), - }, nil -} - -// serialize returns the serialization of the public key. -func (a *AddressEdwardsPubKey) serialize() []byte { - return a.pubKey.Serialize() -} - -// Address returns the string encoding of the public key as a -// pay-to-pubkey-hash. -// -// Part of the Address interface. -func (a *AddressEdwardsPubKey) Address() 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 *AddressEdwardsPubKey) ScriptAddress() []byte { - return a.serialize() -} - -// 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 *AddressEdwardsPubKey) Hash160() *[ripemd160.Size]byte { - h160 := Hash160(a.pubKey.Serialize()) - array := new([ripemd160.Size]byte) - copy(array[:], h160) - - return array -} - -// String returns the hex-encoded human-readable string for the pay-to-pubkey -// address. This is not the same as calling Address. -func (a *AddressEdwardsPubKey) String() string { - return encodePKAddress(a.serialize(), a.pubKeyID, dcrec.STEd25519) -} - -// AddressPubKeyHash returns the pay-to-pubkey address converted to a -// pay-to-pubkey-hash address. -func (a *AddressEdwardsPubKey) AddressPubKeyHash() *AddressPubKeyHash { - addr := &AddressPubKeyHash{netID: a.pubKeyHashID, dsa: dcrec.STEd25519} - copy(addr.hash[:], Hash160(a.serialize())) - return addr -} - -// PubKey returns the underlying public key for the address. -func (a *AddressEdwardsPubKey) PubKey() *edwards.PublicKey { - return a.pubKey -} - -// DSA returns the underlying digital signature algorithm for the -// address. -func (a *AddressEdwardsPubKey) DSA() dcrec.SignatureType { - return dcrec.STEd25519 -} - -// AddressSecSchnorrPubKey is an Address for a secp256k1 pay-to-pubkey -// transaction. -type AddressSecSchnorrPubKey struct { - pubKey *secp256k1.PublicKey - pubKeyID [2]byte - pubKeyHashID [2]byte -} - -// NewAddressSecSchnorrPubKey returns a new AddressSecpPubKey which represents a -// pay-to-pubkey address, using a secp256k1 pubkey. The serializedPubKey -// parameter must be a valid pubkey and must be compressed. -func NewAddressSecSchnorrPubKey(serializedPubKey []byte, net AddressParams) (*AddressSecSchnorrPubKey, error) { - pubKey, err := schnorr.ParsePubKey(serializedPubKey) - if err != nil { - return nil, err - } - - return &AddressSecSchnorrPubKey{ - pubKey: pubKey, - pubKeyID: net.AddrIDPubKeyV0(), - pubKeyHashID: net.AddrIDPubKeyHashSchnorrV0(), - }, nil -} - -// serialize returns the serialization of the public key according to the -// format associated with the address. -func (a *AddressSecSchnorrPubKey) serialize() []byte { - return a.pubKey.SerializeCompressed() -} - -// Address 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 Decred addresses -// are pay-to-pubkey-hash constructed from the compressed public key. -// -// Part of the Address interface. -func (a *AddressSecSchnorrPubKey) Address() 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 *AddressSecSchnorrPubKey) ScriptAddress() []byte { - return a.serialize() -} - -// 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 *AddressSecSchnorrPubKey) Hash160() *[ripemd160.Size]byte { - h160 := Hash160(a.pubKey.SerializeCompressed()) - array := new([ripemd160.Size]byte) - copy(array[:], h160) - - return array -} - -// String returns the hex-encoded human-readable string for the pay-to-pubkey -// address. This is not the same as calling Address. -func (a *AddressSecSchnorrPubKey) String() string { - return encodePKAddress(a.serialize(), a.pubKeyID, dcrec.STSchnorrSecp256k1) -} - -// AddressPubKeyHash returns the pay-to-pubkey address converted to a -// pay-to-pubkey-hash address. -func (a *AddressSecSchnorrPubKey) AddressPubKeyHash() *AddressPubKeyHash { - addr := &AddressPubKeyHash{netID: a.pubKeyHashID, - dsa: dcrec.STSchnorrSecp256k1} - copy(addr.hash[:], Hash160(a.serialize())) - return addr -} - -// DSA returns the underlying digital signature algorithm for the -// address. -func (a *AddressSecSchnorrPubKey) DSA() dcrec.SignatureType { - return dcrec.STSchnorrSecp256k1 -} diff --git a/dcrutil/address_test.go b/dcrutil/address_test.go deleted file mode 100644 index a9274ff7cc..0000000000 --- a/dcrutil/address_test.go +++ /dev/null @@ -1,719 +0,0 @@ -// Copyright (c) 2013, 2014 The btcsuite developers -// Copyright (c) 2015-2020 The Decred developers -// Use of this source code is governed by an ISC -// license that can be found in the LICENSE file. - -package dcrutil - -import ( - "bytes" - "encoding/hex" - "fmt" - "reflect" - "testing" - - "github.com/decred/base58" - "github.com/decred/dcrd/crypto/ripemd160" - "github.com/decred/dcrd/dcrec" - "github.com/decred/dcrd/dcrec/secp256k1/v4" -) - -// mockAddrParams implements the AddressParams interface and is used throughout -// the tests to mock multiple networks. -type mockAddrParams struct { - pubKeyID [2]byte - pkhEcdsaID [2]byte - pkhEd25519ID [2]byte - pkhSchnorrID [2]byte - scriptHashID [2]byte - privKeyID [2]byte -} - -// AddrIDPubKeyV0 returns the magic prefix bytes associated with the mock params -// for version 0 pay-to-pubkey addresses. -// -// This is part of the AddressParams interface. -func (p *mockAddrParams) AddrIDPubKeyV0() [2]byte { - return p.pubKeyID -} - -// AddrIDPubKeyHashECDSAV0 returns the magic prefix bytes associated with the -// mock params for version 0 pay-to-pubkey-hash addresses where the underlying -// pubkey is secp256k1 and the signature algorithm is ECDSA. -// -// This is part of the AddressParams interface. -func (p *mockAddrParams) AddrIDPubKeyHashECDSAV0() [2]byte { - return p.pkhEcdsaID -} - -// AddrIDPubKeyHashEd25519V0 returns the magic prefix bytes associated with the -// mock params for version 0 pay-to-pubkey-hash addresses where the underlying -// pubkey and signature algorithm are Ed25519. -// -// This is part of the AddressParams interface. -func (p *mockAddrParams) AddrIDPubKeyHashEd25519V0() [2]byte { - return p.pkhEd25519ID -} - -// AddrIDPubKeyHashSchnorrV0 returns the magic prefix bytes associated with the -// mock params for version 0 pay-to-pubkey-hash addresses where the underlying -// pubkey is secp256k1 and the signature algorithm is Schnorr. -// -// This is part of the AddressParams interface. -func (p *mockAddrParams) AddrIDPubKeyHashSchnorrV0() [2]byte { - return p.pkhSchnorrID -} - -// AddrIDScriptHashV0 returns the magic prefix bytes associated with the mock -// params for version 0 pay-to-script-hash addresses. -// -// This is part of the AddressParams interface. -func (p *mockAddrParams) AddrIDScriptHashV0() [2]byte { - return p.scriptHashID -} - -// mockMainNetParams returns mock mainnet address parameters to use throughout -// the tests. They match the Decred mainnet params as of the time this comment -// was written. -func mockMainNetParams() *mockAddrParams { - return &mockAddrParams{ - pubKeyID: [2]byte{0x13, 0x86}, // starts with Dk - pkhEcdsaID: [2]byte{0x07, 0x3f}, // starts with Ds - pkhEd25519ID: [2]byte{0x07, 0x1f}, // starts with De - pkhSchnorrID: [2]byte{0x07, 0x01}, // starts with DS - scriptHashID: [2]byte{0x07, 0x1a}, // starts with Dc - privKeyID: [2]byte{0x22, 0xde}, // starts with Pm - } -} - -// mockTestNetParams returns mock testnet address parameters to use throughout -// the tests. They match the Decred mainnet params as of the time this comment -// was written. -func mockTestNetParams() *mockAddrParams { - return &mockAddrParams{ - pubKeyID: [2]byte{0x28, 0xf7}, // starts with Tk - pkhEcdsaID: [2]byte{0x0f, 0x21}, // starts with Ts - pkhEd25519ID: [2]byte{0x0f, 0x01}, // starts with Te - pkhSchnorrID: [2]byte{0x0e, 0xe3}, // starts with TS - scriptHashID: [2]byte{0x0e, 0xfc}, // starts with Tc - privKeyID: [2]byte{0x23, 0x0e}, // starts with Pt - } -} - -// mockRegNetParams returns mock regression test address parameters to use -// throughout the tests. They match the Decred mainnet params as of the time -// this comment was written. -func mockRegNetParams() *mockAddrParams { - return &mockAddrParams{ - pubKeyID: [2]byte{0x25, 0xe5}, // starts with Rk - pkhEcdsaID: [2]byte{0x0e, 0x00}, // starts with Rs - pkhEd25519ID: [2]byte{0x0d, 0xe0}, // starts with Re - pkhSchnorrID: [2]byte{0x0d, 0xc2}, // starts with RS - scriptHashID: [2]byte{0x0d, 0xdb}, // starts with Rc - privKeyID: [2]byte{0x22, 0xfe}, // starts with Pr - } -} - -// tstAddressPubKey makes an AddressPubKey, setting the unexported fields with -// the parameters. -func tstAddressPubKey(serializedPubKey []byte, pubKeyFormat PubKeyFormat, netID [2]byte) *AddressSecpPubKey { - pubKey, _ := secp256k1.ParsePubKey(serializedPubKey) - return &AddressSecpPubKey{ - pubKeyFormat: pubKeyFormat, - pubKey: pubKey, - pubKeyHashID: netID, - } -} - -func TestAddresses(t *testing.T) { - mainNetParams := mockMainNetParams() - testNetParams := mockTestNetParams() - regNetParams := mockRegNetParams() - tests := []struct { - name string - addr string - saddr string - encoded string - valid bool - result Address - f func() (Address, error) - net AddressParams - }{ - // Positive P2PKH tests. - { - name: "mainnet p2pkh", - addr: "DsUZxxoHJSty8DCfwfartwTYbuhmVct7tJu", - encoded: "DsUZxxoHJSty8DCfwfartwTYbuhmVct7tJu", - valid: true, - result: &AddressPubKeyHash{ - hash: [ripemd160.Size]byte{ - 0x27, 0x89, 0xd5, 0x8c, 0xfa, 0x09, 0x57, 0xd2, 0x06, 0xf0, - 0x25, 0xc2, 0xaf, 0x05, 0x6f, 0xc8, 0xa7, 0x7c, 0xeb, 0xb0}, - netID: mainNetParams.AddrIDPubKeyHashECDSAV0(), - }, - f: func() (Address, error) { - pkHash := []byte{ - 0x27, 0x89, 0xd5, 0x8c, 0xfa, 0x09, 0x57, 0xd2, 0x06, 0xf0, - 0x25, 0xc2, 0xaf, 0x05, 0x6f, 0xc8, 0xa7, 0x7c, 0xeb, 0xb0} - return NewAddressPubKeyHash(pkHash, mainNetParams, - dcrec.STEcdsaSecp256k1) - }, - net: mainNetParams, - }, - { - name: "mainnet p2pkh 2", - addr: "DsU7xcg53nxaKLLcAUSKyRndjG78Z2VZnX9", - encoded: "DsU7xcg53nxaKLLcAUSKyRndjG78Z2VZnX9", - valid: true, - result: &AddressPubKeyHash{ - hash: [ripemd160.Size]byte{ - 0x22, 0x9e, 0xba, 0xc3, 0x0e, 0xfd, 0x6a, 0x69, 0xee, 0xc9, - 0xc1, 0xa4, 0x8e, 0x04, 0x8b, 0x7c, 0x97, 0x5c, 0x25, 0xf2}, - netID: mainNetParams.AddrIDPubKeyHashECDSAV0(), - }, - f: func() (Address, error) { - pkHash := []byte{ - 0x22, 0x9e, 0xba, 0xc3, 0x0e, 0xfd, 0x6a, 0x69, 0xee, 0xc9, - 0xc1, 0xa4, 0x8e, 0x04, 0x8b, 0x7c, 0x97, 0x5c, 0x25, 0xf2} - return NewAddressPubKeyHash(pkHash, mainNetParams, - dcrec.STEcdsaSecp256k1) - }, - net: mainNetParams, - }, - { - name: "testnet p2pkh", - addr: "Tso2MVTUeVrjHTBFedFhiyM7yVTbieqp91h", - encoded: "Tso2MVTUeVrjHTBFedFhiyM7yVTbieqp91h", - valid: true, - result: &AddressPubKeyHash{ - hash: [ripemd160.Size]byte{ - 0xf1, 0x5d, 0xa1, 0xcb, 0x8d, 0x1b, 0xcb, 0x16, 0x2c, 0x6a, - 0xb4, 0x46, 0xc9, 0x57, 0x57, 0xa6, 0xe7, 0x91, 0xc9, 0x16}, - netID: testNetParams.AddrIDPubKeyHashECDSAV0(), - }, - f: func() (Address, error) { - pkHash := []byte{ - 0xf1, 0x5d, 0xa1, 0xcb, 0x8d, 0x1b, 0xcb, 0x16, 0x2c, 0x6a, - 0xb4, 0x46, 0xc9, 0x57, 0x57, 0xa6, 0xe7, 0x91, 0xc9, 0x16} - return NewAddressPubKeyHash(pkHash, - testNetParams, dcrec.STEcdsaSecp256k1) - }, - net: testNetParams, - }, - { - name: "regnet p2pkh", - addr: "RsWM2w5LPJip56uxcZ1Scq7Tcbg97EfiwPA", - encoded: "RsWM2w5LPJip56uxcZ1Scq7Tcbg97EfiwPA", - valid: true, - result: &AddressPubKeyHash{ - hash: [ripemd160.Size]byte{ - 0xf1, 0x5d, 0xa1, 0xcb, 0x8d, 0x1b, 0xcb, 0x16, 0x2c, 0x6a, - 0xb4, 0x46, 0xc9, 0x57, 0x57, 0xa6, 0xe7, 0x91, 0xc9, 0x16}, - netID: regNetParams.AddrIDPubKeyHashECDSAV0(), - }, - f: func() (Address, error) { - pkHash := []byte{ - 0xf1, 0x5d, 0xa1, 0xcb, 0x8d, 0x1b, 0xcb, 0x16, 0x2c, 0x6a, - 0xb4, 0x46, 0xc9, 0x57, 0x57, 0xa6, 0xe7, 0x91, 0xc9, 0x16} - return NewAddressPubKeyHash(pkHash, regNetParams, - dcrec.STEcdsaSecp256k1) - }, - net: regNetParams, - }, - - // Negative P2PKH tests. - { - name: "p2pkh wrong hash length", - addr: "", - valid: false, - f: func() (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 NewAddressPubKeyHash(pkHash, mainNetParams, - dcrec.STEcdsaSecp256k1) - }, - }, - { - name: "p2pkh bad checksum", - addr: "TsmWaPM77WSyA3aiQ2Q1KnwGDVWvEkhip23", - valid: false, - net: testNetParams, - }, - - // Positive P2SH tests. - { - // Taken from transactions: - // output: 3c9018e8d5615c306d72397f8f5eef44308c98fb576a88e030c25456b4f3a7ac - // input: 837dea37ddc8b1e3ce646f1a656e79bbd8cc7f558ac56a169626d649ebe2a3ba. - name: "mainnet p2sh", - addr: "DcuQKx8BES9wU7C6Q5VmLBjw436r27hayjS", - encoded: "DcuQKx8BES9wU7C6Q5VmLBjw436r27hayjS", - valid: true, - result: &AddressScriptHash{ - hash: [ripemd160.Size]byte{ - 0xf0, 0xb4, 0xe8, 0x51, 0x00, 0xae, 0xe1, 0xa9, 0x96, 0xf2, - 0x29, 0x15, 0xeb, 0x3c, 0x3f, 0x76, 0x4d, 0x53, 0x77, 0x9a}, - netID: mainNetParams.AddrIDScriptHashV0(), - }, - f: func() (Address, error) { - txscript := []byte{ - 0x51, 0x21, 0x03, 0xaa, 0x43, 0xf0, 0xa6, 0xc1, 0x57, 0x30, - 0xd8, 0x86, 0xcc, 0x1f, 0x03, 0x42, 0x04, 0x6d, 0x20, 0x17, - 0x54, 0x83, 0xd9, 0x0d, 0x7c, 0xcb, 0x65, 0x7f, 0x90, 0xc4, - 0x89, 0x11, 0x1d, 0x79, 0x4c, 0x51, 0xae} - return NewAddressScriptHash(txscript, mainNetParams) - }, - net: mainNetParams, - }, - { - // Taken from transactions: - // output: b0539a45de13b3e0403909b8bd1a555b8cbe45fd4e3f3fda76f3a5f52835c29d - // input: (not yet redeemed at time test was written) - name: "mainnet p2sh 2", - addr: "DcqgK4N4Ccucu2Sq4VDAdu4wH4LASLhzLVp", - encoded: "DcqgK4N4Ccucu2Sq4VDAdu4wH4LASLhzLVp", - valid: true, - result: &AddressScriptHash{ - hash: [ripemd160.Size]byte{ - 0xc7, 0xda, 0x50, 0x95, 0x68, 0x34, 0x36, 0xf4, 0x43, 0x5f, - 0xc4, 0xe7, 0x16, 0x3d, 0xca, 0xfd, 0xa1, 0xa2, 0xd0, 0x07}, - netID: mainNetParams.AddrIDScriptHashV0(), - }, - f: func() (Address, error) { - hash := []byte{ - 0xc7, 0xda, 0x50, 0x95, 0x68, 0x34, 0x36, 0xf4, 0x43, 0x5f, - 0xc4, 0xe7, 0x16, 0x3d, 0xca, 0xfd, 0xa1, 0xa2, 0xd0, 0x07} - return NewAddressScriptHashFromHash(hash, mainNetParams) - }, - net: mainNetParams, - }, - { - // Taken from bitcoind base58_keys_valid. - name: "testnet p2sh", - addr: "TccWLgcquqvwrfBocq5mcK5kBiyw8MvyvCi", - encoded: "TccWLgcquqvwrfBocq5mcK5kBiyw8MvyvCi", - valid: true, - result: &AddressScriptHash{ - hash: [ripemd160.Size]byte{ - 0x36, 0xc1, 0xca, 0x10, 0xa8, 0xa6, 0xa4, 0xb5, 0xd4, 0x20, - 0x4a, 0xc9, 0x70, 0x85, 0x39, 0x79, 0x90, 0x3a, 0xa2, 0x84}, - netID: testNetParams.AddrIDScriptHashV0(), - }, - f: func() (Address, error) { - hash := []byte{ - 0x36, 0xc1, 0xca, 0x10, 0xa8, 0xa6, 0xa4, 0xb5, 0xd4, 0x20, - 0x4a, 0xc9, 0x70, 0x85, 0x39, 0x79, 0x90, 0x3a, 0xa2, 0x84} - return NewAddressScriptHashFromHash(hash, testNetParams) - }, - net: testNetParams, - }, - { - name: "regnet p2sh", - addr: "RcKq28Eheeo2eJvWakqWWAr5pqCUWykwDHe", - encoded: "RcKq28Eheeo2eJvWakqWWAr5pqCUWykwDHe", - valid: true, - result: &AddressScriptHash{ - hash: [ripemd160.Size]byte{ - 0x36, 0xc1, 0xca, 0x10, 0xa8, 0xa6, 0xa4, 0xb5, 0xd4, 0x20, - 0x4a, 0xc9, 0x70, 0x85, 0x39, 0x79, 0x90, 0x3a, 0xa2, 0x84}, - netID: regNetParams.AddrIDScriptHashV0(), - }, - f: func() (Address, error) { - hash := []byte{ - 0x36, 0xc1, 0xca, 0x10, 0xa8, 0xa6, 0xa4, 0xb5, 0xd4, 0x20, - 0x4a, 0xc9, 0x70, 0x85, 0x39, 0x79, 0x90, 0x3a, 0xa2, 0x84} - return NewAddressScriptHashFromHash(hash, regNetParams) - }, - net: regNetParams, - }, - - // Negative P2SH tests. - { - name: "p2sh wrong hash length", - addr: "", - valid: false, - f: func() (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 NewAddressScriptHashFromHash(hash, mainNetParams) - }, - net: mainNetParams, - }, - - // Positive P2PK tests. - { - name: "mainnet p2pk compressed (0x02)", - addr: "DsT4FDqBKYG1Xr8aGrT1rKP3kiv6TZ5K5th", - encoded: "DsT4FDqBKYG1Xr8aGrT1rKP3kiv6TZ5K5th", - valid: true, - result: tstAddressPubKey( - []byte{ - 0x02, 0x8f, 0x53, 0x83, 0x8b, 0x76, 0x39, 0x56, 0x3f, 0x27, - 0xc9, 0x48, 0x45, 0x54, 0x9a, 0x41, 0xe5, 0x14, 0x6b, 0xcd, - 0x52, 0xe7, 0xfe, 0xf0, 0xea, 0x6d, 0xa1, 0x43, 0xa0, 0x2b, - 0x0f, 0xe2, 0xed}, - PKFCompressed, mainNetParams.AddrIDPubKeyHashECDSAV0()), - f: func() (Address, error) { - serializedPubKey := []byte{ - 0x02, 0x8f, 0x53, 0x83, 0x8b, 0x76, 0x39, 0x56, 0x3f, 0x27, - 0xc9, 0x48, 0x45, 0x54, 0x9a, 0x41, 0xe5, 0x14, 0x6b, 0xcd, - 0x52, 0xe7, 0xfe, 0xf0, 0xea, 0x6d, 0xa1, 0x43, 0xa0, 0x2b, - 0x0f, 0xe2, 0xed} - return NewAddressSecpPubKey(serializedPubKey, mainNetParams) - }, - net: mainNetParams, - }, - { - name: "mainnet p2pk compressed (0x03)", - addr: "DsfiE2y23CGwKNxSGjbfPGeEW4xw1tamZdc", - encoded: "DsfiE2y23CGwKNxSGjbfPGeEW4xw1tamZdc", - valid: true, - result: tstAddressPubKey( - []byte{ - 0x03, 0xe9, 0x25, 0xaa, 0xfc, 0x1e, 0xdd, 0x44, 0xe7, 0xc7, - 0xf1, 0xea, 0x4f, 0xb7, 0xd2, 0x65, 0xdc, 0x67, 0x2f, 0x20, - 0x4c, 0x3d, 0x0c, 0x81, 0x93, 0x03, 0x89, 0xc1, 0x0b, 0x81, - 0xfb, 0x75, 0xde}, - PKFCompressed, mainNetParams.AddrIDPubKeyHashECDSAV0()), - f: func() (Address, error) { - serializedPubKey := []byte{ - 0x03, 0xe9, 0x25, 0xaa, 0xfc, 0x1e, 0xdd, 0x44, 0xe7, 0xc7, - 0xf1, 0xea, 0x4f, 0xb7, 0xd2, 0x65, 0xdc, 0x67, 0x2f, 0x20, - 0x4c, 0x3d, 0x0c, 0x81, 0x93, 0x03, 0x89, 0xc1, 0x0b, 0x81, - 0xfb, 0x75, 0xde} - return NewAddressSecpPubKey(serializedPubKey, mainNetParams) - }, - net: mainNetParams, - }, - { - name: "mainnet p2pk uncompressed (0x04)", - addr: "DkM3EyZ546GghVSkvzb6J47PvGDyntqiDtFgipQhNj78Xm2mUYRpf", - encoded: "DsfFjaADsV8c5oHWx85ZqfxCZy74K8RFuhK", - valid: true, - saddr: "0264c44653d6567eff5753c5d24a682ddc2b2cadfe1b0c6433b16374dace6778f0", - result: tstAddressPubKey( - []byte{ - 0x04, 0x64, 0xc4, 0x46, 0x53, 0xd6, 0x56, 0x7e, 0xff, 0x57, - 0x53, 0xc5, 0xd2, 0x4a, 0x68, 0x2d, 0xdc, 0x2b, 0x2c, 0xad, - 0xfe, 0x1b, 0x0c, 0x64, 0x33, 0xb1, 0x63, 0x74, 0xda, 0xce, - 0x67, 0x78, 0xf0, 0xb8, 0x7c, 0xa4, 0x27, 0x9b, 0x56, 0x5d, - 0x21, 0x30, 0xce, 0x59, 0xf7, 0x5b, 0xfb, 0xb2, 0xb8, 0x8d, - 0xa7, 0x94, 0x14, 0x3d, 0x7c, 0xfd, 0x3e, 0x80, 0x80, 0x8a, - 0x1f, 0xa3, 0x20, 0x39, 0x04}, - PKFUncompressed, mainNetParams.AddrIDPubKeyHashECDSAV0()), - f: func() (Address, error) { - serializedPubKey := []byte{ - 0x04, 0x64, 0xc4, 0x46, 0x53, 0xd6, 0x56, 0x7e, 0xff, 0x57, - 0x53, 0xc5, 0xd2, 0x4a, 0x68, 0x2d, 0xdc, 0x2b, 0x2c, 0xad, - 0xfe, 0x1b, 0x0c, 0x64, 0x33, 0xb1, 0x63, 0x74, 0xda, 0xce, - 0x67, 0x78, 0xf0, 0xb8, 0x7c, 0xa4, 0x27, 0x9b, 0x56, 0x5d, - 0x21, 0x30, 0xce, 0x59, 0xf7, 0x5b, 0xfb, 0xb2, 0xb8, 0x8d, - 0xa7, 0x94, 0x14, 0x3d, 0x7c, 0xfd, 0x3e, 0x80, 0x80, 0x8a, - 0x1f, 0xa3, 0x20, 0x39, 0x04} - return NewAddressSecpPubKey(serializedPubKey, mainNetParams) - }, - net: mainNetParams, - }, - { - name: "testnet p2pk compressed (0x02)", - addr: "Tso9sQD3ALqRsmEkAm7KvPrkGbeG2Vun7Kv", - encoded: "Tso9sQD3ALqRsmEkAm7KvPrkGbeG2Vun7Kv", - valid: true, - result: tstAddressPubKey( - []byte{ - 0x02, 0x6a, 0x40, 0xc4, 0x03, 0xe7, 0x46, 0x70, 0xc4, 0xde, - 0x76, 0x56, 0xa0, 0x9c, 0xaa, 0x23, 0x53, 0xd4, 0xb3, 0x83, - 0xa9, 0xce, 0x66, 0xee, 0xf5, 0x1e, 0x12, 0x20, 0xea, 0xcf, - 0x4b, 0xe0, 0x6e}, - PKFCompressed, testNetParams.AddrIDPubKeyHashECDSAV0()), - f: func() (Address, error) { - serializedPubKey := []byte{ - 0x02, 0x6a, 0x40, 0xc4, 0x03, 0xe7, 0x46, 0x70, 0xc4, 0xde, - 0x76, 0x56, 0xa0, 0x9c, 0xaa, 0x23, 0x53, 0xd4, 0xb3, 0x83, - 0xa9, 0xce, 0x66, 0xee, 0xf5, 0x1e, 0x12, 0x20, 0xea, 0xcf, - 0x4b, 0xe0, 0x6e} - return NewAddressSecpPubKey(serializedPubKey, testNetParams) - }, - net: testNetParams, - }, - { - name: "testnet p2pk compressed (0x03)", - addr: "TsWZ1EzypJfMwBKAEDYKuyHRGctqGAxMje2", - encoded: "TsWZ1EzypJfMwBKAEDYKuyHRGctqGAxMje2", - valid: true, - result: tstAddressPubKey( - []byte{ - 0x03, 0x08, 0x44, 0xee, 0x70, 0xd8, 0x38, 0x4d, 0x52, 0x50, - 0xe9, 0xbb, 0x3a, 0x6a, 0x73, 0xd4, 0xb5, 0xbe, 0xc7, 0x70, - 0xe8, 0xb3, 0x1d, 0x6a, 0x0a, 0xe9, 0xfb, 0x73, 0x90, 0x09, - 0xd9, 0x1a, 0xf5}, - PKFCompressed, testNetParams.AddrIDPubKeyHashECDSAV0()), - f: func() (Address, error) { - serializedPubKey := []byte{ - 0x03, 0x08, 0x44, 0xee, 0x70, 0xd8, 0x38, 0x4d, 0x52, 0x50, - 0xe9, 0xbb, 0x3a, 0x6a, 0x73, 0xd4, 0xb5, 0xbe, 0xc7, 0x70, - 0xe8, 0xb3, 0x1d, 0x6a, 0x0a, 0xe9, 0xfb, 0x73, 0x90, 0x09, - 0xd9, 0x1a, 0xf5} - return NewAddressSecpPubKey(serializedPubKey, testNetParams) - }, - net: testNetParams, - }, - { - name: "testnet p2pk uncompressed (0x04)", - addr: "TkKmMiY5iDh4U3KkSopYgkU1AzhAcQZiSoVhYhFymZHGMi9LM9Fdt", - encoded: "Tso9sQD3ALqRsmEkAm7KvPrkGbeG2Vun7Kv", - valid: true, - saddr: "026a40c403e74670c4de7656a09caa2353d4b383a9ce66eef51e1220eacf4be06e", - result: tstAddressPubKey( - []byte{ - 0x04, 0x6a, 0x40, 0xc4, 0x03, 0xe7, 0x46, 0x70, 0xc4, 0xde, - 0x76, 0x56, 0xa0, 0x9c, 0xaa, 0x23, 0x53, 0xd4, 0xb3, 0x83, - 0xa9, 0xce, 0x66, 0xee, 0xf5, 0x1e, 0x12, 0x20, 0xea, 0xcf, - 0x4b, 0xe0, 0x6e, 0xd5, 0x48, 0xc8, 0xc1, 0x6f, 0xb5, 0xeb, - 0x90, 0x07, 0xcb, 0x94, 0x22, 0x0b, 0x3b, 0xb8, 0x94, 0x91, - 0xd5, 0xa1, 0xfd, 0x2d, 0x77, 0x86, 0x7f, 0xca, 0x64, 0x21, - 0x7a, 0xce, 0xcf, 0x22, 0x44}, - PKFUncompressed, testNetParams.AddrIDPubKeyHashECDSAV0()), - f: func() (Address, error) { - serializedPubKey := []byte{ - 0x04, 0x6a, 0x40, 0xc4, 0x03, 0xe7, 0x46, 0x70, 0xc4, 0xde, - 0x76, 0x56, 0xa0, 0x9c, 0xaa, 0x23, 0x53, 0xd4, 0xb3, 0x83, - 0xa9, 0xce, 0x66, 0xee, 0xf5, 0x1e, 0x12, 0x20, 0xea, 0xcf, - 0x4b, 0xe0, 0x6e, 0xd5, 0x48, 0xc8, 0xc1, 0x6f, 0xb5, 0xeb, - 0x90, 0x07, 0xcb, 0x94, 0x22, 0x0b, 0x3b, 0xb8, 0x94, 0x91, - 0xd5, 0xa1, 0xfd, 0x2d, 0x77, 0x86, 0x7f, 0xca, 0x64, 0x21, - 0x7a, 0xce, 0xcf, 0x22, 0x44} - return NewAddressSecpPubKey(serializedPubKey, testNetParams) - }, - net: testNetParams, - }, - { - name: "regnet p2pk compressed (0x02)", - addr: "RsWUYqptu9hWfQyT8gs4pFd5uhroR5yjiVg", - encoded: "RsWUYqptu9hWfQyT8gs4pFd5uhroR5yjiVg", - valid: true, - result: tstAddressPubKey( - []byte{ - 0x02, 0x6a, 0x40, 0xc4, 0x03, 0xe7, 0x46, 0x70, 0xc4, 0xde, - 0x76, 0x56, 0xa0, 0x9c, 0xaa, 0x23, 0x53, 0xd4, 0xb3, 0x83, - 0xa9, 0xce, 0x66, 0xee, 0xf5, 0x1e, 0x12, 0x20, 0xea, 0xcf, - 0x4b, 0xe0, 0x6e}, - PKFCompressed, regNetParams.AddrIDPubKeyHashECDSAV0()), - f: func() (Address, error) { - serializedPubKey := []byte{ - 0x02, 0x6a, 0x40, 0xc4, 0x03, 0xe7, 0x46, 0x70, 0xc4, 0xde, - 0x76, 0x56, 0xa0, 0x9c, 0xaa, 0x23, 0x53, 0xd4, 0xb3, 0x83, - 0xa9, 0xce, 0x66, 0xee, 0xf5, 0x1e, 0x12, 0x20, 0xea, 0xcf, - 0x4b, 0xe0, 0x6e} - return NewAddressSecpPubKey(serializedPubKey, regNetParams) - }, - net: regNetParams, - }, - { - name: "regnet p2pk compressed (0x03)", - addr: "RsDsggcqZ7XSiq3sC9J4oq3kuj7NefnBshc", - encoded: "RsDsggcqZ7XSiq3sC9J4oq3kuj7NefnBshc", - valid: true, - result: tstAddressPubKey( - []byte{ - 0x03, 0x08, 0x44, 0xee, 0x70, 0xd8, 0x38, 0x4d, 0x52, 0x50, - 0xe9, 0xbb, 0x3a, 0x6a, 0x73, 0xd4, 0xb5, 0xbe, 0xc7, 0x70, - 0xe8, 0xb3, 0x1d, 0x6a, 0x0a, 0xe9, 0xfb, 0x73, 0x90, 0x09, - 0xd9, 0x1a, 0xf5}, - PKFCompressed, regNetParams.AddrIDPubKeyHashECDSAV0()), - f: func() (Address, error) { - serializedPubKey := []byte{ - 0x03, 0x08, 0x44, 0xee, 0x70, 0xd8, 0x38, 0x4d, 0x52, 0x50, - 0xe9, 0xbb, 0x3a, 0x6a, 0x73, 0xd4, 0xb5, 0xbe, 0xc7, 0x70, - 0xe8, 0xb3, 0x1d, 0x6a, 0x0a, 0xe9, 0xfb, 0x73, 0x90, 0x09, - 0xd9, 0x1a, 0xf5} - return NewAddressSecpPubKey(serializedPubKey, regNetParams) - }, - net: regNetParams, - }, - - // Negative P2PK tests. - { - name: "mainnet p2pk hybrid (0x06)", - addr: "", - valid: false, - f: func() (Address, error) { - serializedPubKey := []byte{ - 0x06, 0x64, 0xc4, 0x46, 0x53, 0xd6, 0x56, 0x7e, 0xff, 0x57, - 0x53, 0xc5, 0xd2, 0x4a, 0x68, 0x2d, 0xdc, 0x2b, 0x2c, 0xad, - 0xfe, 0x1b, 0x0c, 0x64, 0x33, 0xb1, 0x63, 0x74, 0xda, 0xce, - 0x67, 0x78, 0xf0, 0xb8, 0x7c, 0xa4, 0x27, 0x9b, 0x56, 0x5d, - 0x21, 0x30, 0xce, 0x59, 0xf7, 0x5b, 0xfb, 0xb2, 0xb8, 0x8d, - 0xa7, 0x94, 0x14, 0x3d, 0x7c, 0xfd, 0x3e, 0x80, 0x80, 0x8a, - 0x1f, 0xa3, 0x20, 0x39, 0x04} - return NewAddressSecpPubKey(serializedPubKey, mainNetParams) - }, - net: mainNetParams, - }, - { - name: "mainnet p2pk hybrid (0x07)", - addr: "", - valid: false, - f: func() (Address, error) { - serializedPubKey := []byte{ - 0x07, 0x34, 0x8d, 0x8a, 0xeb, 0x42, 0x53, 0xca, 0x52, 0x45, - 0x6f, 0xe5, 0xda, 0x94, 0xab, 0x12, 0x63, 0xbf, 0xee, 0x16, - 0xbb, 0x81, 0x92, 0x49, 0x7f, 0x66, 0x63, 0x89, 0xca, 0x96, - 0x4f, 0x84, 0x79, 0x83, 0x75, 0x12, 0x9d, 0x79, 0x58, 0x84, - 0x3b, 0x14, 0x25, 0x8b, 0x90, 0x5d, 0xc9, 0x4f, 0xae, 0xd3, - 0x24, 0xdd, 0x8a, 0x9d, 0x67, 0xff, 0xac, 0x8c, 0xc0, 0xa8, - 0x5b, 0xe8, 0x4b, 0xac, 0x5d} - return NewAddressSecpPubKey(serializedPubKey, mainNetParams) - }, - net: mainNetParams, - }, - { - name: "testnet p2pk hybrid (0x06)", - addr: "", - valid: false, - f: func() (Address, error) { - serializedPubKey := []byte{ - 0x06, 0x6a, 0x40, 0xc4, 0x03, 0xe7, 0x46, 0x70, 0xc4, 0xde, - 0x76, 0x56, 0xa0, 0x9c, 0xaa, 0x23, 0x53, 0xd4, 0xb3, 0x83, - 0xa9, 0xce, 0x66, 0xee, 0xf5, 0x1e, 0x12, 0x20, 0xea, 0xcf, - 0x4b, 0xe0, 0x6e, 0xd5, 0x48, 0xc8, 0xc1, 0x6f, 0xb5, 0xeb, - 0x90, 0x07, 0xcb, 0x94, 0x22, 0x0b, 0x3b, 0xb8, 0x94, 0x91, - 0xd5, 0xa1, 0xfd, 0x2d, 0x77, 0x86, 0x7f, 0xca, 0x64, 0x21, - 0x7a, 0xce, 0xcf, 0x22, 0x44} - return NewAddressSecpPubKey(serializedPubKey, testNetParams) - }, - net: testNetParams, - }, - { - name: "testnet p2pk hybrid (0x07)", - addr: "", - valid: false, - f: func() (Address, error) { - serializedPubKey := []byte{ - 0x07, 0xed, 0xd4, 0x07, 0x47, 0xde, 0x90, 0x5a, 0x9b, 0xec, - 0xb1, 0x49, 0x87, 0xa1, 0xa2, 0x6c, 0x1a, 0xdb, 0xd6, 0x17, - 0xc4, 0x5e, 0x15, 0x83, 0xc1, 0x42, 0xa6, 0x35, 0xbf, 0xda, - 0x94, 0x93, 0xdf, 0xa1, 0xc6, 0xd3, 0x67, 0x35, 0x97, 0x49, - 0x65, 0xfe, 0x7b, 0x86, 0x1e, 0x7f, 0x6f, 0xcc, 0x08, 0x7d, - 0xc7, 0xfe, 0x47, 0x38, 0x0f, 0xa8, 0xbd, 0xe0, 0xd9, 0xc3, - 0x22, 0xd5, 0x3c, 0x0e, 0x89} - return NewAddressSecpPubKey(serializedPubKey, testNetParams) - }, - net: testNetParams, - }, - } - - for _, test := range tests { - // Decode addr and compare error against valid. - decoded, err := 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 { - if test.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.Address() - 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 *AddressPubKeyHash: - decoded := base58.Decode(encoded) - saddr = decoded[2 : 2+ripemd160.Size] - - case *AddressScriptHash: - decoded := base58.Decode(encoded) - saddr = decoded[2 : 2+ripemd160.Size] - - case *AddressSecpPubKey: - // Ignore the error here since the script - // address is checked below. - saddr, err = hex.DecodeString(d.String()) - if err != nil { - saddr, _ = hex.DecodeString(test.saddr) - } - - case *AddressEdwardsPubKey: - // Ignore the error here since the script - // address is checked below. - saddr, _ = hex.DecodeString(d.String()) - - case *AddressSecSchnorrPubKey: - // Ignore the error here since the script - // address is checked below. - saddr, _ = hex.DecodeString(d.String()) - } - - // 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 *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 *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 - } - } - } - - 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.ScriptAddress(), test.result.ScriptAddress()) { - t.Errorf("%v: created address does not match expected result \n "+ - " got %x, expected %x", - test.name, addr.ScriptAddress(), test.result.ScriptAddress()) - return - } - } -} diff --git a/dcrutil/example_test.go b/dcrutil/example_test.go index 10f0e9b0b8..5f60479b4b 100644 --- a/dcrutil/example_test.go +++ b/dcrutil/example_test.go @@ -1,4 +1,4 @@ -// Copyright (c) 2015-2020 The Decred developers +// Copyright (c) 2015-2021 The Decred developers // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. @@ -8,7 +8,6 @@ import ( "fmt" "math" - "github.com/decred/dcrd/dcrec" "github.com/decred/dcrd/dcrutil/v4" ) @@ -78,123 +77,3 @@ func ExampleAmount_unitConversions() { // Atom to MicroCoin: 444333222111 μDCR // Atom to Atom: 44433322211100 Atom } - -// mockAddrParams implements the AddressParams interface and is used throughout -// the tests to mock multiple networks. -type mockAddrParams struct { - pubKeyID [2]byte - pkhEcdsaID [2]byte - pkhEd25519ID [2]byte - pkhSchnorrID [2]byte - scriptHashID [2]byte - privKeyID [2]byte -} - -// AddrIDPubKeyV0 returns the magic prefix bytes associated with the mock params -// for version 0 pay-to-pubkey addresses. -// -// This is part of the AddressParams interface. -func (p *mockAddrParams) AddrIDPubKeyV0() [2]byte { - return p.pubKeyID -} - -// AddrIDPubKeyHashECDSAV0 returns the magic prefix bytes associated with the -// mock params for version 0 pay-to-pubkey-hash addresses where the underlying -// pubkey is secp256k1 and the signature algorithm is ECDSA. -// -// This is part of the AddressParams interface. -func (p *mockAddrParams) AddrIDPubKeyHashECDSAV0() [2]byte { - return p.pkhEcdsaID -} - -// AddrIDPubKeyHashEd25519V0 returns the magic prefix bytes associated with the -// mock params for version 0 pay-to-pubkey-hash addresses where the underlying -// pubkey and signature algorithm are Ed25519. -// -// This is part of the AddressParams interface. -func (p *mockAddrParams) AddrIDPubKeyHashEd25519V0() [2]byte { - return p.pkhEd25519ID -} - -// AddrIDPubKeyHashSchnorrV0 returns the magic prefix bytes associated with the -// mock params for version 0 pay-to-pubkey-hash addresses where the underlying -// pubkey is secp256k1 and the signature algorithm is Schnorr. -// -// This is part of the AddressParams interface. -func (p *mockAddrParams) AddrIDPubKeyHashSchnorrV0() [2]byte { - return p.pkhSchnorrID -} - -// AddrIDScriptHashV0 returns the magic prefix bytes associated with the mock -// params for version 0 pay-to-script-hash addresses. -// -// This is part of the AddressParams interface. -func (p *mockAddrParams) AddrIDScriptHashV0() [2]byte { - return p.scriptHashID -} - -// mockMainNetParams returns mock mainnet address parameters to use throughout -// the tests. They match the Decred mainnet params as of the time this comment -// was written. -func mockMainNetParams() *mockAddrParams { - return &mockAddrParams{ - pubKeyID: [2]byte{0x13, 0x86}, // starts with Dk - pkhEcdsaID: [2]byte{0x07, 0x3f}, // starts with Ds - pkhEd25519ID: [2]byte{0x07, 0x1f}, // starts with De - pkhSchnorrID: [2]byte{0x07, 0x01}, // starts with DS - scriptHashID: [2]byte{0x07, 0x1a}, // starts with Dc - privKeyID: [2]byte{0x22, 0xde}, // starts with Pm - } -} - -// This example demonstrates decoding addresses, determining their underlying -// type, and displaying their associated underlying hash160 and digital -// signature algorithm. -func ExampleDecodeAddress() { - // Ordinarily addresses would be read from the user or the result of a - // derivation, but they are hard coded here for the purposes of this - // example. - // - // Also, the caller would ordinarily want to use parameters from chaincfg - // such as chaincfg.MainNetParams(), but mock parameters are used here for - // the purposes of this example to avoid an otherwise unnecessary dependency - // on the chaincfg module. - mainNetParmas := mockMainNetParams() - addrsToDecode := []string{ - "DsRUvfCwTMrKz29dDiQBJhZii9GDN3bVx6Q", // pay-to-pubkey-hash ecdsa - "DSpf9Sru9MarMKQQnuzTiQ9tjWVJA3KSm2d", // pay-to-pubkey-hash schnorr - } - for idx, encodedAddr := range addrsToDecode { - addr, err := dcrutil.DecodeAddress(encodedAddr, mainNetParmas) - if err != nil { - fmt.Println(err) - return - } - fmt.Printf("addr%d hash160: %x\n", idx, *addr.Hash160()) - - // The example addresses are pay-to-pubkey-hash with different signature - // algorithms, so this code is limited to that type - switch a := addr.(type) { - case *dcrutil.AddressPubKeyHash: - // Determine and display the digital signature algorithm. - algo := "unknown" - switch a.DSA() { - case dcrec.STEcdsaSecp256k1: - algo = "ECDSA" - case dcrec.STSchnorrSecp256k1: - algo = "Schnorr" - } - fmt.Printf("addr%d DSA: %v\n", idx, algo) - - default: - fmt.Println("Unexpected test address type") - return - } - } - - // Output: - // addr0 hash160: 05ad744deacf5334671d3e62db86230af1891f71 - // addr0 DSA: ECDSA - // addr1 hash160: e280cb6e66b96679aec288b1fbdbd4db08077a1b - // addr1 DSA: Schnorr -} diff --git a/dcrutil/go.mod b/dcrutil/go.mod index dc03d30dfc..910240f3cf 100644 --- a/dcrutil/go.mod +++ b/dcrutil/go.mod @@ -10,7 +10,11 @@ require ( github.com/decred/dcrd/dcrec v1.0.0 github.com/decred/dcrd/dcrec/edwards/v2 v2.0.1 github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.0-20210127014238-b33b46cf1a24 + github.com/decred/dcrd/txscript/v4 v4.0.0-20210415215133-96b98390a9a9 github.com/decred/dcrd/wire v1.4.0 ) -replace github.com/decred/dcrd/dcrec/secp256k1/v4 => ../dcrec/secp256k1 +replace ( + github.com/decred/dcrd/dcrec/secp256k1/v4 => ../dcrec/secp256k1 + github.com/decred/dcrd/txscript/v4 => ../txscript +) diff --git a/dcrutil/go.sum b/dcrutil/go.sum index 2cef87bb68..5e59b71cc5 100644 --- a/dcrutil/go.sum +++ b/dcrutil/go.sum @@ -2,10 +2,13 @@ github.com/agl/ed25519 v0.0.0-20170116200512-5312a6153412 h1:w1UutsfOrms1J05zt7I github.com/agl/ed25519 v0.0.0-20170116200512-5312a6153412/go.mod h1:WPjqKcmVOxf0XSf3YxCJs6N6AOSrOx3obionmG7T0y0= 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/dchest/siphash v1.2.2/go.mod h1:q+IRvb2gOSrUnYoPqHiyHXS0FOBBOdl6tONBlVnOnt4= github.com/decred/base58 v1.0.3 h1:KGZuh8d1WEMIrK0leQRM47W85KqCAdl2N+uagbctdDI= github.com/decred/base58 v1.0.3/go.mod h1:pXP9cXCfM2sFLb2viz2FNIdeMWmZDBKG3ZBYbiSM78E= github.com/decred/dcrd/chaincfg/chainhash v1.0.2 h1:rt5Vlq/jM3ZawwiacWjPa+smINyLRN07EO0cNBV6DGU= github.com/decred/dcrd/chaincfg/chainhash v1.0.2/go.mod h1:BpbrGgrPTr3YJYRN3Bm+D9NuaFd+zGyNeIKgrhCXK60= +github.com/decred/dcrd/chaincfg/v3 v3.0.0 h1:+TFbu7ZmvBwM+SZz5mrj6cun9ts/6DAL5sqnsaFBHGQ= +github.com/decred/dcrd/chaincfg/v3 v3.0.0/go.mod h1:EspyubQ7D2w6tjP7rBGDIE7OTbuMgBjR2F2kZFnh31A= github.com/decred/dcrd/crypto/blake256 v1.0.0 h1:/8DMNYp9SGi5f0w7uCm6d6M4OU2rGFK09Y2A4Xv7EE0= github.com/decred/dcrd/crypto/blake256 v1.0.0/go.mod h1:sQl2p6Y26YV+ZOcSTP6thNdn47hh8kt6rqSlvmrXFAc= github.com/decred/dcrd/crypto/ripemd160 v1.0.1 h1:TjRL4LfftzTjXzaufov96iDAkbY2R3aTvH2YMYa1IOc= @@ -16,3 +19,4 @@ github.com/decred/dcrd/dcrec/edwards/v2 v2.0.1 h1:V6eqU1crZzuoFT4KG2LhaU5xDSdkHu github.com/decred/dcrd/dcrec/edwards/v2 v2.0.1/go.mod h1:d0H8xGMWbiIQP7gN3v2rByWUcuZPm9YsgmnfoxgbINc= github.com/decred/dcrd/wire v1.4.0 h1:KmSo6eTQIvhXS0fLBQ/l7hG7QLcSJQKSwSyzSqJYDk0= github.com/decred/dcrd/wire v1.4.0/go.mod h1:WxC/0K+cCAnBh+SKsRjIX9YPgvrjhmE+6pZlel1G7Ro= +github.com/decred/slog v1.1.0/go.mod h1:kVXlGnt6DHy2fV5OjSeuvCJ0OmlmTF6LFpEPMu/fOY0= diff --git a/dcrutil/util.go b/dcrutil/util.go index 0357fcf2d9..f1a9733392 100644 --- a/dcrutil/util.go +++ b/dcrutil/util.go @@ -1,5 +1,5 @@ // Copyright (c) 2013, 2014 The btcsuite developers -// Copyright (c) 2015-2020 The Decred developers +// Copyright (c) 2015-2021 The Decred developers // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. @@ -12,21 +12,50 @@ import ( "github.com/decred/dcrd/chaincfg/chainhash" "github.com/decred/dcrd/dcrec/secp256k1/v4/ecdsa" + "github.com/decred/dcrd/txscript/v4/stdaddr" "github.com/decred/dcrd/wire" ) +// AddressParams defines an interface that is used to provide the parameters +// required when encoding and decoding addresses. These values are typically +// well-defined and unique per network. +type AddressParams interface { + // AddrIDPubKeyV0 returns the magic prefix bytes for version 0 pay-to-pubkey + // addresses. + AddrIDPubKeyV0() [2]byte + + // AddrIDPubKeyHashECDSAV0 returns the magic prefix bytes for version 0 + // pay-to-pubkey-hash addresses where the underlying pubkey is secp256k1 and + // the signature algorithm is ECDSA. + AddrIDPubKeyHashECDSAV0() [2]byte + + // AddrIDPubKeyHashEd25519V0 returns the magic prefix bytes for version 0 + // pay-to-pubkey-hash addresses where the underlying pubkey and signature + // algorithm are Ed25519. + AddrIDPubKeyHashEd25519V0() [2]byte + + // AddrIDPubKeyHashSchnorrV0 returns the magic prefix bytes for version 0 + // pay-to-pubkey-hash addresses where the underlying pubkey is secp256k1 and + // the signature algorithm is Schnorr. + AddrIDPubKeyHashSchnorrV0() [2]byte + + // AddrIDScriptHashV0 returns the magic prefix bytes for version 0 + // pay-to-script-hash addresses. + AddrIDScriptHashV0() [2]byte +} + // VerifyMessage verifies that signature is a valid signature of message and was created // using the secp256k1 private key for address. func VerifyMessage(address string, signature string, message string, params AddressParams) error { // Decode the provided address. This also ensures the network encoded with // the address matches the network the server is currently on. - addr, err := DecodeAddress(address, params) + addr, err := stdaddr.DecodeAddress(address, params) if err != nil { return err } // Only P2PKH addresses are valid for signing. - if _, ok := addr.(*AddressPubKeyHash); !ok { + if _, ok := addr.(*stdaddr.AddressPubKeyHashEcdsaSecp256k1V0); !ok { return fmt.Errorf("address is not a pay-to-pubkey-hash address") } @@ -48,19 +77,19 @@ func VerifyMessage(address string, signature string, message string, params Addr } // Reconstruct the address from the recovered pubkey. - var serializedPK []byte + var pkHash []byte if wasCompressed { - serializedPK = pk.SerializeCompressed() + pkHash = stdaddr.Hash160(pk.SerializeCompressed()) } else { - serializedPK = pk.SerializeUncompressed() + pkHash = stdaddr.Hash160(pk.SerializeUncompressed()) } - recoveredAddr, err := NewAddressSecpPubKey(serializedPK, params) + recAddr, err := stdaddr.NewAddressPubKeyHashEcdsaSecp256k1V0(pkHash, params) if err != nil { return err } // Check whether addresses match. - if recoveredAddr.Address() != addr.Address() { + if recAddr.String() != addr.String() { return fmt.Errorf("message not signed by address") } diff --git a/dcrutil/util_test.go b/dcrutil/util_test.go index dbddd82482..b3d56c2571 100644 --- a/dcrutil/util_test.go +++ b/dcrutil/util_test.go @@ -1,4 +1,4 @@ -// Copyright (c) 2020 The Decred developers +// Copyright (c) 2020-2021 The Decred developers // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. @@ -8,6 +8,88 @@ import ( "testing" ) +// mockAddrParams implements the AddressParams interface and is used throughout +// the tests to mock multiple networks. +type mockAddrParams struct { + pubKeyID [2]byte + pkhEcdsaID [2]byte + pkhEd25519ID [2]byte + pkhSchnorrID [2]byte + scriptHashID [2]byte + privKeyID [2]byte +} + +// AddrIDPubKeyV0 returns the magic prefix bytes associated with the mock params +// for version 0 pay-to-pubkey addresses. +// +// This is part of the AddressParams interface. +func (p *mockAddrParams) AddrIDPubKeyV0() [2]byte { + return p.pubKeyID +} + +// AddrIDPubKeyHashECDSAV0 returns the magic prefix bytes associated with the +// mock params for version 0 pay-to-pubkey-hash addresses where the underlying +// pubkey is secp256k1 and the signature algorithm is ECDSA. +// +// This is part of the AddressParams interface. +func (p *mockAddrParams) AddrIDPubKeyHashECDSAV0() [2]byte { + return p.pkhEcdsaID +} + +// AddrIDPubKeyHashEd25519V0 returns the magic prefix bytes associated with the +// mock params for version 0 pay-to-pubkey-hash addresses where the underlying +// pubkey and signature algorithm are Ed25519. +// +// This is part of the AddressParams interface. +func (p *mockAddrParams) AddrIDPubKeyHashEd25519V0() [2]byte { + return p.pkhEd25519ID +} + +// AddrIDPubKeyHashSchnorrV0 returns the magic prefix bytes associated with the +// mock params for version 0 pay-to-pubkey-hash addresses where the underlying +// pubkey is secp256k1 and the signature algorithm is Schnorr. +// +// This is part of the AddressParams interface. +func (p *mockAddrParams) AddrIDPubKeyHashSchnorrV0() [2]byte { + return p.pkhSchnorrID +} + +// AddrIDScriptHashV0 returns the magic prefix bytes associated with the mock +// params for version 0 pay-to-script-hash addresses. +// +// This is part of the AddressParams interface. +func (p *mockAddrParams) AddrIDScriptHashV0() [2]byte { + return p.scriptHashID +} + +// mockMainNetParams returns mock mainnet address parameters to use throughout +// the tests. They match the Decred mainnet params as of the time this comment +// was written. +func mockMainNetParams() *mockAddrParams { + return &mockAddrParams{ + pubKeyID: [2]byte{0x13, 0x86}, // starts with Dk + pkhEcdsaID: [2]byte{0x07, 0x3f}, // starts with Ds + pkhEd25519ID: [2]byte{0x07, 0x1f}, // starts with De + pkhSchnorrID: [2]byte{0x07, 0x01}, // starts with DS + scriptHashID: [2]byte{0x07, 0x1a}, // starts with Dc + privKeyID: [2]byte{0x22, 0xde}, // starts with Pm + } +} + +// mockTestNetParams returns mock testnet address parameters to use throughout +// the tests. They match the Decred mainnet params as of the time this comment +// was written. +func mockTestNetParams() *mockAddrParams { + return &mockAddrParams{ + pubKeyID: [2]byte{0x28, 0xf7}, // starts with Tk + pkhEcdsaID: [2]byte{0x0f, 0x21}, // starts with Ts + pkhEd25519ID: [2]byte{0x0f, 0x01}, // starts with Te + pkhSchnorrID: [2]byte{0x0e, 0xe3}, // starts with TS + scriptHashID: [2]byte{0x0e, 0xfc}, // starts with Tc + privKeyID: [2]byte{0x23, 0x0e}, // starts with Pt + } +} + // TestVerifyMessage ensures the verifying a message works as intended. func TestVerifyMessage(t *testing.T) { mainNetParams := mockMainNetParams() diff --git a/dcrutil/wif.go b/dcrutil/wif.go index 2d606ac6c0..c4204a33de 100644 --- a/dcrutil/wif.go +++ b/dcrutil/wif.go @@ -1,5 +1,5 @@ // Copyright (c) 2013-2016 The btcsuite developers -// Copyright (c) 2015-2020 The Decred developers +// Copyright (c) 2015-2021 The Decred developers // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. @@ -17,11 +17,17 @@ import ( "github.com/decred/dcrd/dcrec/secp256k1/v4" ) -// ErrMalformedPrivateKey describes an error where a WIF-encoded private key -// cannot be decoded due to being improperly formatted. This may occur if -// the byte length is incorrect or an unexpected magic number was -// encountered. -var ErrMalformedPrivateKey = errors.New("malformed private key") +var ( + // ErrMalformedPrivateKey describes an error where a WIF-encoded private key + // cannot be decoded due to being improperly formatted. This may occur if + // the byte length is incorrect or an unexpected magic number was + // encountered. + ErrMalformedPrivateKey = errors.New("malformed private key") + + // ErrChecksumMismatch describes an error where decoding failed due to a bad + // checksum. + ErrChecksumMismatch = errors.New("checksum mismatch") +) // ErrWrongWIFNetwork describes an error in which the provided WIF is not for // the expected network. diff --git a/gcs/go.mod b/gcs/go.mod index 653d40c990..1880bd5ae0 100644 --- a/gcs/go.mod +++ b/gcs/go.mod @@ -7,7 +7,7 @@ require ( github.com/decred/dcrd/blockchain/stake/v4 v4.0.0-20210129192908-660d0518b4cf github.com/decred/dcrd/chaincfg/chainhash v1.0.2 github.com/decred/dcrd/crypto/blake256 v1.0.0 - github.com/decred/dcrd/txscript/v4 v4.0.0-20210330065944-a2366e6e0b3b + github.com/decred/dcrd/txscript/v4 v4.0.0-20210415215133-96b98390a9a9 github.com/decred/dcrd/wire v1.4.0 ) diff --git a/go.mod b/go.mod index 6c8e1ce363..9b2045f559 100644 --- a/go.mod +++ b/go.mod @@ -27,7 +27,7 @@ require ( github.com/decred/dcrd/peer/v3 v3.0.0 github.com/decred/dcrd/rpc/jsonrpc/types/v3 v3.0.0-20210129200153-14fd1a785bf2 github.com/decred/dcrd/rpcclient/v7 v7.0.0-20210129214723-fc227a05904d - github.com/decred/dcrd/txscript/v4 v4.0.0-20210330065944-a2366e6e0b3b + github.com/decred/dcrd/txscript/v4 v4.0.0-20210415215133-96b98390a9a9 github.com/decred/dcrd/wire v1.4.0 github.com/decred/go-socks v1.1.0 github.com/decred/slog v1.2.0 diff --git a/rpcclient/go.mod b/rpcclient/go.mod index 72863a512b..4bffc3e4fd 100644 --- a/rpcclient/go.mod +++ b/rpcclient/go.mod @@ -8,7 +8,7 @@ require ( github.com/decred/dcrd/dcrutil/v4 v4.0.0-20210129181600-6ae0142d3b28 github.com/decred/dcrd/gcs/v3 v3.0.0-20210129195202-a4265d63b619 github.com/decred/dcrd/rpc/jsonrpc/types/v3 v3.0.0-20210129200153-14fd1a785bf2 - github.com/decred/dcrd/txscript/v4 v4.0.0-20210330065944-a2366e6e0b3b + github.com/decred/dcrd/txscript/v4 v4.0.0-20210415215133-96b98390a9a9 github.com/decred/dcrd/wire v1.4.0 github.com/decred/go-socks v1.1.0 github.com/decred/slog v1.1.0