mirror of
https://github.com/LBRYFoundation/lbcutil.git
synced 2025-08-23 17:47:30 +00:00
Add a new concrete Address for pay-to-pubkey.
This commit adds a new concrete Address interface implementation for pay-to-pubkey addresses. It supports uncompressed, compressed, and hybrid pubkeys. It also provides a convenience method for converting to a pay-to-pubkey-hash address.
This commit is contained in:
parent
de0c59fee1
commit
043e07d57b
1 changed files with 142 additions and 8 deletions
150
address.go
150
address.go
|
@ -7,7 +7,9 @@ package btcutil
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"code.google.com/p/go.crypto/ripemd160"
|
"code.google.com/p/go.crypto/ripemd160"
|
||||||
|
"encoding/hex"
|
||||||
"errors"
|
"errors"
|
||||||
|
"github.com/conformal/btcec"
|
||||||
"github.com/conformal/btcwire"
|
"github.com/conformal/btcwire"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -21,7 +23,7 @@ var (
|
||||||
ErrUnknownIdentifier = errors.New("unknown identifier byte")
|
ErrUnknownIdentifier = errors.New("unknown identifier byte")
|
||||||
)
|
)
|
||||||
|
|
||||||
// checkBitcoinNet returns an error is the bitcoin network is not supported.
|
// checkBitcoinNet returns an error if the bitcoin network is not supported.
|
||||||
func checkBitcoinNet(net btcwire.BitcoinNet) error {
|
func checkBitcoinNet(net btcwire.BitcoinNet) error {
|
||||||
// Check for a valid bitcoin network.
|
// Check for a valid bitcoin network.
|
||||||
if !(net == btcwire.MainNet || net == btcwire.TestNet3) {
|
if !(net == btcwire.MainNet || net == btcwire.TestNet3) {
|
||||||
|
@ -117,13 +119,6 @@ func DecodeAddr(addr string) (Address, error) {
|
||||||
return NewAddressPubKeyHash(decoded[1:ripemd160.Size+1],
|
return NewAddressPubKeyHash(decoded[1:ripemd160.Size+1],
|
||||||
net)
|
net)
|
||||||
|
|
||||||
case 33: // Compressed pubkey
|
|
||||||
fallthrough
|
|
||||||
|
|
||||||
case 65: // Uncompressed pubkey
|
|
||||||
// TODO(jrick)
|
|
||||||
return nil, errors.New("pay-to-pubkey unimplemented")
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return nil, errors.New("decoded address is of unknown size")
|
return nil, errors.New("decoded address is of unknown size")
|
||||||
}
|
}
|
||||||
|
@ -253,3 +248,142 @@ func (a *AddressScriptHash) Net() btcwire.BitcoinNet {
|
||||||
func (a *AddressScriptHash) String() string {
|
func (a *AddressScriptHash) String() string {
|
||||||
return a.EncodeAddress()
|
return a.EncodeAddress()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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
|
||||||
|
|
||||||
|
// PKFHybrid indicates the pay-to-pubkey address format is a hybrid
|
||||||
|
// public key.
|
||||||
|
PKFHybrid
|
||||||
|
)
|
||||||
|
|
||||||
|
// AddressPubKey is an Address for a pay-to-pubkey transaction.
|
||||||
|
type AddressPubKey struct {
|
||||||
|
pubKeyFormat PubKeyFormat
|
||||||
|
pubKey *btcec.PublicKey
|
||||||
|
net btcwire.BitcoinNet
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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. The net parameter must be
|
||||||
|
// btcwire.MainNet or btcwire.TestNet3.
|
||||||
|
func NewAddressPubKey(serializedPubKey []byte, net btcwire.BitcoinNet) (*AddressPubKey, error) {
|
||||||
|
pubKey, err := btcec.ParsePubKey(serializedPubKey, btcec.S256())
|
||||||
|
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:
|
||||||
|
fallthrough
|
||||||
|
case 0x03:
|
||||||
|
pkFormat = PKFCompressed
|
||||||
|
|
||||||
|
case 0x06:
|
||||||
|
fallthrough
|
||||||
|
case 0x07:
|
||||||
|
pkFormat = PKFHybrid
|
||||||
|
}
|
||||||
|
|
||||||
|
ecPubKey := (*btcec.PublicKey)(pubKey)
|
||||||
|
addr := &AddressPubKey{pubKeyFormat: pkFormat, pubKey: ecPubKey, net: net}
|
||||||
|
return addr, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// serialize returns the serialization of the public key according to the
|
||||||
|
// format associated with the address.
|
||||||
|
func (a *AddressPubKey) serialize() []byte {
|
||||||
|
var serializedPubKey []byte
|
||||||
|
switch a.pubKeyFormat {
|
||||||
|
default:
|
||||||
|
fallthrough
|
||||||
|
case PKFUncompressed:
|
||||||
|
serializedPubKey = a.pubKey.SerializeUncompressed()
|
||||||
|
|
||||||
|
case PKFCompressed:
|
||||||
|
serializedPubKey = a.pubKey.SerializeCompressed()
|
||||||
|
|
||||||
|
case PKFHybrid:
|
||||||
|
serializedPubKey = a.pubKey.SerializeHybrid()
|
||||||
|
}
|
||||||
|
|
||||||
|
return serializedPubKey
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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 {
|
||||||
|
var netID byte
|
||||||
|
switch a.net {
|
||||||
|
case btcwire.MainNet:
|
||||||
|
netID = MainNetAddr
|
||||||
|
case btcwire.TestNet3:
|
||||||
|
netID = TestNetAddr
|
||||||
|
}
|
||||||
|
|
||||||
|
return encodeAddress(Hash160(a.serialize()), netID)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Net returns the bitcoin network associated with the pay-to-pubkey address.
|
||||||
|
func (a *AddressPubKey) Net() btcwire.BitcoinNet {
|
||||||
|
return a.net
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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())
|
||||||
|
}
|
||||||
|
|
||||||
|
// PubKeyFormat 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 {
|
||||||
|
// All potential error conditions are already checked, so it's safe to
|
||||||
|
// ignore the error here.
|
||||||
|
addr, _ := NewAddressPubKeyHash(Hash160(a.serialize()), a.net)
|
||||||
|
return addr
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue