mirror of
https://github.com/lightninglabs/loop.git
synced 2026-08-13 12:33:03 +02:00
instantout: validate MuSig2 response dimensions
Check nonce, signature, session, and transaction input counts before indexing signing vectors, returning clear errors for incomplete data.
This commit is contained in:
parent
51eb8f410a
commit
b3776e92f4
2 changed files with 85 additions and 0 deletions
|
|
@ -263,12 +263,31 @@ func (i *InstantOut) signMusig2Tx(ctx context.Context,
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
if tx == nil {
|
||||||
|
return nil, errors.New("transaction is nil")
|
||||||
|
}
|
||||||
|
if len(tx.TxIn) != len(inputs) {
|
||||||
|
return nil, fmt.Errorf("invalid number of transaction inputs: "+
|
||||||
|
"expected %d, got %d", len(inputs), len(tx.TxIn))
|
||||||
|
}
|
||||||
|
if len(musig2sessions) != len(inputs) {
|
||||||
|
return nil, fmt.Errorf("invalid number of MuSig2 sessions: "+
|
||||||
|
"expected %d, got %d", len(inputs), len(musig2sessions))
|
||||||
|
}
|
||||||
|
if len(counterPartyNonces) != len(inputs) {
|
||||||
|
return nil, fmt.Errorf("invalid number of server nonces: "+
|
||||||
|
"expected %d, got %d", len(inputs), len(counterPartyNonces))
|
||||||
|
}
|
||||||
|
|
||||||
prevOutFetcher := inputs.GetPrevoutFetcher()
|
prevOutFetcher := inputs.GetPrevoutFetcher()
|
||||||
sigHashes := txscript.NewTxSigHashes(tx, prevOutFetcher)
|
sigHashes := txscript.NewTxSigHashes(tx, prevOutFetcher)
|
||||||
sigs := make([][]byte, len(inputs))
|
sigs := make([][]byte, len(inputs))
|
||||||
|
|
||||||
for idx, reservation := range inputs {
|
for idx, reservation := range inputs {
|
||||||
|
if musig2sessions[idx] == nil {
|
||||||
|
return nil, fmt.Errorf("MuSig2 session %d is nil", idx)
|
||||||
|
}
|
||||||
|
|
||||||
if !reflect.DeepEqual(tx.TxIn[idx].PreviousOutPoint,
|
if !reflect.DeepEqual(tx.TxIn[idx].PreviousOutPoint,
|
||||||
reservation.Outpoint) {
|
reservation.Outpoint) {
|
||||||
|
|
||||||
|
|
@ -329,8 +348,27 @@ func (i *InstantOut) finalizeMusig2Transaction(ctx context.Context,
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
if tx == nil {
|
||||||
|
return nil, errors.New("transaction is nil")
|
||||||
|
}
|
||||||
|
if len(tx.TxIn) != len(inputs) {
|
||||||
|
return nil, fmt.Errorf("invalid number of transaction inputs: "+
|
||||||
|
"expected %d, got %d", len(inputs), len(tx.TxIn))
|
||||||
|
}
|
||||||
|
if len(musig2Sessions) != len(inputs) {
|
||||||
|
return nil, fmt.Errorf("invalid number of MuSig2 sessions: "+
|
||||||
|
"expected %d, got %d", len(inputs), len(musig2Sessions))
|
||||||
|
}
|
||||||
|
if len(serverSigs) != len(inputs) {
|
||||||
|
return nil, fmt.Errorf("invalid number of server signatures: "+
|
||||||
|
"expected %d, got %d", len(inputs), len(serverSigs))
|
||||||
|
}
|
||||||
|
|
||||||
for idx := range inputs {
|
for idx := range inputs {
|
||||||
|
if musig2Sessions[idx] == nil {
|
||||||
|
return nil, fmt.Errorf("MuSig2 session %d is nil", idx)
|
||||||
|
}
|
||||||
|
|
||||||
haveAllSigs, finalSig, err := signer.MuSig2CombineSig(
|
haveAllSigs, finalSig, err := signer.MuSig2CombineSig(
|
||||||
ctx, musig2Sessions[idx].SessionID,
|
ctx, musig2Sessions[idx].SessionID,
|
||||||
[][]byte{serverSigs[idx]},
|
[][]byte{serverSigs[idx]},
|
||||||
|
|
|
||||||
47
instantout/instantout_test.go
Normal file
47
instantout/instantout_test.go
Normal file
|
|
@ -0,0 +1,47 @@
|
||||||
|
package instantout
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/btcsuite/btcd/btcec/v2"
|
||||||
|
"github.com/btcsuite/btcd/btcutil"
|
||||||
|
"github.com/btcsuite/btcd/wire"
|
||||||
|
"github.com/lightninglabs/loop/instantout/reservation"
|
||||||
|
"github.com/lightningnetwork/lnd/input"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
// TestMuSig2VectorLengthValidation verifies that malformed server-controlled
|
||||||
|
// vectors are rejected before they can be indexed.
|
||||||
|
func TestMuSig2VectorLengthValidation(t *testing.T) {
|
||||||
|
_, pubKey := btcec.PrivKeyFromBytes([]byte{1})
|
||||||
|
instantOut := &InstantOut{
|
||||||
|
Reservations: []*reservation.Reservation{
|
||||||
|
{
|
||||||
|
ClientPubkey: pubKey,
|
||||||
|
ServerPubkey: pubKey,
|
||||||
|
Value: btcutil.Amount(100_000),
|
||||||
|
Expiry: 200,
|
||||||
|
Outpoint: &wire.OutPoint{},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
tx := wire.NewMsgTx(2)
|
||||||
|
tx.AddTxIn(&wire.TxIn{})
|
||||||
|
sessions := []*input.MuSig2SessionInfo{{}}
|
||||||
|
|
||||||
|
require.NotPanics(t, func() {
|
||||||
|
_, err := instantOut.signMusig2Tx(
|
||||||
|
context.Background(), nil, tx, sessions, nil,
|
||||||
|
)
|
||||||
|
require.ErrorContains(t, err, "server nonces")
|
||||||
|
})
|
||||||
|
|
||||||
|
require.NotPanics(t, func() {
|
||||||
|
_, err := instantOut.finalizeMusig2Transaction(
|
||||||
|
context.Background(), nil, sessions, tx, nil,
|
||||||
|
)
|
||||||
|
require.ErrorContains(t, err, "server signatures")
|
||||||
|
})
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue