Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 31 additions & 12 deletions internal/staging/stdaddr/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,18 +26,19 @@ implicit depending on the specific concrete encoding of the address.
### Supported Version 0 Addresses

The following table lists the `version 0` address types this package supports
along with whether the type is supported by the staking system, whether it has
an associated `hash160`, and some additional notes and recommendations:

Version 0 Address Type | Staking? | Hash160? | Notes / Recommendations
--------------------------|----------|----------|----------------------------------
p2pk-ecdsa-secp256k1 | N | N | Prefer p2pkh in on-chain txns [1]
p2pk-ed25519 | N | N | Not recommended [2]
p2pk-schnorr-secp256k1 | N | N | Prefer p2pkh, single party [1,3]
**p2pkh-ecdsa-secp256k1** | **Y** | **Y** | **Preferred v0 address**
p2pkh-ed25519 | N | Y | Not recommended [2]
p2pkh-schnorr-secp256k1 | N | Y | Only use with single party [3]
p2sh | Y | Y | -
along with whether the type is supported by the staking system, whether it has a
raw public key that can be obtained, whether it has an associated `hash160`, and
some additional notes and recommendations:

Version 0 Address Type | Staking? | PubKey? | Hash160? | Notes / Recommendations
--------------------------|----------|---------|----------|----------------------------------
p2pk-ecdsa-secp256k1 | N | Y | N | Prefer p2pkh in on-chain txns [1]
p2pk-ed25519 | N | Y | N | Not recommended [2]
p2pk-schnorr-secp256k1 | N | Y | N | Prefer p2pkh, single party [1,3]
**p2pkh-ecdsa-secp256k1** | **Y** | **N** | **Y** | **Preferred v0 address**
p2pkh-ed25519 | N | N | Y | Not recommended [2]
p2pkh-schnorr-secp256k1 | N | N | Y | Only use with single party [3]
p2sh | Y | N | Y | -

Abbreviations:

Expand Down Expand Up @@ -182,6 +183,24 @@ if an address can be converted to its public key hash variant by type asserting
the interface and then convert it by making use of the `AddressPubKeyHash`
method provided by the interface.

### Obtaining Serialized Public Key From Public Key Addresses

When making use of public key addresses, callers often need to obtain the
serialized public key associated with the address for further processing.

This package provides the `SerializedPubKeyer` interface, which is only
implemented by the public key address types, for this purpose. Callers may
determine if a serialized public key can be obtained from an address by type
asserting the interface and then extract it by making use of the
`SerializedPubKey` method provided by the interface.

However, it is also worth noting that merely obtaining the serialized public key
via the generic interface is typically not sufficient on its own for a caller to
be able to work with it since parsing a public key requires knowing what type of
key it is as well. In that case, the caller will likely need to fall back to
type asserting the specific concrete implementation to determine which type of
public key it is dealing with.

### Hash160 Use in Addresses

The term `Hash160` is used as shorthand to refer to a hash that is created via a
Expand Down
6 changes: 6 additions & 0 deletions internal/staging/stdaddr/address.go
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,12 @@ type StakeAddress interface {
PayFromTreasuryScript() (uint16, []byte)
}

// SerializedPubKeyer is an interface for public key addresses that allows the
// serialized public key to be obtained from addresses that involve them.
type SerializedPubKeyer interface {
SerializedPubKey() []byte
}

