Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

psbt: add support for PSBT_GLOBAL_XPUB type #2296

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
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
96 changes: 86 additions & 10 deletions btcutil/psbt/bip32.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,15 @@ package psbt
import (
"bytes"
"encoding/binary"

"github.com/btcsuite/btcd/btcutil/base58"
"github.com/btcsuite/btcd/btcutil/hdkeychain"
"github.com/btcsuite/btcd/chaincfg/chainhash"
)

const (
// uint32Size is the size of a uint32 in bytes.
uint32Size = 4
)

// Bip32Derivation encapsulates the data for the input and output
Expand Down Expand Up @@ -38,21 +47,23 @@ func (s Bip32Sorter) Less(i, j int) bool {

// 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.
// MasterKeyFingerprint and the remainder of which are the derivation path.
func ReadBip32Derivation(path []byte) (uint32, []uint32, error) {
// BIP-0174 defines the derivation path being encoded as
// "<32-bit uint> <32-bit uint>*"
// with the asterisk meaning 0 to n times. Which in turn means that an
// empty path is valid, only the key fingerprint is mandatory.
if len(path)%4 != 0 {
if len(path)%uint32Size != 0 {
return 0, nil, ErrInvalidPsbtFormat
}

masterKeyInt := binary.LittleEndian.Uint32(path[:4])
masterKeyInt := binary.LittleEndian.Uint32(path[:uint32Size])

var paths []uint32
for i := 4; i < len(path); i += 4 {
paths = append(paths, binary.LittleEndian.Uint32(path[i:i+4]))
for i := uint32Size; i < len(path); i += uint32Size {
paths = append(paths, binary.LittleEndian.Uint32(
path[i:i+uint32Size],
))
}

return masterKeyInt, paths, nil
Expand All @@ -65,16 +76,81 @@ func ReadBip32Derivation(path []byte) (uint32, []uint32, error) {
func SerializeBIP32Derivation(masterKeyFingerprint uint32,
bip32Path []uint32) []byte {

var masterKeyBytes [4]byte
var masterKeyBytes [uint32Size]byte
binary.LittleEndian.PutUint32(masterKeyBytes[:], masterKeyFingerprint)

derivationPath := make([]byte, 0, 4+4*len(bip32Path))
derivationPath := make([]byte, 0, uint32Size+uint32Size*len(bip32Path))
derivationPath = append(derivationPath, masterKeyBytes[:]...)
for _, path := range bip32Path {
var pathbytes [4]byte
binary.LittleEndian.PutUint32(pathbytes[:], path)
derivationPath = append(derivationPath, pathbytes[:]...)
var pathBytes [uint32Size]byte
binary.LittleEndian.PutUint32(pathBytes[:], path)
derivationPath = append(derivationPath, pathBytes[:]...)
}

return derivationPath
}

// XPub is a struct that encapsulates an extended public key, as defined in
// BIP-0032.
type XPub struct {
// ExtendedKey is the serialized extended public key as defined in
// BIP-0032.
ExtendedKey []byte

// MasterFingerprint is the fingerprint of the master pubkey.
MasterKeyFingerprint uint32

// Bip32Path is the derivation path of the key, with hardened elements
// having the 0x80000000 offset added, as defined in BIP-0032. The
// number of path elements must match the depth provided in the extended
// public key.
Bip32Path []uint32
}

// ReadXPub deserializes a byte slice containing an extended public key and a
// BIP-0032 derivation path.
func ReadXPub(keyData []byte, path []byte) (*XPub, error) {
xPub, err := DecodeExtendedKey(keyData)
if err != nil {
return nil, ErrInvalidPsbtFormat
}
numPathElements := xPub.Depth()

// The path also contains the master key fingerprint,
expectedSize := int(uint32Size * (numPathElements + 1))
if len(path) != expectedSize {
return nil, ErrInvalidPsbtFormat
}

masterKeyFingerprint, bip32Path, err := ReadBip32Derivation(path)
if err != nil {
return nil, err
}

return &XPub{
ExtendedKey: keyData,
MasterKeyFingerprint: masterKeyFingerprint,
Bip32Path: bip32Path,
}, nil
}

// EncodeExtendedKey serializes an extended key to a byte slice, without the
// checksum.
func EncodeExtendedKey(key *hdkeychain.ExtendedKey) []byte {
serializedKey := key.String()
decodedKey := base58.Decode(serializedKey)
return decodedKey[:len(decodedKey)-uint32Size]
}

// DecodeExtendedKey deserializes an extended key from a byte slice that does
// not contain the checksum.
func DecodeExtendedKey(encodedKey []byte) (*hdkeychain.ExtendedKey, error) {
checkSum := chainhash.DoubleHashB(encodedKey)[:uint32Size]
serializedBytes := append(encodedKey, checkSum...)
xPub, err := hdkeychain.NewKeyFromString(base58.Encode(serializedBytes))
if err != nil {
return nil, err
}

return xPub, nil
}
60 changes: 52 additions & 8 deletions btcutil/psbt/psbt.go
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,13 @@ type Packet struct {
// produced by this PSBT.
Outputs []POutput

// XPubs is a list of extended public keys 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.
XPubs []XPub

// Unknowns are the set of custom types (global only) within this PSBT.
Unknowns []*Unknown
}
Expand All @@ -161,12 +168,14 @@ func NewFromUnsignedTx(tx *wire.MsgTx) (*Packet, error) {

inSlice := make([]PInput, len(tx.TxIn))
outSlice := make([]POutput, len(tx.TxOut))
xPubSlice := make([]XPub, 0)
unknownSlice := make([]*Unknown, 0)

return &Packet{
UnsignedTx: tx,
Inputs: inSlice,
Outputs: outSlice,
XPubs: xPubSlice,
Unknowns: unknownSlice,
}, nil
}
Expand Down Expand Up @@ -230,7 +239,10 @@ func NewFromRawBytes(r io.Reader, b64 bool) (*Packet, error) {

// Next we parse any unknowns that may be present, making sure that we
// break at the separator.
var unknownSlice []*Unknown
var (
xPubSlice []XPub
unknownSlice []*Unknown
)
for {
keyint, keydata, err := getKey(r)
if err != nil {
Expand All @@ -247,14 +259,32 @@ func NewFromRawBytes(r io.Reader, b64 bool) (*Packet, error) {
return nil, err
}

keyintanddata := []byte{byte(keyint)}
keyintanddata = append(keyintanddata, keydata...)

newUnknown := &Unknown{
Key: keyintanddata,
Value: value,
switch GlobalType(keyint) {
case XPubType:
xPub, err := ReadXPub(keydata, value)
if err != nil {
return nil, err
}

// Duplicate keys are not allowed
for _, x := range xPubSlice {
if bytes.Equal(x.ExtendedKey, keyData) {
return nil, ErrDuplicateKey
}
}

xPubSlice = append(xPubSlice, *xPub)

default:
keyintanddata := []byte{byte(keyint)}
keyintanddata = append(keyintanddata, keydata...)

newUnknown := &Unknown{
Key: keyintanddata,
Value: value,
}
unknownSlice = append(unknownSlice, newUnknown)
}
unknownSlice = append(unknownSlice, newUnknown)
}

// Next we parse the INPUT section.
Expand Down Expand Up @@ -286,6 +316,7 @@ func NewFromRawBytes(r io.Reader, b64 bool) (*Packet, error) {
UnsignedTx: msgTx,
Inputs: inSlice,
Outputs: outSlice,
XPubs: xPubSlice,
Unknowns: unknownSlice,
}

Expand Down Expand Up @@ -325,6 +356,19 @@ func (p *Packet) Serialize(w io.Writer) error {
return err
}

// Serialize the global xPubs.
for _, xPub := range p.XPubs {
pathBytes := SerializeBIP32Derivation(
xPub.MasterKeyFingerprint, xPub.Bip32Path,
)
err := serializeKVPairWithType(
w, uint8(XPubType), xPub.ExtendedKey, pathBytes,
)
if err != nil {
return err
}
}

// Unknown is a special case; we don't have a key type, only a key and
// a value field
for _, kv := range p.Unknowns {
Expand Down
4 changes: 4 additions & 0 deletions btcutil/psbt/psbt_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,8 @@ var validPsbtHex = map[int]string{
5: "70736274ff01003f0200000001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000ffffffff010000000000000000036a010000000000000a0f0102030405060708090f0102030405060708090a0b0c0d0e0f0000",
6: "70736274ff01003f0200000001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000ffffffff010000000000000000036a010000000000002206030d097466b7f59162ac4d90bf65f2a31a8bad82fcd22e98138dcf279401939bd104ffffffff0a0f0102030405060708090f0102030405060708090a0b0c0d0e0f0000",
7: "70736274ff01002001000000000100000000000000000d6a0b68656c6c6f20776f726c64000000000000",
8: "70736274ff01005202000000019dfc6628c26c5899fe1bd3dc338665bfd55d7ada10f6220973df2d386dec12760100000000ffffffff01f03dcd1d000000001600147b3a00bfdc14d27795c2b74901d09da6ef133579000000004f01043587cf02da3fd0088000000097048b1ad0445b1ec8275517727c87b4e4ebc18a203ffa0f94c01566bd38e9000351b743887ee1d40dc32a6043724f2d6459b3b5a4d73daec8fbae0472f3bc43e20cd90c6a4fae000080000000804f01043587cf02da3fd00880000001b90452427139cd78c2cff2444be353cd58605e3e513285e528b407fae3f6173503d30a5e97c8adbc557dac2ad9a7e39c1722ebac69e668b6f2667cc1d671c83cab0cd90c6a4fae000080010000800001012b0065cd1d000000002200202c5486126c4978079a814e13715d65f36459e4d6ccaded266d0508645bafa6320105475221029da12cdb5b235692b91536afefe5c91c3ab9473d8e43b533836ab456299c88712103372b34234ed7cf9c1fea5d05d441557927be9542b162eb02e1ab2ce80224c00b52ae2206029da12cdb5b235692b91536afefe5c91c3ab9473d8e43b533836ab456299c887110d90c6a4fae0000800000008000000000220603372b34234ed7cf9c1fea5d05d441557927be9542b162eb02e1ab2ce80224c00b10d90c6a4fae0000800100008000000000002202039eff1f547a1d5f92dfa2ba7af6ac971a4bd03ba4a734b03156a256b8ad3a1ef910ede45cc500000080000000800100008000",
9: "70736274ff01009d0100000002710ea76ab45c5cb6438e607e59cc037626981805ae9e0dfd9089012abb0be5350100000000ffffffff190994d6a8b3c8c82ccbcfb2fba4106aa06639b872a8d447465c0d42588d6d670000000000ffffffff0200e1f505000000001976a914b6bc2c0ee5655a843d79afedd0ccc3f7dd64340988ac605af405000000001600141188ef8e4ce0449eaac8fb141cbf5a1176e6a088000000004f010488b21e039e530cac800000003dbc8a5c9769f031b17e77fea1518603221a18fd18f2b9a54c6c8c1ac75cbc3502f230584b155d1c7f1cd45120a653c48d650b431b67c5b2c13f27d7142037c1691027569c503100008000000080000000800001011f00e1f5050000000016001433b982f91b28f160c920b4ab95e58ce50dda3a4a220203309680f33c7de38ea6a47cd4ecd66f1f5a49747c6ffb8808ed09039243e3ad5c47304402202d704ced830c56a909344bd742b6852dccd103e963bae92d38e75254d2bb424502202d86c437195df46c0ceda084f2a291c3da2d64070f76bf9b90b195e7ef28f77201220603309680f33c7de38ea6a47cd4ecd66f1f5a49747c6ffb8808ed09039243e3ad5c1827569c5031000080000000800000008000000000010000000001011f00e1f50500000000160014388fb944307eb77ef45197d0b0b245e079f011de220202c777161f73d0b7c72b9ee7bde650293d13f095bc7656ad1f525da5fd2e10b11047304402204cb1fb5f869c942e0e26100576125439179ae88dca8a9dc3ba08f7953988faa60220521f49ca791c27d70e273c9b14616985909361e25be274ea200d7e08827e514d01220602c777161f73d0b7c72b9ee7bde650293d13f095bc7656ad1f525da5fd2e10b1101827569c5031000080000000800000008000000000000000000000220202d20ca502ee289686d21815bd43a80637b0698e1fbcdbe4caed445f6c1a0a90ef1827569c50310000800000008000000080000000000400000000",
}

// These are additional valid PSBTs encoded as base64.
Expand All @@ -78,6 +80,8 @@ var validPsbtBase64 = map[int]string{
4: "cHNidP8BAF4CAAAAAZvUh2UjC/mnLmYgAflyVW5U8Mb5f+tWvLVgDYF/aZUmAQAAAAD/////AUjmBSoBAAAAIlEgg2mORYxmZOFZXXXaJZfeHiLul9eY5wbEwKS1qYI810MAAAAAAAEBKwDyBSoBAAAAIlEgwiR++/2SrEf29AuNQtFpF1oZ+p+hDkol1/NetN2FtpJiFcFQkpt0waBJVLeLS2A16XpeB4paDyjsltVHv+6azoA6wG99YgWelJehpKJnVp2YdtpgEBr/OONSm5uTnOf5GulwEV8uSQr3zEXE94UR82BXzlxaXFYyWin7RN/CA/NW4fgjICyxOsaCSN6AaqajZZzzwD62gh0JyBFKToaP696GW7bSrMBCFcFQkpt0waBJVLeLS2A16XpeB4paDyjsltVHv+6azoA6wJfG5v6l/3FP9XJEmZkIEOQG6YqhD1v35fZ4S8HQqabOIyBDILC/FvARtT6nvmFZJKp/J+XSmtIOoRVdhIZ2w7rRsqzAYhXBUJKbdMGgSVS3i0tgNel6XgeKWg8o7JbVR7/ums6AOsDNlw4V9T/AyC+VD9Vg/6kZt2FyvgFzaKiZE68HT0ALCRFfLkkK98xFxPeFEfNgV85cWlxWMlop+0TfwgPzVuH4IyD6D3o87zsdDAps59JuF62gsuXJLRnvrUi0GFnLikUcqazAIRYssTrGgkjegGqmo2Wc88A+toIdCcgRSk6Gj+vehlu20jkBzZcOFfU/wMgvlQ/VYP+pGbdhcr4Bc2iomROvB09ACwl3Ky2nVgAAgAEAAIACAACAAAAAAAAAAAAhFkMgsL8W8BG1Pqe+YVkkqn8n5dKa0g6hFV2EhnbDutGyOQERXy5JCvfMRcT3hRHzYFfOXFpcVjJaKftE38ID81bh+HcrLadWAACAAQAAgAEAAIAAAAAAAAAAACEWUJKbdMGgSVS3i0tgNel6XgeKWg8o7JbVR7/ums6AOsAFAHxGHl0hFvoPejzvOx0MCmzn0m4XraCy5cktGe+tSLQYWcuKRRypOQFvfWIFnpSXoaSiZ1admHbaYBAa/zjjUpubk5zn+RrpcHcrLadWAACAAQAAgAMAAIAAAAAAAAAAAAEXIFCSm3TBoElUt4tLYDXpel4HiloPKOyW1Ue/7prOgDrAARgg8DYuL3Wm9CClvePrIh2WrmcgzyX4GJDJWx13WstRXmUAAQUgESTaeuySzNBslUViZH9DexOLlXIahL4r8idrvdqz5nEhBxEk2nrskszQbJVFYmR/Q3sTi5VyGoS+K/Ina73as+ZxGQB3Ky2nVgAAgAEAAIAAAACAAAAAAAUAAAAA",
5: "cHNidP8BAF4CAAAAASd0Srq/MCf+DWzyOpbu4u+xiO9SMBlUWFiD5ptmJLJCAAAAAAD/////AUjmBSoBAAAAIlEgCoy9yG3hzhwPnK6yLW33ztNoP+Qj4F0eQCqHk0HW9vUAAAAAAAEBKwDyBSoBAAAAIlEgWiws9bUs8x+DrS6Npj/wMYPs2PYJx1EK6KSOA5EKB1chFv40kGTJjW4qhT+jybEr2LMEoZwZXGDvp+4jkwRtP6IyGQB3Ky2nVgAAgAEAAIAAAACAAQAAAAAAAAABFyD+NJBkyY1uKoU/o8mxK9izBKGcGVxg76fuI5MEbT+iMgABBSBQkpt0waBJVLeLS2A16XpeB4paDyjsltVHv+6azoA6wAEGbwLAIiBzblcpAP4SUliaIUPI88efcaBBLSNTr3VelwHHgmlKAqwCwCIgYxxfO1gyuPvev7GXBM7rMjwh9A96JPQ9aO8MwmsSWWmsAcAiIET6pJoDON5IjI3//s37bzKfOAvVZu8gyN9tgT6rHEJzrCEHRPqkmgM43kiMjf/+zftvMp84C9Vm7yDI322BPqscQnM5AfBreYuSoQ7ZqdC7/Trxc6U7FhfaOkFZygCCFs2Fay4Odystp1YAAIABAACAAQAAgAAAAAADAAAAIQdQkpt0waBJVLeLS2A16XpeB4paDyjsltVHv+6azoA6wAUAfEYeXSEHYxxfO1gyuPvev7GXBM7rMjwh9A96JPQ9aO8MwmsSWWk5ARis5AmIl4Xg6nDO67jhyokqenjq7eDy4pbPQ1lhqPTKdystp1YAAIABAACAAgAAgAAAAAADAAAAIQdzblcpAP4SUliaIUPI88efcaBBLSNTr3VelwHHgmlKAjkBKaW0kVCQFi11mv0/4Pk/ozJgVtC0CIy5M8rngmy42Cx3Ky2nVgAAgAEAAIADAACAAAAAAAMAAAAA",
6: "cHNidP8BAF4CAAAAAZvUh2UjC/mnLmYgAflyVW5U8Mb5f+tWvLVgDYF/aZUmAQAAAAD/////AUjmBSoBAAAAIlEgg2mORYxmZOFZXXXaJZfeHiLul9eY5wbEwKS1qYI810MAAAAAAAEBKwDyBSoBAAAAIlEgwiR++/2SrEf29AuNQtFpF1oZ+p+hDkol1/NetN2FtpJBFCyxOsaCSN6AaqajZZzzwD62gh0JyBFKToaP696GW7bSzZcOFfU/wMgvlQ/VYP+pGbdhcr4Bc2iomROvB09ACwlAv4GNl1fW/+tTi6BX+0wfxOD17xhudlvrVkeR4Cr1/T1eJVHU404z2G8na4LJnHmu0/A5Wgge/NLMLGXdfmk9eUEUQyCwvxbwEbU+p75hWSSqfyfl0prSDqEVXYSGdsO60bIRXy5JCvfMRcT3hRHzYFfOXFpcVjJaKftE38ID81bh+EDh8atvq/omsjbyGDNxncHUKKt2jYD5H5mI2KvvR7+4Y7sfKlKfdowV8AzjTsKDzcB+iPhCi+KPbvZAQ8MpEYEaQRT6D3o87zsdDAps59JuF62gsuXJLRnvrUi0GFnLikUcqW99YgWelJehpKJnVp2YdtpgEBr/OONSm5uTnOf5GulwQOwfA3kgZGHIM0IoVCMyZwirAx8NpKJT7kWq+luMkgNNi2BUkPjNE+APmJmJuX4hX6o28S3uNpPS2szzeBwXV/ZiFcFQkpt0waBJVLeLS2A16XpeB4paDyjsltVHv+6azoA6wG99YgWelJehpKJnVp2YdtpgEBr/OONSm5uTnOf5GulwEV8uSQr3zEXE94UR82BXzlxaXFYyWin7RN/CA/NW4fgjICyxOsaCSN6AaqajZZzzwD62gh0JyBFKToaP696GW7bSrMBCFcFQkpt0waBJVLeLS2A16XpeB4paDyjsltVHv+6azoA6wJfG5v6l/3FP9XJEmZkIEOQG6YqhD1v35fZ4S8HQqabOIyBDILC/FvARtT6nvmFZJKp/J+XSmtIOoRVdhIZ2w7rRsqzAYhXBUJKbdMGgSVS3i0tgNel6XgeKWg8o7JbVR7/ums6AOsDNlw4V9T/AyC+VD9Vg/6kZt2FyvgFzaKiZE68HT0ALCRFfLkkK98xFxPeFEfNgV85cWlxWMlop+0TfwgPzVuH4IyD6D3o87zsdDAps59JuF62gsuXJLRnvrUi0GFnLikUcqazAIRYssTrGgkjegGqmo2Wc88A+toIdCcgRSk6Gj+vehlu20jkBzZcOFfU/wMgvlQ/VYP+pGbdhcr4Bc2iomROvB09ACwl3Ky2nVgAAgAEAAIACAACAAAAAAAAAAAAhFkMgsL8W8BG1Pqe+YVkkqn8n5dKa0g6hFV2EhnbDutGyOQERXy5JCvfMRcT3hRHzYFfOXFpcVjJaKftE38ID81bh+HcrLadWAACAAQAAgAEAAIAAAAAAAAAAACEWUJKbdMGgSVS3i0tgNel6XgeKWg8o7JbVR7/ums6AOsAFAHxGHl0hFvoPejzvOx0MCmzn0m4XraCy5cktGe+tSLQYWcuKRRypOQFvfWIFnpSXoaSiZ1admHbaYBAa/zjjUpubk5zn+RrpcHcrLadWAACAAQAAgAMAAIAAAAAAAAAAAAEXIFCSm3TBoElUt4tLYDXpel4HiloPKOyW1Ue/7prOgDrAARgg8DYuL3Wm9CClvePrIh2WrmcgzyX4GJDJWx13WstRXmUAAQUgESTaeuySzNBslUViZH9DexOLlXIahL4r8idrvdqz5nEhBxEk2nrskszQbJVFYmR/Q3sTi5VyGoS+K/Ina73as+ZxGQB3Ky2nVgAAgAEAAIAAAACAAAAAAAUAAAAA",
7: "cHNidP8BAFICAAAAAZ38ZijCbFiZ/hvT3DOGZb/VXXraEPYiCXPfLTht7BJ2AQAAAAD/////AfA9zR0AAAAAFgAUezoAv9wU0neVwrdJAdCdpu8TNXkAAAAATwEENYfPAto/0AiAAAAAlwSLGtBEWx7IJ1UXcnyHtOTrwYogP/oPlMAVZr046QADUbdDiH7h1A3DKmBDck8tZFmztaTXPa7I+64EcvO8Q+IM2QxqT64AAIAAAACATwEENYfPAto/0AiAAAABuQRSQnE5zXjCz/JES+NTzVhgXj5RMoXlKLQH+uP2FzUD0wpel8itvFV9rCrZp+OcFyLrrGnmaLbyZnzB1nHIPKsM2QxqT64AAIABAACAAAEBKwBlzR0AAAAAIgAgLFSGEmxJeAeagU4TcV1l82RZ5NbMre0mbQUIZFuvpjIBBUdSIQKdoSzbWyNWkrkVNq/v5ckcOrlHPY5DtTODarRWKZyIcSEDNys0I07Xz5wf6l0F1EFVeSe+lUKxYusC4ass6AIkwAtSriIGAp2hLNtbI1aSuRU2r+/lyRw6uUc9jkO1M4NqtFYpnIhxENkMak+uAACAAAAAgAAAAAAiBgM3KzQjTtfPnB/qXQXUQVV5J76VQrFi6wLhqyzoAiTACxDZDGpPrgAAgAEAAIAAAAAAACICA57/H1R6HV+S36K6evaslxpL0DukpzSwMVaiVritOh75EO3kXMUAAACAAAAAgAEAAIAA",
8: "cHNidP8BAJ0BAAAAAnEOp2q0XFy2Q45gflnMA3YmmBgFrp4N/ZCJASq7C+U1AQAAAAD/////GQmU1qizyMgsy8+y+6QQaqBmObhyqNRHRlwNQliNbWcAAAAAAP////8CAOH1BQAAAAAZdqkUtrwsDuVlWoQ9ea/t0MzD991kNAmIrGBa9AUAAAAAFgAUEYjvjkzgRJ6qyPsUHL9aEXbmoIgAAAAATwEEiLIeA55TDKyAAAAAPbyKXJdp8DGxfnf+oVGGAyIaGP0Y8rmlTGyMGsdcvDUC8jBYSxVdHH8c1FEgplPEjWULQxtnxbLBPyfXFCA3wWkQJ1acUDEAAIAAAACAAAAAgAABAR8A4fUFAAAAABYAFDO5gvkbKPFgySC0q5XljOUN2jpKIgIDMJaA8zx9446mpHzU7NZvH1pJdHxv+4gI7QkDkkPjrVxHMEQCIC1wTO2DDFapCTRL10K2hS3M0QPpY7rpLTjnUlTSu0JFAiAthsQ3GV30bAztoITyopHD2i1kBw92v5uQsZXn7yj3cgEiBgMwloDzPH3jjqakfNTs1m8fWkl0fG/7iAjtCQOSQ+OtXBgnVpxQMQAAgAAAAIAAAACAAAAAAAEAAAAAAQEfAOH1BQAAAAAWABQ4j7lEMH63fvRRl9CwskXgefAR3iICAsd3Fh9z0LfHK57nveZQKT0T8JW8dlatH1Jdpf0uELEQRzBEAiBMsftfhpyULg4mEAV2ElQ5F5rojcqKncO6CPeVOYj6pgIgUh9JynkcJ9cOJzybFGFphZCTYeJb4nTqIA1+CIJ+UU0BIgYCx3cWH3PQt8crnue95lApPRPwlbx2Vq0fUl2l/S4QsRAYJ1acUDEAAIAAAACAAAAAgAAAAAAAAAAAAAAiAgLSDKUC7iiWhtIYFb1DqAY3sGmOH7zb5MrtRF9sGgqQ7xgnVpxQMQAAgAAAAIAAAACAAAAAAAQAAAAA",
}

// These are all invalid PSBTs for the indicated reasons.
Expand Down
16 changes: 8 additions & 8 deletions btcutil/psbt/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,22 +13,22 @@ const (
// invalid.
UnsignedTxType GlobalType = 0

// XpubType houses a global xpub for the entire PSBT packet.
// 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
// The key ({0x01}|{xpub}) is the 78 byte serialized extended public key
// as defined by BIP-0032. 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.
// 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
// The value is the master key fingerprint as defined by BIP-0032
// 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
// 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
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
Expand Down
Loading