psbt: move PSBT keys/type into new file
This commit is contained in:
parent
e17c9730c4
commit
112dd55802
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"
|
||||
)
|
||||
|
||||
// BIP-174 aka PSBT defined values
|
||||
|
||||
// Key types are currently encoded with single bytes
|
||||
type psbtKeyType = uint8
|
||||
|
||||
// psbtMagicLength is the length of the magic bytes used to signal the start of
|
||||
// a serialized PSBT packet.
|
||||
const psbtMagicLength = 5
|
||||
|
||||
var (
|
||||
// psbtMagic is the separator
|
||||
psbtMagic = [psbtMagicLength]byte{0x70,
|
||||
0x73, 0x62, 0x74, 0xff, // = "psbt" + 0xff sep
|
||||
}
|
||||
|
@ -39,30 +37,6 @@ var (
|
|||
//less than 4M.
|
||||
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 (
|
||||
|
||||
// ErrInvalidPsbtFormat is a generic error for any situation in which a
|
||||
|
@ -130,187 +104,9 @@ var (
|
|||
ErrUnsupportedScriptType = errors.New("Unsupported script type")
|
||||
)
|
||||
|
||||
func serializeKVpair(w io.Writer, key []byte, value []byte) error {
|
||||
err := wire.WriteVarBytes(w, 0, key)
|
||||
if err != nil {
|
||||
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.
|
||||
// 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 {
|
||||
Key []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