// AddressPubKeyHasher is an interface for public key addresses that can be
// converted to an address that imposes an encumbrance that requires the public
// key that hashes to a given public key hash along with a valid signature for
Expand Down
40 changes: 40 additions & 0 deletions internal/staging/stdaddr/address_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,7 @@ func TestAddresses(t *testing.T) {
commitScript string // hex-encoded expected vote commitment script
revokeScript string // hex-encoded expected revoke commitment script
trsyScript string // hex-encoded expected pay from treasury script
pubKey string // hex-encoded expected public key
}{{
// ---------------------------------------------------------------------
// Misc decoding error tests.
Expand Down Expand Up @@ -265,6 +266,7 @@ func TestAddresses(t *testing.T) {
decodeErr: nil,
version: 0,
payScript: "21028f53838b7639563f27c94845549a41e5146bcd52e7fef0ea6da143a02b0fe2edac",
pubKey: "028f53838b7639563f27c94845549a41e5146bcd52e7fef0ea6da143a02b0fe2ed",
}, {
name: "mainnet p2pk-ecdsa-secp256k1 compressed (0x03)",
makeAddr: func() (Address, error) {
Expand All @@ -278,6 +280,7 @@ func TestAddresses(t *testing.T) {
decodeErr: nil,
version: 0,
payScript: "2103e925aafc1edd44e7c7f1ea4fb7d265dc672f204c3d0c81930389c10b81fb75deac",
pubKey: "03e925aafc1edd44e7c7f1ea4fb7d265dc672f204c3d0c81930389c10b81fb75de",
}, {
name: "mainnet p2pk-ecdsa-secp256k1 compressed via concrete constructor",
makeAddr: func() (Address, error) {
Expand All @@ -294,6 +297,7 @@ func TestAddresses(t *testing.T) {
decodeErr: nil,
version: 0,
payScript: "21028f53838b7639563f27c94845549a41e5146bcd52e7fef0ea6da143a02b0fe2edac",
pubKey: "028f53838b7639563f27c94845549a41e5146bcd52e7fef0ea6da143a02b0fe2ed",
}, {
name: "mainnet p2pk-ecdsa-secp256k1 compressed from uncompressed via concrete constructor",
makeAddr: func() (Address, error) {
Expand All @@ -312,6 +316,7 @@ func TestAddresses(t *testing.T) {
decodeErr: nil,
version: 0,
payScript: "210264c44653d6567eff5753c5d24a682ddc2b2cadfe1b0c6433b16374dace6778f0ac",
pubKey: "0264c44653d6567eff5753c5d24a682ddc2b2cadfe1b0c6433b16374dace6778f0",
}, {
name: "testnet p2pk-ecdsa-secp256k1 compressed (0x02)",
makeAddr: func() (Address, error) {
Expand All @@ -325,6 +330,7 @@ func TestAddresses(t *testing.T) {
decodeErr: nil,
version: 0,
payScript: "21026a40c403e74670c4de7656a09caa2353d4b383a9ce66eef51e1220eacf4be06eac",
pubKey: "026a40c403e74670c4de7656a09caa2353d4b383a9ce66eef51e1220eacf4be06e",
}, {
name: "testnet p2pk-ecdsa-secp256k1 compressed (0x03)",
makeAddr: func() (Address, error) {
Expand All @@ -338,6 +344,7 @@ func TestAddresses(t *testing.T) {
decodeErr: nil,
version: 0,
payScript: "21030844ee70d8384d5250e9bb3a6a73d4b5bec770e8b31d6a0ae9fb739009d91af5ac",
pubKey: "030844ee70d8384d5250e9bb3a6a73d4b5bec770e8b31d6a0ae9fb739009d91af5",
}, {
name: "testnet p2pk-ecdsa-secp256k1 compressed via concrete constructor",
makeAddr: func() (Address, error) {
Expand All @@ -354,6 +361,7 @@ func TestAddresses(t *testing.T) {
decodeErr: nil,
version: 0,
payScript: "21026a40c403e74670c4de7656a09caa2353d4b383a9ce66eef51e1220eacf4be06eac",
pubKey: "026a40c403e74670c4de7656a09caa2353d4b383a9ce66eef51e1220eacf4be06e",
}, {
name: "testnet p2pk-ecdsa-secp256k1 compressed from uncompressed via concrete constructor",
makeAddr: func() (Address, error) {
Expand All @@ -372,20 +380,23 @@ func TestAddresses(t *testing.T) {
decodeErr: nil,
version: 0,
payScript: "21026a40c403e74670c4de7656a09caa2353d4b383a9ce66eef51e1220eacf4be06eac",
pubKey: "026a40c403e74670c4de7656a09caa2353d4b383a9ce66eef51e1220eacf4be06e",
}, {
name: "regnet p2pk-ecdsa-secp256k1 compressed (0x02)",
addr: "Rk41kKgrecrxQ8bLg8GJm1feMPBFtFeb4rG56tDfMdAtvPy4HneyR",
net: regNetParams,
decodeErr: nil,
version: 0,
payScript: "21026a40c403e74670c4de7656a09caa2353d4b383a9ce66eef51e1220eacf4be06eac",
pubKey: "026a40c403e74670c4de7656a09caa2353d4b383a9ce66eef51e1220eacf4be06e",
}, {
name: "regnet p2pk-ecdsa-secp256k1 compressed (0x03)",
addr: "Rk8HpTQVbFvNQgxK3sPSiks8K1B8wbyYUGM8qABDpWGp63Q5mnG52",
net: regNetParams,
decodeErr: nil,
version: 0,
payScript: "21030844ee70d8384d5250e9bb3a6a73d4b5bec770e8b31d6a0ae9fb739009d91af5ac",
pubKey: "030844ee70d8384d5250e9bb3a6a73d4b5bec770e8b31d6a0ae9fb739009d91af5",
}, {
// ---------------------------------------------------------------------
// Negative P2PK Ed25519 tests.
Expand Down Expand Up @@ -438,6 +449,7 @@ func TestAddresses(t *testing.T) {
decodeErr: nil,
version: 0,
payScript: "20cecc1507dc1ddd7295951c290888f095adb9044d1b73d696e6df065d683bd4fc51be",
pubKey: "cecc1507dc1ddd7295951c290888f095adb9044d1b73d696e6df065d683bd4fc",
}, {
name: "mainnet p2pk-ed25519 via concrete constructor",
makeAddr: func() (Address, error) {
Expand All @@ -455,6 +467,7 @@ func TestAddresses(t *testing.T) {
decodeErr: nil,
version: 0,
payScript: "20cecc1507dc1ddd7295951c290888f095adb9044d1b73d696e6df065d683bd4fc51be",
pubKey: "cecc1507dc1ddd7295951c290888f095adb9044d1b73d696e6df065d683bd4fc",
}, {
name: "testnet p2pk-ed25519",
makeAddr: func() (Address, error) {
Expand All @@ -469,6 +482,7 @@ func TestAddresses(t *testing.T) {
decodeErr: nil,
version: 0,
payScript: "20cecc1507dc1ddd7295951c290888f095adb9044d1b73d696e6df065d683bd4fc51be",
pubKey: "cecc1507dc1ddd7295951c290888f095adb9044d1b73d696e6df065d683bd4fc",
}, {
name: "testnet p2pk-ed25519 via concrete constructor",
makeAddr: func() (Address, error) {
Expand All @@ -486,6 +500,7 @@ func TestAddresses(t *testing.T) {
decodeErr: nil,
version: 0,
payScript: "20cecc1507dc1ddd7295951c290888f095adb9044d1b73d696e6df065d683bd4fc51be",
pubKey: "cecc1507dc1ddd7295951c290888f095adb9044d1b73d696e6df065d683bd4fc",
}, {
name: "regnet p2pk-ed25519",
makeAddr: func() (Address, error) {
Expand All @@ -500,6 +515,7 @@ func TestAddresses(t *testing.T) {
decodeErr: nil,
version: 0,
payScript: "20cecc1507dc1ddd7295951c290888f095adb9044d1b73d696e6df065d683bd4fc51be",
pubKey: "cecc1507dc1ddd7295951c290888f095adb9044d1b73d696e6df065d683bd4fc",
}, {
// ---------------------------------------------------------------------
// Negative P2PK Schnorr secp256k1 tests.
Expand Down Expand Up @@ -582,13 +598,15 @@ func TestAddresses(t *testing.T) {
decodeErr: nil,
version: 0,
payScript: "21028f53838b7639563f27c94845549a41e5146bcd52e7fef0ea6da143a02b0fe2ed52be",
pubKey: "028f53838b7639563f27c94845549a41e5146bcd52e7fef0ea6da143a02b0fe2ed",
}, {
name: "mainnet p2pk-schnorr-secp256k1 compressed (0x03)",
addr: "DkRQx3y6YoJPnMKom23nuDFdfhmEnu8oDLTp4YVyWC6RjND19UxHk",
net: mainNetParams,
decodeErr: nil,
version: 0,
payScript: "2103e925aafc1edd44e7c7f1ea4fb7d265dc672f204c3d0c81930389c10b81fb75de52be",
pubKey: "03e925aafc1edd44e7c7f1ea4fb7d265dc672f204c3d0c81930389c10b81fb75de",
}, {
name: "mainnet p2pk-schnorr-secp256k1 compressed via concrete constructor",
makeAddr: func() (Address, error) {
Expand All @@ -605,6 +623,7 @@ func TestAddresses(t *testing.T) {
decodeErr: nil,
version: 0,
payScript: "21028f53838b7639563f27c94845549a41e5146bcd52e7fef0ea6da143a02b0fe2ed52be",
pubKey: "028f53838b7639563f27c94845549a41e5146bcd52e7fef0ea6da143a02b0fe2ed",
}, {
name: "mainnet p2pk-schnorr-secp256k1 compressed from uncompressed via concrete constructor",
makeAddr: func() (Address, error) {
Expand All @@ -623,34 +642,39 @@ func TestAddresses(t *testing.T) {
decodeErr: nil,
version: 0,
payScript: "21028f53838b7639563f27c94845549a41e5146bcd52e7fef0ea6da143a02b0fe2ed52be",
pubKey: "028f53838b7639563f27c94845549a41e5146bcd52e7fef0ea6da143a02b0fe2ed",
}, {
name: "testnet p2pk-schnorr-secp256k1 compressed (0x02)",
addr: "TkKqFCtYcHPupVbPcDdhvkNeNYXPqqs88Z4ygukH9MGaNV8e1WWhX",
net: testNetParams,
decodeErr: nil,
version: 0,
payScript: "21026a40c403e74670c4de7656a09caa2353d4b383a9ce66eef51e1220eacf4be06e52be",
pubKey: "026a40c403e74670c4de7656a09caa2353d4b383a9ce66eef51e1220eacf4be06e",
}, {
name: "testnet p2pk-schnorr-secp256k1 compressed (0x03)",
addr: "TkQ7KLcBYvTKq3xMyxkqtVa8LAXGuCC5XyA3RBhqcENVY8ZiDjuAB",
net: testNetParams,
decodeErr: nil,
version: 0,
payScript: "21030844ee70d8384d5250e9bb3a6a73d4b5bec770e8b31d6a0ae9fb739009d91af552be",
pubKey: "030844ee70d8384d5250e9bb3a6a73d4b5bec770e8b31d6a0ae9fb739009d91af5",
}, {
name: "regnet p2pk-schnorr-secp256k1 compressed (0x02)",
addr: "Rk45dp3KYgZokaryqY5U11aHYw1V7gwzkbqMF6hxjRACwAxDivM6N",
net: regNetParams,
decodeErr: nil,
version: 0,
payScript: "21026a40c403e74670c4de7656a09caa2353d4b383a9ce66eef51e1220eacf4be06e52be",
pubKey: "026a40c403e74670c4de7656a09caa2353d4b383a9ce66eef51e1220eacf4be06e",
}, {
name: "regnet p2pk-schnorr-secp256k1 compressed (0x03)",
addr: "Rk8MhwkxVKdDm9DxDHCbxkmmWZ1NB3GxA1vQyNfXCJG86pPPnnn9M",
net: regNetParams,
decodeErr: nil,
version: 0,
payScript: "21030844ee70d8384d5250e9bb3a6a73d4b5bec770e8b31d6a0ae9fb739009d91af552be",
pubKey: "030844ee70d8384d5250e9bb3a6a73d4b5bec770e8b31d6a0ae9fb739009d91af5",
}, {
// ---------------------------------------------------------------------
// Negative P2PKH ECDSA secp256k1 tests.
Expand Down Expand Up @@ -1196,6 +1220,22 @@ func TestAddresses(t *testing.T) {
continue
}

// Ensure the method to get the serialized public key for the addresses
// that support it returns the expected value.
if pubKeyer, ok := decodedAddr.(SerializedPubKeyer); ok {
wantPubKey, err := hex.DecodeString(test.pubKey)
if err != nil {
t.Errorf("%s: unexpected hex decode err: %v", test.name, err)
continue
}
gotPubKey := pubKeyer.SerializedPubKey()
if !bytes.Equal(gotPubKey, wantPubKey) {
t.Errorf("%s: mismatched public key -- got %x, want %x",
test.name, gotPubKey, wantPubKey)
continue
}
}

// Ensure the AddressPubKeyHash method for the address types that
// support it returns the expected address.
var pkhAddr Address
Expand Down
18 changes: 18 additions & 0 deletions internal/staging/stdaddr/addressv0.go
Original file line number Diff line number Diff line change
Expand Up @@ -258,6 +258,12 @@ func (addr *AddressPubKeyEcdsaSecp256k1V0) AddressPubKeyHash() Address {
return addrPKH
}

// SerializedPubKey returns the compressed serialization of the secp256k1 public
// key. The bytes must not be modified.
func (addr *AddressPubKeyEcdsaSecp256k1V0) SerializedPubKey() []byte {
return addr.serializedPubKey
}

// String returns a human-readable string for the address.
//
// This is equivalent to calling Address, but is provided so the type can be
Expand Down Expand Up @@ -373,6 +379,12 @@ func (addr *AddressPubKeyEd25519V0) AddressPubKeyHash() Address {
return addrPKH
}

// SerializedPubKey returns the serialization of the ed25519 public key. The
// bytes must not be modified.
func (addr *AddressPubKeyEd25519V0) SerializedPubKey() []byte {
return addr.serializedPubKey
}

// String returns a human-readable string for the address.
//
// This is equivalent to calling Address, but is provided so the type can be
Expand Down Expand Up @@ -517,6 +529,12 @@ func (addr *AddressPubKeySchnorrSecp256k1V0) AddressPubKeyHash() Address {
return addrPKH
}

// SerializedPubKey returns the compressed serialization of the secp256k1 public
// key. The bytes must not be modified.
func (addr *AddressPubKeySchnorrSecp256k1V0) SerializedPubKey() []byte {
return addr.serializedPubKey
}

// String returns a human-readable string for the address.
//
// This is equivalent to calling Address, but is provided so the type can be
Expand Down