dcrutil: Disallow creation of hybrid P2PK addrs.

Hybrid pubkeys, which are a relic of OpenSSL used in Bitcoin Core, are
not usable with OP_CHECKSIG and we can potentially prevent creating
unspendable outputs by never allowing the creation of P2PK (or derived
P2PKH) addresses for these pubkeys.
This commit is contained in:
Josh Rickmar 2018-03-20 15:14:02 -04:00
parent 4e01f768cb
commit dcc58786d3
2 changed files with 53 additions and 103 deletions

View File

@ -419,12 +419,12 @@ const (
// PKFCompressed indicates the pay-to-pubkey address format is a
// compressed public key.
PKFCompressed
// PKFHybrid indicates the pay-to-pubkey address format is a hybrid
// public key.
PKFHybrid
)
// 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 {
net *chaincfg.Params
@ -435,8 +435,7 @@ type AddressSecpPubKey struct {
// 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 can be uncompressed, compressed, or
// hybrid.
// parameter must be a valid pubkey and must be uncompressed or compressed.
func NewAddressSecpPubKey(serializedPubKey []byte,
net *chaincfg.Params) (*AddressSecpPubKey, error) {
pubKey, err := chainec.Secp256k1.ParsePubKey(serializedPubKey)
@ -448,12 +447,14 @@ func NewAddressSecpPubKey(serializedPubKey []byte,
// 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.
pkFormat := PKFUncompressed
var pkFormat PubKeyFormat
switch serializedPubKey[0] {
case 0x02, 0x03:
pkFormat = PKFCompressed
case 0x06, 0x07:
pkFormat = PKFHybrid
case 0x04:
pkFormat = PKFUncompressed
default:
return nil, ErrInvalidPubKeyFormat
}
return &AddressSecpPubKey{
@ -475,9 +476,6 @@ func (a *AddressSecpPubKey) serialize() []byte {
case PKFCompressed:
return a.pubKey.SerializeCompressed()
case PKFHybrid:
return a.pubKey.SerializeHybrid()
}
}
@ -671,8 +669,7 @@ type AddressSecSchnorrPubKey struct {
// 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 can be uncompressed, compressed, or
// hybrid.
// parameter must be a valid pubkey and must be compressed.
func NewAddressSecSchnorrPubKey(serializedPubKey []byte,
net *chaincfg.Params) (*AddressSecSchnorrPubKey, error) {
pubKey, err := chainec.SecSchnorr.ParsePubKey(serializedPubKey)

View File

@ -237,7 +237,6 @@ func TestAddresses(t *testing.T) {
},
net: &chaincfg.MainNetParams,
},
// Hybrid, uncompressed and compressed key types are supported, dcrd consensus rules require a compressed key type however.
{
name: "mainnet p2pk uncompressed (0x04)",
addr: "DkM3EyZ546GghVSkvzb6J47PvGDyntqiDtFgipQhNj78Xm2mUYRpf",
@ -267,64 +266,6 @@ func TestAddresses(t *testing.T) {
},
net: &chaincfg.MainNetParams,
},
{
name: "mainnet p2pk hybrid (0x06)",
addr: "DkM3EyZ546GghVSkvzb6J47PvGDyntqiDtFgipQhNj78Xm2mUYRpf",
encoded: "DsfFjaADsV8c5oHWx85ZqfxCZy74K8RFuhK",
valid: true,
saddr: "0264c44653d6567eff5753c5d24a682ddc2b2cadfe1b0c6433b16374dace6778f0",
result: dcrutil.TstAddressPubKey(
[]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},
dcrutil.PKFHybrid, chaincfg.MainNetParams.PubKeyHashAddrID),
f: func() (dcrutil.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 dcrutil.NewAddressSecpPubKey(serializedPubKey, &chaincfg.MainNetParams)
},
net: &chaincfg.MainNetParams,
},
{
name: "mainnet p2pk hybrid (0x07)",
addr: "DkRKh2aTdwjKKL1mkCb2DFp2Hr7SqMyx3zWqNwyc37PYiGpKmGRsi",
encoded: "DskEQZMCs4nifL7wx7iHYGWxMQvR9ThCBKQ",
valid: true,
saddr: "03348d8aeb4253ca52456fe5da94ab1263bfee16bb8192497f666389ca964f8479",
result: dcrutil.TstAddressPubKey(
[]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},
dcrutil.PKFHybrid, chaincfg.MainNetParams.PubKeyHashAddrID),
f: func() (dcrutil.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 dcrutil.NewAddressSecpPubKey(serializedPubKey, &chaincfg.MainNetParams)
},
net: &chaincfg.MainNetParams,
},
{
name: "testnet p2pk compressed (0x02)",
addr: "Tso9sQD3ALqRsmEkAm7KvPrkGbeG2Vun7Kv",
@ -398,22 +339,46 @@ func TestAddresses(t *testing.T) {
},
net: &chaincfg.TestNet2Params,
},
// Negative P2PK tests.
{
name: "testnet p2pk hybrid (0x06)",
addr: "TkKmMiY5iDh4U3KkSopYgkU1AzhAcQZiSoVhYhFymZHGMi9LM9Fdt",
encoded: "Tso9sQD3ALqRsmEkAm7KvPrkGbeG2Vun7Kv",
valid: true,
saddr: "026a40c403e74670c4de7656a09caa2353d4b383a9ce66eef51e1220eacf4be06e",
result: dcrutil.TstAddressPubKey(
[]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},
dcrutil.PKFHybrid, chaincfg.TestNet2Params.PubKeyHashAddrID),
name: "mainnet p2pk hybrid (0x06)",
addr: "",
valid: false,
f: func() (dcrutil.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 dcrutil.NewAddressSecpPubKey(serializedPubKey, &chaincfg.MainNetParams)
},
net: &chaincfg.MainNetParams,
},
{
name: "mainnet p2pk hybrid (0x07)",
addr: "",
valid: false,
f: func() (dcrutil.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 dcrutil.NewAddressSecpPubKey(serializedPubKey, &chaincfg.MainNetParams)
},
net: &chaincfg.MainNetParams,
},
{
name: "testnet p2pk hybrid (0x06)",
addr: "",
valid: false,
f: func() (dcrutil.Address, error) {
serializedPubKey := []byte{
0x06, 0x6a, 0x40, 0xc4, 0x03, 0xe7, 0x46, 0x70, 0xc4, 0xde,
@ -428,21 +393,9 @@ func TestAddresses(t *testing.T) {
net: &chaincfg.TestNet2Params,
},
{
name: "testnet p2pk hybrid (0x07)",
addr: "TkQ5Ax2ieEZpBDA963VDH4y27KMpXtP8qyeykzwBNFocDc8ZKqTGz",
encoded: "TsTFLdM32YVrYsEQDFxo2zmPuKFcFhH5ZT3",
valid: true,
saddr: "03edd40747de905a9becb14987a1a26c1adbd617c45e1583c142a635bfda9493df",
result: dcrutil.TstAddressPubKey(
[]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},
dcrutil.PKFHybrid, chaincfg.TestNet2Params.PubKeyHashAddrID),
name: "testnet p2pk hybrid (0x07)",
addr: "",
valid: false,
f: func() (dcrutil.Address, error) {
serializedPubKey := []byte{
0x07, 0xed, 0xd4, 0x07, 0x47, 0xde, 0x90, 0x5a, 0x9b, 0xec,