psbt: move PSBT keys/type into new file
This commit is contained in:
parent
e17c9730c4
commit
7611eb65d8
2 changed files with 155 additions and 210 deletions
216
psbt/psbt.go
216
psbt/psbt.go
|
@ -21,14 +21,12 @@ import (
|
||||||
"github.com/btcsuite/btcd/wire"
|
"github.com/btcsuite/btcd/wire"
|
||||||
)
|
)
|
||||||
|
|
||||||
// BIP-174 aka PSBT defined values
|
// psbtMagicLength is the length of the magic bytes used to signal the start of
|
||||||
|
// a serialized PSBT packet.
|
||||||
// Key types are currently encoded with single bytes
|
|
||||||
type psbtKeyType = uint8
|
|
||||||
|
|
||||||
const psbtMagicLength = 5
|
const psbtMagicLength = 5
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
// psbtMagic is the separator
|
||||||
psbtMagic = [psbtMagicLength]byte{0x70,
|
psbtMagic = [psbtMagicLength]byte{0x70,
|
||||||
0x73, 0x62, 0x74, 0xff, // = "psbt" + 0xff sep
|
0x73, 0x62, 0x74, 0xff, // = "psbt" + 0xff sep
|
||||||
}
|
}
|
||||||
|
@ -39,30 +37,6 @@ var (
|
||||||
//less than 4M.
|
//less than 4M.
|
||||||
const MaxPsbtValueLength = 4000000
|
const MaxPsbtValueLength = 4000000
|
||||||
|
|
||||||
// The below are the known key types as per the BIP.
|
|
||||||
// Unknown types may be accepted but will not be processed.
|
|
||||||
const (
|
|
||||||
|
|
||||||
// Global known key types
|
|
||||||
PsbtGlobalUnsignedTx psbtKeyType = 0
|
|
||||||
|
|
||||||
// TxIn section known key types
|
|
||||||
PsbtInNonWitnessUtxo psbtKeyType = 0
|
|
||||||
PsbtInWitnessUtxo psbtKeyType = 1
|
|
||||||
PsbtInPartialSig psbtKeyType = 2
|
|
||||||
PsbtInSighashType psbtKeyType = 3
|
|
||||||
PsbtInRedeemScript psbtKeyType = 4
|
|
||||||
PsbtInWitnessScript psbtKeyType = 5
|
|
||||||
PsbtInBip32Derivation psbtKeyType = 6
|
|
||||||
PsbtInFinalScriptSig psbtKeyType = 7
|
|
||||||
PsbtInFinalScriptWitness psbtKeyType = 8
|
|
||||||
|
|
||||||
// TxOut section known key types
|
|
||||||
PsbtOutRedeemScript psbtKeyType = 0
|
|
||||||
PsbtOutWitnessScript psbtKeyType = 1
|
|
||||||
PsbtOutBip32Derivation psbtKeyType = 2
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
|
||||||
// ErrInvalidPsbtFormat is a generic error for any situation in which a
|
// ErrInvalidPsbtFormat is a generic error for any situation in which a
|
||||||
|
@ -130,187 +104,9 @@ var (
|
||||||
ErrUnsupportedScriptType = errors.New("Unsupported script type")
|
ErrUnsupportedScriptType = errors.New("Unsupported script type")
|
||||||
)
|
)
|
||||||
|
|
||||||
func serializeKVpair(w io.Writer, key []byte, value []byte) error {
|
// Unknown is a struct encapsulating a key-value pair for which the key type is
|
||||||
err := wire.WriteVarBytes(w, 0, key)
|
// unknown by this package; these fields are allowed in both the 'Global' and
|
||||||
if err != nil {
|
// the 'Input' section of a PSBT.
|
||||||
return err
|
|
||||||
}
|
|
||||||
err = wire.WriteVarBytes(w, 0, value)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func serializeKVPairWithType(w io.Writer, kt psbtKeyType, keydata []byte,
|
|
||||||
value []byte) error {
|
|
||||||
if keydata == nil {
|
|
||||||
keydata = []byte{}
|
|
||||||
}
|
|
||||||
serializedKey := append([]byte{byte(kt)}, keydata...)
|
|
||||||
return serializeKVpair(w, serializedKey, value)
|
|
||||||
}
|
|
||||||
|
|
||||||
// getKey retrieves a single key - both the key type and the keydata
|
|
||||||
// (if present) from the stream and returns the key type as an integer,
|
|
||||||
// or -1 if the key was of zero length, which is used to indicate the
|
|
||||||
// presence of a separator byte which indicates the end of a given key-
|
|
||||||
// value pair list, and the keydata as a byte slice or nil if none is
|
|
||||||
// present.
|
|
||||||
func getKey(r io.Reader) (int, []byte, error) {
|
|
||||||
|
|
||||||
// For the key, we read the varint separately, instead of
|
|
||||||
// using the available ReadVarBytes, because we have a specific
|
|
||||||
// treatment of 0x00 here:
|
|
||||||
count, err := wire.ReadVarInt(r, 0)
|
|
||||||
if err != nil {
|
|
||||||
return -1, nil, ErrInvalidPsbtFormat
|
|
||||||
}
|
|
||||||
if count == 0 {
|
|
||||||
// separator indicates end of key-value pair list
|
|
||||||
return -1, nil, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// read count bytes, this is the key (including type and any data)
|
|
||||||
var keyintanddata = make([]byte, count)
|
|
||||||
if _, err := io.ReadFull(r, keyintanddata[:]); err != nil {
|
|
||||||
return -1, nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
keyType := int(string(keyintanddata)[0])
|
|
||||||
// Note that the second return value will usually be empty,
|
|
||||||
// since most keys contain no more than the key type byte.
|
|
||||||
if len(keyintanddata) == 1 {
|
|
||||||
return keyType, nil, nil
|
|
||||||
}
|
|
||||||
return keyType, keyintanddata[1:], nil
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// readTxOut is a limited version of wire.readTxOut, because
|
|
||||||
// the latter is not exported.
|
|
||||||
func readTxOut(txout []byte) (*wire.TxOut, error) {
|
|
||||||
if len(txout) < 10 {
|
|
||||||
return nil, ErrInvalidPsbtFormat
|
|
||||||
}
|
|
||||||
valueSer := binary.LittleEndian.Uint64(txout[:8])
|
|
||||||
scriptPubKey := txout[9:]
|
|
||||||
return wire.NewTxOut(int64(valueSer), scriptPubKey), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// PartialSig encapsulate a (BTC public key, ECDSA signature)
|
|
||||||
// pair, note that the fields are stored as byte slices, not
|
|
||||||
// btcec.PublicKey or btcec.Signature (because manipulations will
|
|
||||||
// be with the former not the latter, here); compliance with consensus
|
|
||||||
// serialization is enforced with .checkValid()
|
|
||||||
type PartialSig struct {
|
|
||||||
PubKey []byte
|
|
||||||
Signature []byte
|
|
||||||
}
|
|
||||||
|
|
||||||
// PartialSigSorter implements sort.Interface.
|
|
||||||
type PartialSigSorter []*PartialSig
|
|
||||||
|
|
||||||
func (s PartialSigSorter) Len() int { return len(s) }
|
|
||||||
|
|
||||||
func (s PartialSigSorter) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
|
|
||||||
|
|
||||||
func (s PartialSigSorter) Less(i, j int) bool {
|
|
||||||
return bytes.Compare(s[i].PubKey, s[j].PubKey) < 0
|
|
||||||
}
|
|
||||||
|
|
||||||
// validatePubkey checks if pubKey is *any* valid
|
|
||||||
// pubKey serialization in a Bitcoin context (compressed/uncomp. OK)
|
|
||||||
func validatePubkey(pubKey []byte) bool {
|
|
||||||
_, err := btcec.ParsePubKey(pubKey, btcec.S256())
|
|
||||||
if err != nil {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
// validateSignature checks that the passed byte slice is a valid
|
|
||||||
// DER-encoded ECDSA signature, including the sighash flag.
|
|
||||||
// It does *not* of course validate the signature against any message
|
|
||||||
// or public key.
|
|
||||||
func validateSignature(sig []byte) bool {
|
|
||||||
_, err := btcec.ParseDERSignature(sig, btcec.S256())
|
|
||||||
if err != nil {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
// See above notes (PartialSig, validatePubkey, validateSignature).
|
|
||||||
// NOTE update for Schnorr will be needed here if/when that activates.
|
|
||||||
func (ps *PartialSig) checkValid() bool {
|
|
||||||
return validatePubkey(ps.PubKey) && validateSignature(ps.Signature)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Bip32Derivation encapsulates the data for the input and output
|
|
||||||
// Bip32Derivation key-value fields.
|
|
||||||
type Bip32Derivation struct {
|
|
||||||
PubKey []byte
|
|
||||||
MasterKeyFingerprint uint32
|
|
||||||
Bip32Path []uint32
|
|
||||||
}
|
|
||||||
|
|
||||||
// checkValid ensures that the PubKey in the Bip32Derivation
|
|
||||||
// struct is valid.
|
|
||||||
func (pb *Bip32Derivation) checkValid() bool {
|
|
||||||
return validatePubkey(pb.PubKey)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Bip32Sorter implements sort.Interface.
|
|
||||||
type Bip32Sorter []*Bip32Derivation
|
|
||||||
|
|
||||||
func (s Bip32Sorter) Len() int { return len(s) }
|
|
||||||
|
|
||||||
func (s Bip32Sorter) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
|
|
||||||
|
|
||||||
func (s Bip32Sorter) Less(i, j int) bool {
|
|
||||||
return bytes.Compare(s[i].PubKey, s[j].PubKey) < 0
|
|
||||||
}
|
|
||||||
|
|
||||||
// readBip32Derivation deserializes a byte slice containing
|
|
||||||
// chunks of 4 byte little endian encodings of uint32 values,
|
|
||||||
// the first of which is the masterkeyfingerprint and the remainder
|
|
||||||
// of which are the derivation path.
|
|
||||||
func readBip32Derivation(path []byte) (uint32, []uint32, error) {
|
|
||||||
|
|
||||||
if len(path)%4 != 0 || len(path)/4-1 < 1 {
|
|
||||||
return 0, nil, ErrInvalidPsbtFormat
|
|
||||||
}
|
|
||||||
masterKeyInt := binary.LittleEndian.Uint32(path[:4])
|
|
||||||
paths := make([]uint32, 0)
|
|
||||||
for i := 4; i < len(path); i += 4 {
|
|
||||||
paths = append(paths, binary.LittleEndian.Uint32(path[i:i+4]))
|
|
||||||
}
|
|
||||||
return masterKeyInt, paths, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// SerializeBIP32Derivation takes a master key fingerprint
|
|
||||||
// as defined in BIP32, along with a path specified as a list
|
|
||||||
// of uint32 values, and returns a bytestring specifying the derivation
|
|
||||||
// in the format required by BIP174:
|
|
||||||
// // master key fingerprint (4) || child index (4) || child index (4) || ...
|
|
||||||
func SerializeBIP32Derivation(masterKeyFingerprint uint32,
|
|
||||||
bip32Path []uint32) []byte {
|
|
||||||
derivationPath := make([]byte, 0, 4+4*len(bip32Path))
|
|
||||||
var masterKeyBytes [4]byte
|
|
||||||
binary.LittleEndian.PutUint32(masterKeyBytes[:], masterKeyFingerprint)
|
|
||||||
derivationPath = append(derivationPath, masterKeyBytes[:]...)
|
|
||||||
for _, path := range bip32Path {
|
|
||||||
var pathbytes [4]byte
|
|
||||||
binary.LittleEndian.PutUint32(pathbytes[:], path)
|
|
||||||
derivationPath = append(derivationPath, pathbytes[:]...)
|
|
||||||
}
|
|
||||||
return derivationPath
|
|
||||||
}
|
|
||||||
|
|
||||||
// Unknown is a struct encapsulating a key-value pair for which
|
|
||||||
// the key type is unknown by this package; these fields are allowed
|
|
||||||
// in both the 'Global' and the 'Input' section of a PSBT.
|
|
||||||
type Unknown struct {
|
type Unknown struct {
|
||||||
Key []byte
|
Key []byte
|
||||||
Value []byte
|
Value []byte
|
||||||
|
|
149
psbt/types.go
Normal file
149
psbt/types.go
Normal file
|
@ -0,0 +1,149 @@
|
||||||
|
package psbt
|
||||||
|
|
||||||
|
// GlobalType is the set of types that are used at the global scope level
|
||||||
|
// within the PSBT.
|
||||||
|
type GlobalType uint8
|
||||||
|
|
||||||
|
const (
|
||||||
|
// UnsignedTxType is the global scope key that houses the unsigned
|
||||||
|
// transaction of the PSBT. The value is a transaction in network
|
||||||
|
// serialization. The scriptSigs and witnesses for each input must be
|
||||||
|
// empty. The transaction must be in the old serialization format
|
||||||
|
// (without witnesses). A PSBT must have a transaction, otherwise it is
|
||||||
|
// invalid.
|
||||||
|
UnsignedTxType GlobalType = 0
|
||||||
|
|
||||||
|
// XpubType houses a global xpub for the entire PSBT packet.
|
||||||
|
//
|
||||||
|
// The key ({0x01}|{xpub}) is he 78 byte serialized extended public key
|
||||||
|
// as defined by BIP 32. Extended public keys are those that can be
|
||||||
|
// used to derive public keys used in the inputs and outputs of this
|
||||||
|
// transaction. It should be the public key at the highest hardened
|
||||||
|
// derivation index so that
|
||||||
|
// the unhardened child keys used in the transaction can be derived.
|
||||||
|
//
|
||||||
|
// The value is the master key fingerprint as defined by BIP 32
|
||||||
|
// concatenated with the derivation path of the public key. The
|
||||||
|
// derivation path is represented as 32-bit little endian unsigned
|
||||||
|
// integer indexes concatenated with each other. The number of 32 bit
|
||||||
|
// unsigned integer indexes must match the depth provided in the
|
||||||
|
// extended public key.
|
||||||
|
XpubType GlobalType = 1
|
||||||
|
|
||||||
|
// VersionType houses the global version number of this PSBT. There is
|
||||||
|
// no key (only contains the byte type), then the value if omitted, is
|
||||||
|
// assumed to be zero.
|
||||||
|
VersionType GlobalType = 0xFB
|
||||||
|
|
||||||
|
// ProprietaryGlobalType is used to house any proper chary global-scope
|
||||||
|
// keys within the PSBT.
|
||||||
|
//
|
||||||
|
// The key is ({0xFC}|<prefix>|{subtype}|{key data}) a variable length
|
||||||
|
// identifier prefix, followed by a subtype, followed by the key data
|
||||||
|
// itself.
|
||||||
|
//
|
||||||
|
// The value is any data as defined by the proprietary type user.
|
||||||
|
ProprietaryGlobalType = 0xFC
|
||||||
|
)
|
||||||
|
|
||||||
|
// InputType is the set of types that are defined for each input included
|
||||||
|
// within the PSBT.
|
||||||
|
type InputType uint32
|
||||||
|
|
||||||
|
const (
|
||||||
|
// NonWitnessUtxoType has no key ({0x00}) and houses the transaction in
|
||||||
|
// network serialization format the current input spends from. This
|
||||||
|
// should only be present for inputs which spend non-segwit outputs.
|
||||||
|
// However, if it is unknown whether an input spends a segwit output,
|
||||||
|
// this type should be used. The entire input transaction is needed in
|
||||||
|
// order to be able to verify the values of the input (pre-segwit they
|
||||||
|
// aren't in the signature digest).
|
||||||
|
NonWitnessUtxoType InputType = 0
|
||||||
|
|
||||||
|
// WitnessUtxoType has no key ({0x01}), and houses the entire
|
||||||
|
// transaction output in network serialization which the current input
|
||||||
|
// spends from. This should only be present for inputs which spend
|
||||||
|
// segwit outputs, including P2SH embedded ones (value || script).
|
||||||
|
WitnessUtxoType InputType = 1
|
||||||
|
|
||||||
|
// PartialSigType is used to include a partial signature with key
|
||||||
|
// ({0x02}|{public key}).
|
||||||
|
//
|
||||||
|
// The value is the signature as would be pushed to the stack from a
|
||||||
|
// scriptSig or witness..
|
||||||
|
PartialSigType InputType = 2
|
||||||
|
|
||||||
|
// SighashType is an empty key ({0x03}).
|
||||||
|
//
|
||||||
|
// The value contains the 32-bit unsigned integer specifying the
|
||||||
|
// sighash type to be used for this input. Signatures for this input
|
||||||
|
// must use the sighash type, finalizers must fail to finalize inputs
|
||||||
|
// which have signatures that do not match the specified sighash type.
|
||||||
|
// Signers who cannot produce signatures with the sighash type must not
|
||||||
|
// provide a signature.
|
||||||
|
SighashType InputType = 3
|
||||||
|
|
||||||
|
// RedeemScriptInputType is an empty key ({0x40}).
|
||||||
|
//
|
||||||
|
// The value is the redeem script of the input if present.
|
||||||
|
RedeemScriptInputType InputType = 4
|
||||||
|
|
||||||
|
// WitnessScriptInputType is an empty key ({0x05}).
|
||||||
|
//
|
||||||
|
// The value is the witness script of this input, if it has one.
|
||||||
|
WitnessScriptInputType InputType = 5
|
||||||
|
|
||||||
|
// Bip32DerivationInputType is a type that carries the pubkey along
|
||||||
|
// with the key ({0x06}|{public key}).
|
||||||
|
//
|
||||||
|
// The value is master key fingerprint as defined by BIP 32
|
||||||
|
// concatenated with the derivation path of the public key. The
|
||||||
|
// derivation path is represented as 32 bit unsigned integer indexes
|
||||||
|
// concatenated with each other. Public keys are those that will be
|
||||||
|
// needed to sign this input.
|
||||||
|
Bip32DerivationInputType InputType = 6
|
||||||
|
|
||||||
|
// FinalScriptSigType is an empty key ({0x07}).
|
||||||
|
//
|
||||||
|
// The value contains a fully constructed scriptSig with signatures and
|
||||||
|
// any other scripts necessary for the input to pass validation.
|
||||||
|
FinalScriptSigType InputType = 7
|
||||||
|
|
||||||
|
// FinalScriptWitnessType is an empty key ({0x08}). The value is a
|
||||||
|
// fully constructed scriptWitness with signatures and any other
|
||||||
|
// scripts necessary for the input to pass validation.
|
||||||
|
FinalScriptWitnessType InputType = 8
|
||||||
|
|
||||||
|
// ProprietaryInputType is a custom type for use by devs.
|
||||||
|
//
|
||||||
|
// The key ({0xFC}|<prefix>|{subtype}|{key data}), is a Variable length
|
||||||
|
// identifier prefix, followed by a subtype, followed by the key data
|
||||||
|
// itself.
|
||||||
|
//
|
||||||
|
// The value is any value data as defined by the proprietary type user.
|
||||||
|
ProprietaryInputType InputType = 0xFC
|
||||||
|
)
|
||||||
|
|
||||||
|
// OutputType is the set of types defined per output within the PSBT.
|
||||||
|
type OutputType uint32
|
||||||
|
|
||||||
|
const (
|
||||||
|
// RedeemScriptOutputType is an empty key ({0x00}>
|
||||||
|
//
|
||||||
|
// The value is the redeemScript for this output if it has one.
|
||||||
|
RedeemScriptOutputType OutputType = 0
|
||||||
|
|
||||||
|
// WitnessScriptOutputType is an empty key ({0x01}).
|
||||||
|
//
|
||||||
|
// The value is the witness script of this input, if it has one.
|
||||||
|
WitnessScriptOutputType OutputType = 1
|
||||||
|
|
||||||
|
j // Bip32DerivationOutputType is used to communicate derivation information
|
||||||
|
// needed to spend this output. The key is ({0x02}|{public key}).
|
||||||
|
//
|
||||||
|
// The value is master key fingerprint concatenated with the derivation
|
||||||
|
// path of the public key. The derivation path is represented as 32-bit
|
||||||
|
// little endian unsigned integer indexes concatenated with each other.
|
||||||
|
// Public keys are those needed to spend this output.
|
||||||
|
Bip32DerivationOutputType OutputType = 2
|
||||||
|
)
|
Loading…
Reference in a new issue