Skip to content
Merged
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
44 changes: 37 additions & 7 deletions api/firmware/psbt.go
Original file line number Diff line number Diff line change
Expand Up @@ -595,7 +595,7 @@ func newBTCTxFromPSBT(
}

// BTCSignPSBT signs a PSBT. If `options` is nil, the default options are used. The PSBT input signatures will be
// populated.
// populated. If a (partial) signature for the public key of the device already exists, it will be overwritten.
func (device *Device) BTCSignPSBT(
coin messages.BTCCoin,
psbt_ *psbt.Packet,
Expand Down Expand Up @@ -630,12 +630,16 @@ func (device *Device) BTCSignPSBT(
ourKey := txResult.ourKeys[inputIndex]
switch {
case ourKey.segwit != nil:
psbtInput.PartialSigs = []*psbt.PartialSig{
{
PubKey: ourKey.segwit.PubKey,
Signature: append(signatureDER, byte(txscript.SigHashAll)),
},
}
// Check if we already have a partial signature for this
// public key. If we do, we overwrite it. Duplicate
// entries would lead to an invalid PSBT. Erroring out
// is suboptimal as well, since we've already gone
// through the signing process. It's the caller's
// responsibility to check if this device has already
// signed the PSBT to avoid this behavior.
setPartialSig(
signatureDER, psbtInput, ourKey.segwit.PubKey,
txscript.SigHashAll)
case ourKey.taprootInternal != nil:
psbtInput.TaprootKeySpendSig = signatureCompact
case ourKey.taprootScript != nil:
Expand All @@ -659,6 +663,32 @@ func (device *Device) BTCSignPSBT(
return nil
}

// setPartialSig replaces or adds a partial signature for the given public key,
// depending on whether a partial signature already exists for the key or not.
func setPartialSig(
sig []byte,
psbtInput *psbt.PInput,
pubKey []byte,
sigHash txscript.SigHashType,
) {
for idx, partialSig := range psbtInput.PartialSigs {
if bytes.Equal(partialSig.PubKey, pubKey) {
psbtInput.PartialSigs[idx] = &psbt.PartialSig{
PubKey: pubKey,
Signature: append(sig, byte(sigHash)),
}

return
}
}
psbtInput.PartialSigs = append(
psbtInput.PartialSigs, &psbt.PartialSig{
PubKey: pubKey,
Signature: append(sig, byte(sigHash)),
},
)
}

// BTCSignNeedsNonWitnessUTXOs returns true if the BitBox requires the NON_WITNESS_UTXO fields of
// each PSBT input to be present. They are the previous transactions of the inputs, and the BitBox
// needs them to validate the input amount, unless all inputs are Taproot. This helper function
Expand Down
Loading