From a4814e5ef71397a90eb7cf6a43c224220ca8dc0c Mon Sep 17 00:00:00 2001 From: sufay Date: Thu, 20 Jun 2024 14:04:30 +0800 Subject: [PATCH] add psbt signature verification --- x/btcbridge/keeper/msg_server.go | 3 ++ x/btcbridge/types/signature.go | 62 ++++++++++++++++++++++++++++++-- 2 files changed, 63 insertions(+), 2 deletions(-) diff --git a/x/btcbridge/keeper/msg_server.go b/x/btcbridge/keeper/msg_server.go index e5524fe2..c39a91d0 100644 --- a/x/btcbridge/keeper/msg_server.go +++ b/x/btcbridge/keeper/msg_server.go @@ -178,6 +178,9 @@ func (m msgServer) SubmitWithdrawSignatures(goCtx context.Context, msg *types.Ms } // verify the signatures + if !types.VerifyPsbtSignatures(packet) { + return nil, types.ErrInvalidSignatures + } // Set the signing request status to signed request := m.GetSigningRequest(ctx, msg.Txid) diff --git a/x/btcbridge/types/signature.go b/x/btcbridge/types/signature.go index de9e436d..128f14ea 100644 --- a/x/btcbridge/types/signature.go +++ b/x/btcbridge/types/signature.go @@ -1,6 +1,64 @@ package types -func (m *BitcoinSigningRequest) ValidateSignatures(sigs []string) bool { +import ( + secp256k1 "github.com/btcsuite/btcd/btcec/v2" + "github.com/btcsuite/btcd/btcec/v2/ecdsa" + "github.com/btcsuite/btcd/btcutil/psbt" + "github.com/btcsuite/btcd/txscript" +) - return false +// VerifyPsbtSignatures verifies the signatures of the given psbt +// Note: assume that the psbt is valid and all inputs are native segwit +func VerifyPsbtSignatures(p *psbt.Packet) bool { + // build previous output fetcher + prevOutputFetcher := txscript.NewMultiPrevOutFetcher(nil) + + for i, txIn := range p.UnsignedTx.TxIn { + prevOutput := p.Inputs[i].WitnessUtxo + if prevOutput == nil { + return false + } + + prevOutputFetcher.AddPrevOut(txIn.PreviousOutPoint, prevOutput) + } + + // verify signatures + for i := range p.Inputs { + output := p.Inputs[i].WitnessUtxo + hashType := p.Inputs[i].SighashType + + witness := p.Inputs[i].FinalScriptWitness + if len(witness) < 72+33 { + return false + } + + sigBytes := witness[0 : len(witness)-33] + pkBytes := witness[len(witness)-33:] + + if sigBytes[len(sigBytes)-1] != byte(hashType) { + return false + } + + sig, err := ecdsa.ParseDERSignature(sigBytes[0 : len(sigBytes)-1]) + if err != nil { + return false + } + + pk, err := secp256k1.ParsePubKey(pkBytes) + if err != nil { + return false + } + + sigHash, err := txscript.CalcWitnessSigHash(output.PkScript, txscript.NewTxSigHashes(p.UnsignedTx, prevOutputFetcher), + hashType, p.UnsignedTx, i, output.Value) + if err != nil { + return false + } + + if !sig.Verify(sigHash, pk) { + return false + } + } + + return true }