Skip to content

Commit be681c9

Browse files
committed
firmware: append or replace partial sigs to support multisig
1 parent c3430d8 commit be681c9

1 file changed

Lines changed: 37 additions & 7 deletions

File tree

api/firmware/psbt.go

Lines changed: 37 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -595,7 +595,7 @@ func newBTCTxFromPSBT(
595595
}
596596

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

666+
// setPartialSig replaces or adds a partial signature for the given public key,
667+
// depending on whether a partial signature already exists for the key or not.
668+
func setPartialSig(
669+
sig []byte,
670+
psbtInput *psbt.PInput,
671+
pubKey []byte,
672+
sigHash txscript.SigHashType,
673+
) {
674+
for idx, partialSig := range psbtInput.PartialSigs {
675+
if bytes.Equal(partialSig.PubKey, pubKey) {
676+
psbtInput.PartialSigs[idx] = &psbt.PartialSig{
677+
PubKey: pubKey,
678+
Signature: append(sig, byte(sigHash)),
679+
}
680+
681+
return
682+
}
683+
}
684+
psbtInput.PartialSigs = append(
685+
psbtInput.PartialSigs, &psbt.PartialSig{
686+
PubKey: pubKey,
687+
Signature: append(sig, byte(sigHash)),
688+
},
689+
)
690+
}
691+
662692
// BTCSignNeedsNonWitnessUTXOs returns true if the BitBox requires the NON_WITNESS_UTXO fields of
663693
// each PSBT input to be present. They are the previous transactions of the inputs, and the BitBox
664694
// needs them to validate the input amount, unless all inputs are Taproot. This helper function

0 commit comments

Comments
 (0)