diff --git a/chancloser.go b/chancloser.go index 4dc28d40..befb6ccd 100644 --- a/chancloser.go +++ b/chancloser.go @@ -589,7 +589,7 @@ func (c *channelCloser) proposeCloseSigned(fee btcutil.Amount) (*lnwire.ClosingS // party responds we'll be able to decide if we've agreed on fees or // not. c.lastFeeProposal = fee - parsedSig, err := lnwire.NewSigFromRawSignature(rawSig) + parsedSig, err := lnwire.NewSigFromSignature(rawSig) if err != nil { return nil, err } diff --git a/contractcourt/htlc_timeout_resolver_test.go b/contractcourt/htlc_timeout_resolver_test.go index 52324698..923fb3ea 100644 --- a/contractcourt/htlc_timeout_resolver_test.go +++ b/contractcourt/htlc_timeout_resolver_test.go @@ -7,6 +7,7 @@ import ( "testing" "time" + "github.com/btcsuite/btcd/btcec" "github.com/btcsuite/btcd/txscript" "github.com/btcsuite/btcd/wire" "github.com/lightningnetwork/lnd/chainntnfs" @@ -15,12 +16,22 @@ import ( "github.com/lightningnetwork/lnd/lnwallet" ) +type dummySignature struct{} + +func (s *dummySignature) Serialize() []byte { + return []byte{} +} + +func (s *dummySignature) Verify(_ []byte, _ *btcec.PublicKey) bool { + return true +} + type mockSigner struct { } func (m *mockSigner) SignOutputRaw(tx *wire.MsgTx, - signDesc *input.SignDescriptor) ([]byte, error) { - return nil, nil + signDesc *input.SignDescriptor) (input.Signature, error) { + return &dummySignature{}, nil } func (m *mockSigner) ComputeInputScript(tx *wire.MsgTx, @@ -145,8 +156,8 @@ func TestHtlcTimeoutResolver(t *testing.T) { timeout: true, txToBroadcast: func() (*wire.MsgTx, error) { witness, err := input.SenderHtlcSpendTimeout( - nil, txscript.SigHashAll, signer, - fakeSignDesc, sweepTx, + &dummySignature{}, txscript.SigHashAll, + signer, fakeSignDesc, sweepTx, ) if err != nil { return nil, err @@ -165,9 +176,9 @@ func TestHtlcTimeoutResolver(t *testing.T) { timeout: false, txToBroadcast: func() (*wire.MsgTx, error) { witness, err := input.ReceiverHtlcSpendRedeem( - nil, txscript.SigHashAll, - fakePreimageBytes, signer, - fakeSignDesc, sweepTx, + &dummySignature{}, txscript.SigHashAll, + fakePreimageBytes, signer, fakeSignDesc, + sweepTx, ) if err != nil { return nil, err diff --git a/discovery/gossiper_test.go b/discovery/gossiper_test.go index f927a960..75d3cef6 100644 --- a/discovery/gossiper_test.go +++ b/discovery/gossiper_test.go @@ -23,6 +23,7 @@ import ( "github.com/go-errors/errors" "github.com/lightningnetwork/lnd/chainntnfs" "github.com/lightningnetwork/lnd/channeldb" + "github.com/lightningnetwork/lnd/input" "github.com/lightningnetwork/lnd/lnpeer" "github.com/lightningnetwork/lnd/lntest/wait" "github.com/lightningnetwork/lnd/lnwire" @@ -96,7 +97,7 @@ type mockSigner struct { } func (n *mockSigner) SignMessage(pubKey *btcec.PublicKey, - msg []byte) (*btcec.Signature, error) { + msg []byte) (input.Signature, error) { if !pubKey.IsEqual(n.privKey.PubKey()) { return nil, fmt.Errorf("unknown public key") diff --git a/fundingmanager.go b/fundingmanager.go index 23126c30..761227c9 100644 --- a/fundingmanager.go +++ b/fundingmanager.go @@ -254,7 +254,8 @@ type fundingConfig struct { // // TODO(roasbeef): should instead pass on this responsibility to a // distinct sub-system? - SignMessage func(pubKey *btcec.PublicKey, msg []byte) (*btcec.Signature, error) + SignMessage func(pubKey *btcec.PublicKey, + msg []byte) (input.Signature, error) // CurrentNodeAnnouncement should return the latest, fully signed node // announcement from the backing Lightning Network node. @@ -1726,7 +1727,7 @@ func (f *fundingManager) continueFundingAccept(resCtx *reservationWithCtx, PendingChannelID: pendingChanID, FundingPoint: *outPoint, } - fundingCreated.CommitSig, err = lnwire.NewSigFromRawSignature(sig) + fundingCreated.CommitSig, err = lnwire.NewSigFromSignature(sig) if err != nil { fndgLog.Errorf("Unable to parse signature: %v", err) f.failFundingFlow(resCtx.peer, pendingChanID, err) @@ -1775,14 +1776,21 @@ func (f *fundingManager) handleFundingCreated(fmsg *fundingCreatedMsg) { fndgLog.Infof("completing pending_id(%x) with ChannelPoint(%v)", pendingChanID[:], fundingOut) + commitSig, err := fmsg.msg.CommitSig.ToSignature() + if err != nil { + fndgLog.Errorf("unable to parse signature: %v", err) + f.failFundingFlow(fmsg.peer, pendingChanID, err) + return + } + // With all the necessary data available, attempt to advance the // funding workflow to the next stage. If this succeeds then the // funding transaction will broadcast after our next message. // CompleteReservationSingle will also mark the channel as 'IsPending' // in the database. - commitSig := fmsg.msg.CommitSig.ToSignatureBytes() completeChan, err := resCtx.reservation.CompleteReservationSingle( - &fundingOut, commitSig) + &fundingOut, commitSig, + ) if err != nil { // TODO(roasbeef): better error logging: peerID, channelID, etc. fndgLog.Errorf("unable to complete single reservation: %v", err) @@ -1837,7 +1845,7 @@ func (f *fundingManager) handleFundingCreated(fmsg *fundingCreatedMsg) { // With their signature for our version of the commitment transaction // verified, we can now send over our signature to the remote peer. _, sig := resCtx.reservation.OurSignatures() - ourCommitSig, err := lnwire.NewSigFromRawSignature(sig) + ourCommitSig, err := lnwire.NewSigFromSignature(sig) if err != nil { fndgLog.Errorf("unable to parse signature: %v", err) f.failFundingFlow(fmsg.peer, pendingChanID, err) @@ -1950,7 +1958,13 @@ func (f *fundingManager) handleFundingSigned(fmsg *fundingSignedMsg) { // The remote peer has responded with a signature for our commitment // transaction. We'll verify the signature for validity, then commit // the state to disk as we can now open the channel. - commitSig := fmsg.msg.CommitSig.ToSignatureBytes() + commitSig, err := fmsg.msg.CommitSig.ToSignature() + if err != nil { + fndgLog.Errorf("Unable to parse signature: %v", err) + f.failFundingFlow(fmsg.peer, pendingChanID, err) + return + } + completeChan, err := resCtx.reservation.CompleteReservation( nil, commitSig, ) diff --git a/fundingmanager_test.go b/fundingmanager_test.go index c7247136..b222bf94 100644 --- a/fundingmanager_test.go +++ b/fundingmanager_test.go @@ -334,7 +334,9 @@ func createTestFundingManager(t *testing.T, privKey *btcec.PrivateKey, Wallet: lnw, Notifier: chainNotifier, FeeEstimator: estimator, - SignMessage: func(pubKey *btcec.PublicKey, msg []byte) (*btcec.Signature, error) { + SignMessage: func(pubKey *btcec.PublicKey, + msg []byte) (input.Signature, error) { + return testSig, nil }, SendAnnouncement: func(msg lnwire.Message, @@ -474,7 +476,7 @@ func recreateAliceFundingManager(t *testing.T, alice *testNode) { Notifier: oldCfg.Notifier, FeeEstimator: oldCfg.FeeEstimator, SignMessage: func(pubKey *btcec.PublicKey, - msg []byte) (*btcec.Signature, error) { + msg []byte) (input.Signature, error) { return testSig, nil }, SendAnnouncement: func(msg lnwire.Message, diff --git a/htlcswitch/mock.go b/htlcswitch/mock.go index cefb673a..c65e5fb0 100644 --- a/htlcswitch/mock.go +++ b/htlcswitch/mock.go @@ -852,7 +852,9 @@ type mockSigner struct { key *btcec.PrivateKey } -func (m *mockSigner) SignOutputRaw(tx *wire.MsgTx, signDesc *input.SignDescriptor) ([]byte, error) { +func (m *mockSigner) SignOutputRaw(tx *wire.MsgTx, + signDesc *input.SignDescriptor) (input.Signature, error) { + amt := signDesc.Output.Value witnessScript := signDesc.WitnessScript privKey := m.key @@ -877,7 +879,7 @@ func (m *mockSigner) SignOutputRaw(tx *wire.MsgTx, signDesc *input.SignDescripto return nil, err } - return sig[:len(sig)-1], nil + return btcec.ParseDERSignature(sig[:len(sig)-1], btcec.S256()) } func (m *mockSigner) ComputeInputScript(tx *wire.MsgTx, signDesc *input.SignDescriptor) (*input.Script, error) { diff --git a/input/script_utils.go b/input/script_utils.go index 56bfbe97..97938ce8 100644 --- a/input/script_utils.go +++ b/input/script_utils.go @@ -28,6 +28,10 @@ var ( type Signature interface { // Serialize returns a DER-encoded ECDSA signature. Serialize() []byte + + // Verify return true if the ECDSA signature is valid for the passed + // message digest under the provided public key. + Verify([]byte, *btcec.PublicKey) bool } // WitnessScriptHash generates a pay-to-witness-script-hash public key script @@ -290,7 +294,7 @@ func SenderHtlcSpendRevokeWithKey(signer Signer, signDesc *SignDescriptor, // manner in order to encode the revocation contract into a sig+key // pair. witnessStack := wire.TxWitness(make([][]byte, 3)) - witnessStack[0] = append(sweepSig, byte(signDesc.HashType)) + witnessStack[0] = append(sweepSig.Serialize(), byte(signDesc.HashType)) witnessStack[1] = revokeKey.SerializeCompressed() witnessStack[2] = signDesc.WitnessScript @@ -339,7 +343,7 @@ func SenderHtlcSpendRedeem(signer Signer, signDesc *SignDescriptor, // generated above under the receiver's public key, and the payment // pre-image. witnessStack := wire.TxWitness(make([][]byte, 3)) - witnessStack[0] = append(sweepSig, byte(signDesc.HashType)) + witnessStack[0] = append(sweepSig.Serialize(), byte(signDesc.HashType)) witnessStack[1] = paymentPreimage witnessStack[2] = signDesc.WitnessScript @@ -367,7 +371,7 @@ func SenderHtlcSpendTimeout(receiverSig Signature, witnessStack := wire.TxWitness(make([][]byte, 5)) witnessStack[0] = nil witnessStack[1] = append(receiverSig.Serialize(), byte(receiverSigHash)) - witnessStack[2] = append(sweepSig, byte(signDesc.HashType)) + witnessStack[2] = append(sweepSig.Serialize(), byte(signDesc.HashType)) witnessStack[3] = nil witnessStack[4] = signDesc.WitnessScript @@ -535,7 +539,7 @@ func ReceiverHtlcSpendRedeem(senderSig Signature, witnessStack := wire.TxWitness(make([][]byte, 5)) witnessStack[0] = nil witnessStack[1] = append(senderSig.Serialize(), byte(senderSigHash)) - witnessStack[2] = append(sweepSig, byte(signDesc.HashType)) + witnessStack[2] = append(sweepSig.Serialize(), byte(signDesc.HashType)) witnessStack[3] = paymentPreimage witnessStack[4] = signDesc.WitnessScript @@ -562,7 +566,7 @@ func ReceiverHtlcSpendRevokeWithKey(signer Signer, signDesc *SignDescriptor, // witness stack in order to force script execution to the HTLC // revocation clause. witnessStack := wire.TxWitness(make([][]byte, 3)) - witnessStack[0] = append(sweepSig, byte(signDesc.HashType)) + witnessStack[0] = append(sweepSig.Serialize(), byte(signDesc.HashType)) witnessStack[1] = revokeKey.SerializeCompressed() witnessStack[2] = signDesc.WitnessScript @@ -627,7 +631,7 @@ func ReceiverHtlcSpendTimeout(signer Signer, signDesc *SignDescriptor, } witnessStack := wire.TxWitness(make([][]byte, 3)) - witnessStack[0] = append(sweepSig, byte(signDesc.HashType)) + witnessStack[0] = append(sweepSig.Serialize(), byte(signDesc.HashType)) witnessStack[1] = nil witnessStack[2] = signDesc.WitnessScript @@ -732,7 +736,7 @@ func HtlcSpendSuccess(signer Signer, signDesc *SignDescriptor, // witness script), in order to force execution to the second portion // of the if clause. witnessStack := wire.TxWitness(make([][]byte, 3)) - witnessStack[0] = append(sweepSig, byte(signDesc.HashType)) + witnessStack[0] = append(sweepSig.Serialize(), byte(signDesc.HashType)) witnessStack[1] = nil witnessStack[2] = signDesc.WitnessScript @@ -757,7 +761,7 @@ func HtlcSpendRevoke(signer Signer, signDesc *SignDescriptor, // witness script), in order to force execution to the revocation // clause in the second level HTLC script. witnessStack := wire.TxWitness(make([][]byte, 3)) - witnessStack[0] = append(sweepSig, byte(signDesc.HashType)) + witnessStack[0] = append(sweepSig.Serialize(), byte(signDesc.HashType)) witnessStack[1] = []byte{1} witnessStack[2] = signDesc.WitnessScript @@ -788,7 +792,7 @@ func HtlcSecondLevelSpend(signer Signer, signDesc *SignDescriptor, // witness script), in order to force execution to the second portion // of the if clause. witnessStack := wire.TxWitness(make([][]byte, 3)) - witnessStack[0] = append(sweepSig, byte(txscript.SigHashAll)) + witnessStack[0] = append(sweepSig.Serialize(), byte(txscript.SigHashAll)) witnessStack[1] = nil witnessStack[2] = signDesc.WitnessScript @@ -892,7 +896,7 @@ func CommitSpendTimeout(signer Signer, signDesc *SignDescriptor, // place an empty byte in order to ensure our script is still valid // from the PoV of nodes that are enforcing minimal OP_IF/OP_NOTIF. witnessStack := wire.TxWitness(make([][]byte, 3)) - witnessStack[0] = append(sweepSig, byte(signDesc.HashType)) + witnessStack[0] = append(sweepSig.Serialize(), byte(signDesc.HashType)) witnessStack[1] = nil witnessStack[2] = signDesc.WitnessScript @@ -917,7 +921,7 @@ func CommitSpendRevoke(signer Signer, signDesc *SignDescriptor, // Place a 1 as the first item in the evaluated witness stack to // force script execution to the revocation clause. witnessStack := wire.TxWitness(make([][]byte, 3)) - witnessStack[0] = append(sweepSig, byte(signDesc.HashType)) + witnessStack[0] = append(sweepSig.Serialize(), byte(signDesc.HashType)) witnessStack[1] = []byte{1} witnessStack[2] = signDesc.WitnessScript @@ -951,7 +955,7 @@ func CommitSpendNoDelay(signer Signer, signDesc *SignDescriptor, // exact same as a regular p2wkh witness, depending on the value of the // tweakless bool. witness := make([][]byte, 2) - witness[0] = append(sweepSig, byte(signDesc.HashType)) + witness[0] = append(sweepSig.Serialize(), byte(signDesc.HashType)) switch tweakless { // If we're tweaking the key, then we use the tweaked public key as the @@ -1028,7 +1032,7 @@ func CommitSpendToRemoteConfirmed(signer Signer, signDesc *SignDescriptor, // Finally, we'll manually craft the witness. The witness here is the // signature and the redeem script. witnessStack := make([][]byte, 2) - witnessStack[0] = append(sweepSig, byte(signDesc.HashType)) + witnessStack[0] = append(sweepSig.Serialize(), byte(signDesc.HashType)) witnessStack[1] = signDesc.WitnessScript return witnessStack, nil @@ -1084,7 +1088,7 @@ func CommitSpendAnchor(signer Signer, signDesc *SignDescriptor, // The witness here is just a signature and the redeem script. witnessStack := make([][]byte, 2) - witnessStack[0] = append(sweepSig, byte(signDesc.HashType)) + witnessStack[0] = append(sweepSig.Serialize(), byte(signDesc.HashType)) witnessStack[1] = signDesc.WitnessScript return witnessStack, nil diff --git a/input/script_utils_test.go b/input/script_utils_test.go index a76183dc..5978d3ee 100644 --- a/input/script_utils_test.go +++ b/input/script_utils_test.go @@ -303,12 +303,14 @@ func TestHTLCSenderSpendValidation(t *testing.T) { SigHashes: sweepTxSigHashes, InputIndex: 0, } - bobSigBytes, err := bobSigner.SignOutputRaw(sweepTx, &bobSignDesc) + bobSig, err := bobSigner.SignOutputRaw(sweepTx, &bobSignDesc) if err != nil { t.Fatalf("unable to generate alice signature: %v", err) } - bobRecvrSig, err = btcec.ParseDERSignature(bobSigBytes, btcec.S256()) + bobRecvrSig, err = btcec.ParseDERSignature( + bobSig.Serialize(), btcec.S256(), + ) if err != nil { t.Fatalf("unable to parse signature: %v", err) } @@ -700,12 +702,14 @@ func TestHTLCReceiverSpendValidation(t *testing.T) { SigHashes: sweepTxSigHashes, InputIndex: 0, } - aliceSigBytes, err := aliceSigner.SignOutputRaw(sweepTx, &aliceSignDesc) + aliceSig, err := aliceSigner.SignOutputRaw(sweepTx, &aliceSignDesc) if err != nil { t.Fatalf("unable to generate alice signature: %v", err) } - aliceSenderSig, err = btcec.ParseDERSignature(aliceSigBytes, btcec.S256()) + aliceSenderSig, err = btcec.ParseDERSignature( + aliceSig.Serialize(), btcec.S256(), + ) if err != nil { t.Fatalf("unable to parse signature: %v", err) } diff --git a/input/signer.go b/input/signer.go index cd320255..86622638 100644 --- a/input/signer.go +++ b/input/signer.go @@ -14,7 +14,8 @@ type Signer interface { // according to the data within the passed SignDescriptor. // // NOTE: The resulting signature should be void of a sighash byte. - SignOutputRaw(tx *wire.MsgTx, signDesc *SignDescriptor) ([]byte, error) + SignOutputRaw(tx *wire.MsgTx, + signDesc *SignDescriptor) (Signature, error) // ComputeInputScript generates a complete InputIndex for the passed // transaction with the signature as defined within the passed diff --git a/input/size.go b/input/size.go index 32a89bcd..74f1247d 100644 --- a/input/size.go +++ b/input/size.go @@ -410,6 +410,14 @@ const ( OfferedHtlcPenaltyWitnessSize = 1 + 1 + 73 + 1 + 33 + 1 + OfferedHtlcScriptSize ) +type dummySignature struct{} + +func (d *dummySignature) Serialize() []byte { + // Always return worst-case signature length, excluding the one byte + // sighash flag. + return make([]byte, 73-1) +} + // dummySigner is a fake signer used for size (upper bound) calculations. type dummySigner struct { Signer @@ -417,12 +425,10 @@ type dummySigner struct { // SignOutputRaw generates a signature for the passed transaction according to // the data within the passed SignDescriptor. -func (s *dummySigner) SignOutputRaw(tx *wire.MsgTx, signDesc *SignDescriptor) ( - []byte, error) { +func (s *dummySigner) SignOutputRaw(tx *wire.MsgTx, + signDesc *SignDescriptor) (Signature, error) { - // Always return worst-case signature length, excluding the one byte - // sighash flag. - return make([]byte, 73-1), nil + return &dummySignature{}, nil } var ( diff --git a/input/test_utils.go b/input/test_utils.go index b9719438..5b004417 100644 --- a/input/test_utils.go +++ b/input/test_utils.go @@ -50,7 +50,9 @@ type MockSigner struct { // SignOutputRaw generates a signature for the passed transaction according to // the data within the passed SignDescriptor. -func (m *MockSigner) SignOutputRaw(tx *wire.MsgTx, signDesc *SignDescriptor) ([]byte, error) { +func (m *MockSigner) SignOutputRaw(tx *wire.MsgTx, + signDesc *SignDescriptor) (Signature, error) { + pubkey := signDesc.KeyDesc.PubKey switch { case signDesc.SingleTweak != nil: @@ -72,7 +74,7 @@ func (m *MockSigner) SignOutputRaw(tx *wire.MsgTx, signDesc *SignDescriptor) ([] return nil, err } - return sig[:len(sig)-1], nil + return btcec.ParseDERSignature(sig[:len(sig)-1], btcec.S256()) } // ComputeInputScript generates a complete InputIndex for the passed transaction diff --git a/lnwallet/btcwallet/signer.go b/lnwallet/btcwallet/signer.go index 35e158c0..a79a5fd9 100644 --- a/lnwallet/btcwallet/signer.go +++ b/lnwallet/btcwallet/signer.go @@ -225,7 +225,7 @@ func maybeTweakPrivKey(signDesc *input.SignDescriptor, // // This is a part of the WalletController interface. func (b *BtcWallet) SignOutputRaw(tx *wire.MsgTx, - signDesc *input.SignDescriptor) ([]byte, error) { + signDesc *input.SignDescriptor) (input.Signature, error) { witnessScript := signDesc.WitnessScript @@ -256,7 +256,7 @@ func (b *BtcWallet) SignOutputRaw(tx *wire.MsgTx, } // Chop off the sighash flag at the end of the signature. - return sig[:len(sig)-1], nil + return btcec.ParseDERSignature(sig[:len(sig)-1], btcec.S256()) } // ComputeInputScript generates a complete InputScript for the passed @@ -358,7 +358,7 @@ var _ input.Signer = (*BtcWallet)(nil) // // NOTE: This is a part of the MessageSigner interface. func (b *BtcWallet) SignMessage(pubKey *btcec.PublicKey, - msg []byte) (*btcec.Signature, error) { + msg []byte) (input.Signature, error) { // First attempt to fetch the private key which corresponds to the // specified public key. diff --git a/lnwallet/channel.go b/lnwallet/channel.go index 11eb1159..33380deb 100644 --- a/lnwallet/channel.go +++ b/lnwallet/channel.go @@ -3402,7 +3402,7 @@ func (lc *LightningChannel) SignNextCommitment() (lnwire.Sig, []lnwire.Sig, []ch close(cancelChan) return sig, htlcSigs, nil, err } - sig, err = lnwire.NewSigFromRawSignature(rawSig) + sig, err = lnwire.NewSigFromSignature(rawSig) if err != nil { close(cancelChan) return sig, htlcSigs, nil, err @@ -5075,7 +5075,7 @@ func (lc *LightningChannel) getSignedCommitTx() (*wire.MsgTx, error) { return nil, err } - ourSig := append(ourSigRaw, byte(txscript.SigHashAll)) + ourSig := append(ourSigRaw.Serialize(), byte(txscript.SigHashAll)) // With the final signature generated, create the witness stack // required to spend from the multi-sig output. @@ -5950,7 +5950,8 @@ func NewLocalForceCloseSummary(chanState *channeldb.OpenChannel, signer input.Si // settle any in flight. func (lc *LightningChannel) CreateCloseProposal(proposedFee btcutil.Amount, localDeliveryScript []byte, - remoteDeliveryScript []byte) ([]byte, *chainhash.Hash, btcutil.Amount, error) { + remoteDeliveryScript []byte) (input.Signature, *chainhash.Hash, + btcutil.Amount, error) { lc.Lock() defer lc.Unlock() diff --git a/lnwallet/channel_test.go b/lnwallet/channel_test.go index c266db1c..8a7711fe 100644 --- a/lnwallet/channel_test.go +++ b/lnwallet/channel_test.go @@ -616,7 +616,7 @@ func TestCooperativeChannelClosure(t *testing.T) { if err != nil { t.Fatalf("unable to create alice coop close proposal: %v", err) } - aliceCloseSig := append(aliceSig, byte(txscript.SigHashAll)) + aliceCloseSig := append(aliceSig.Serialize(), byte(txscript.SigHashAll)) bobFee := bobChannel.CalcFee(bobFeeRate) bobSig, _, _, err := bobChannel.CreateCloseProposal( @@ -625,7 +625,7 @@ func TestCooperativeChannelClosure(t *testing.T) { if err != nil { t.Fatalf("unable to create bob coop close proposal: %v", err) } - bobCloseSig := append(bobSig, byte(txscript.SigHashAll)) + bobCloseSig := append(bobSig.Serialize(), byte(txscript.SigHashAll)) // With the proposals created, both sides should be able to properly // process the other party's signature. This indicates that the @@ -2059,7 +2059,7 @@ func TestCooperativeCloseDustAdherence(t *testing.T) { if err != nil { t.Fatalf("unable to close channel: %v", err) } - aliceCloseSig := append(aliceSig, byte(txscript.SigHashAll)) + aliceCloseSig := append(aliceSig.Serialize(), byte(txscript.SigHashAll)) bobFee := btcutil.Amount(bobChannel.CalcFee(bobFeeRate)) + 1000 bobSig, _, _, err := bobChannel.CreateCloseProposal(bobFee, @@ -2067,7 +2067,7 @@ func TestCooperativeCloseDustAdherence(t *testing.T) { if err != nil { t.Fatalf("unable to close channel: %v", err) } - bobCloseSig := append(bobSig, byte(txscript.SigHashAll)) + bobCloseSig := append(bobSig.Serialize(), byte(txscript.SigHashAll)) closeTx, _, err := bobChannel.CompleteCooperativeClose( bobCloseSig, aliceCloseSig, @@ -2098,14 +2098,14 @@ func TestCooperativeCloseDustAdherence(t *testing.T) { if err != nil { t.Fatalf("unable to close channel: %v", err) } - aliceCloseSig = append(aliceSig, byte(txscript.SigHashAll)) + aliceCloseSig = append(aliceSig.Serialize(), byte(txscript.SigHashAll)) bobSig, _, _, err = bobChannel.CreateCloseProposal(bobFee, bobDeliveryScript, aliceDeliveryScript) if err != nil { t.Fatalf("unable to close channel: %v", err) } - bobCloseSig = append(bobSig, byte(txscript.SigHashAll)) + bobCloseSig = append(bobSig.Serialize(), byte(txscript.SigHashAll)) closeTx, _, err = bobChannel.CompleteCooperativeClose( bobCloseSig, aliceCloseSig, @@ -2141,7 +2141,7 @@ func TestCooperativeCloseDustAdherence(t *testing.T) { if err != nil { t.Fatalf("unable to close channel: %v", err) } - aliceCloseSig = append(aliceSig, byte(txscript.SigHashAll)) + aliceCloseSig = append(aliceSig.Serialize(), byte(txscript.SigHashAll)) bobSig, _, _, err = bobChannel.CreateCloseProposal( bobFee, bobDeliveryScript, aliceDeliveryScript, @@ -2149,7 +2149,7 @@ func TestCooperativeCloseDustAdherence(t *testing.T) { if err != nil { t.Fatalf("unable to close channel: %v", err) } - bobCloseSig = append(bobSig, byte(txscript.SigHashAll)) + bobCloseSig = append(bobSig.Serialize(), byte(txscript.SigHashAll)) closeTx, _, err = bobChannel.CompleteCooperativeClose( bobCloseSig, aliceCloseSig, diff --git a/lnwallet/interface.go b/lnwallet/interface.go index 1c6c2bd7..41052503 100644 --- a/lnwallet/interface.go +++ b/lnwallet/interface.go @@ -10,6 +10,7 @@ import ( "github.com/btcsuite/btcd/wire" "github.com/btcsuite/btcutil" "github.com/btcsuite/btcwallet/wallet/txauthor" + "github.com/lightningnetwork/lnd/input" "github.com/lightningnetwork/lnd/lnwallet/chainfee" ) @@ -292,7 +293,7 @@ type MessageSigner interface { // that corresponds to the passed public key. If the target private key // is unable to be found, then an error will be returned. The actual // digest signed is the double SHA-256 of the passed message. - SignMessage(pubKey *btcec.PublicKey, msg []byte) (*btcec.Signature, error) + SignMessage(pubKey *btcec.PublicKey, msg []byte) (input.Signature, error) } // WalletDriver represents a "driver" for a particular concrete diff --git a/lnwallet/interface_test.go b/lnwallet/interface_test.go index 1b6a1f28..16fc7ce4 100644 --- a/lnwallet/interface_test.go +++ b/lnwallet/interface_test.go @@ -1591,7 +1591,7 @@ func txFromOutput(tx *wire.MsgTx, signer input.Signer, fromPubKey, return nil, fmt.Errorf("unable to generate signature: %v", err) } witness := make([][]byte, 2) - witness[0] = append(spendSig, byte(txscript.SigHashAll)) + witness[0] = append(spendSig.Serialize(), byte(txscript.SigHashAll)) witness[1] = fromPubKey.SerializeCompressed() tx1.TxIn[0].Witness = witness @@ -1976,7 +1976,7 @@ func testSignOutputUsingTweaks(r *rpctest.Harness, t.Fatalf("unable to generate signature: %v", err) } witness := make([][]byte, 2) - witness[0] = append(spendSig, byte(txscript.SigHashAll)) + witness[0] = append(spendSig.Serialize(), byte(txscript.SigHashAll)) witness[1] = tweakedKey.SerializeCompressed() sweepTx.TxIn[0].Witness = witness diff --git a/lnwallet/reservation.go b/lnwallet/reservation.go index 19251351..22ef08b3 100644 --- a/lnwallet/reservation.go +++ b/lnwallet/reservation.go @@ -134,8 +134,8 @@ type ChannelReservation struct { theirFundingInputScripts []*input.Script // Our signature for their version of the commitment transaction. - ourCommitmentSig []byte - theirCommitmentSig []byte + ourCommitmentSig input.Signature + theirCommitmentSig input.Signature ourContribution *ChannelContribution theirContribution *ChannelContribution @@ -538,7 +538,9 @@ func (r *ChannelReservation) TheirContribution() *ChannelContribution { // // NOTE: These signatures will only be populated after a call to // .ProcessContribution() -func (r *ChannelReservation) OurSignatures() ([]*input.Script, []byte) { +func (r *ChannelReservation) OurSignatures() ([]*input.Script, + input.Signature) { + r.RLock() defer r.RUnlock() return r.ourFundingInputScripts, r.ourCommitmentSig @@ -558,7 +560,7 @@ func (r *ChannelReservation) OurSignatures() ([]*input.Script, []byte) { // confirmations. Once the method unblocks, a LightningChannel instance is // returned, marking the channel available for updates. func (r *ChannelReservation) CompleteReservation(fundingInputScripts []*input.Script, - commitmentSig []byte) (*channeldb.OpenChannel, error) { + commitmentSig input.Signature) (*channeldb.OpenChannel, error) { // TODO(roasbeef): add flag for watch or not? errChan := make(chan error, 1) @@ -585,7 +587,7 @@ func (r *ChannelReservation) CompleteReservation(fundingInputScripts []*input.Sc // called as a response to a single funder channel, only a commitment signature // will be populated. func (r *ChannelReservation) CompleteReservationSingle(fundingPoint *wire.OutPoint, - commitSig []byte) (*channeldb.OpenChannel, error) { + commitSig input.Signature) (*channeldb.OpenChannel, error) { errChan := make(chan error, 1) completeChan := make(chan *channeldb.OpenChannel, 1) @@ -608,7 +610,9 @@ func (r *ChannelReservation) CompleteReservationSingle(fundingPoint *wire.OutPoi // // NOTE: These attributes will be unpopulated before a call to // .CompleteReservation(). -func (r *ChannelReservation) TheirSignatures() ([]*input.Script, []byte) { +func (r *ChannelReservation) TheirSignatures() ([]*input.Script, + input.Signature) { + r.RLock() defer r.RUnlock() return r.theirFundingInputScripts, r.theirCommitmentSig diff --git a/lnwallet/sigpool.go b/lnwallet/sigpool.go index 57b84988..ec1d4f34 100644 --- a/lnwallet/sigpool.go +++ b/lnwallet/sigpool.go @@ -205,7 +205,7 @@ func (s *SigPool) poolWorker() { } } - sig, err := lnwire.NewSigFromRawSignature(rawSig) + sig, err := lnwire.NewSigFromSignature(rawSig) select { case sigMsg.Resp <- SignJobResp{ Sig: sig, diff --git a/lnwallet/wallet.go b/lnwallet/wallet.go index f7d66b6b..3349d29e 100644 --- a/lnwallet/wallet.go +++ b/lnwallet/wallet.go @@ -215,7 +215,7 @@ type addCounterPartySigsMsg struct { // This should be 1/2 of the signatures needed to successfully spend our // version of the commitment transaction. - theirCommitmentSig []byte + theirCommitmentSig input.Signature // This channel is used to return the completed channel after the wallet // has completed all of its stages in the funding process. @@ -240,7 +240,7 @@ type addSingleFunderSigsMsg struct { // theirCommitmentSig are the 1/2 of the signatures needed to // successfully spend our version of the commitment transaction. - theirCommitmentSig []byte + theirCommitmentSig input.Signature // This channel is used to return the completed channel after the wallet // has completed all of its stages in the funding process. @@ -1406,18 +1406,13 @@ func (l *LightningWallet) handleFundingCounterPartySigs(msg *addCounterPartySigs // Verify that we've received a valid signature from the remote party // for our version of the commitment transaction. - theirCommitSig := msg.theirCommitmentSig - sig, err := btcec.ParseSignature(theirCommitSig, btcec.S256()) - if err != nil { - msg.err <- err - msg.completeChan <- nil - return - } else if !sig.Verify(sigHash, theirKey.PubKey) { + if !msg.theirCommitmentSig.Verify(sigHash, theirKey.PubKey) { msg.err <- fmt.Errorf("counterparty's commitment signature is invalid") msg.completeChan <- nil return } - res.partialState.LocalCommitment.CommitSig = theirCommitSig + theirCommitSigBytes := msg.theirCommitmentSig.Serialize() + res.partialState.LocalCommitment.CommitSig = theirCommitSigBytes // Funding complete, this entry can be removed from limbo. l.limboMtx.Lock() @@ -1566,19 +1561,14 @@ func (l *LightningWallet) handleSingleFunderSigs(req *addSingleFunderSigsMsg) { // Verify that we've received a valid signature from the remote party // for our version of the commitment transaction. - sig, err := btcec.ParseSignature(req.theirCommitmentSig, btcec.S256()) - if err != nil { - req.err <- err - req.completeChan <- nil - return - } - if !sig.Verify(sigHash, theirKey.PubKey) { + if !req.theirCommitmentSig.Verify(sigHash, theirKey.PubKey) { req.err <- fmt.Errorf("counterparty's commitment signature " + "is invalid") req.completeChan <- nil return } - chanState.LocalCommitment.CommitSig = req.theirCommitmentSig + theirCommitSigBytes := req.theirCommitmentSig.Serialize() + chanState.LocalCommitment.CommitSig = theirCommitSigBytes // With their signature for our version of the commitment transactions // verified, we can now generate a signature for their version, diff --git a/lnwire/signature.go b/lnwire/signature.go index 012d5a91..13a2f25c 100644 --- a/lnwire/signature.go +++ b/lnwire/signature.go @@ -4,6 +4,7 @@ import ( "fmt" "github.com/btcsuite/btcd/btcec" + "github.com/lightningnetwork/lnd/input" ) // Sig is a fixed-sized ECDSA signature. Unlike Bitcoin, we use fixed sized @@ -64,7 +65,7 @@ func NewSigFromRawSignature(sig []byte) (Sig, error) { // NewSigFromSignature creates a new signature as used on the wire, from an // existing btcec.Signature. -func NewSigFromSignature(e *btcec.Signature) (Sig, error) { +func NewSigFromSignature(e input.Signature) (Sig, error) { if e == nil { return Sig{}, fmt.Errorf("cannot decode empty signature") } diff --git a/mock.go b/mock.go index bf9559d7..0b71a6dc 100644 --- a/mock.go +++ b/mock.go @@ -33,7 +33,7 @@ type mockSigner struct { } func (m *mockSigner) SignOutputRaw(tx *wire.MsgTx, - signDesc *input.SignDescriptor) ([]byte, error) { + signDesc *input.SignDescriptor) (input.Signature, error) { amt := signDesc.Output.Value witnessScript := signDesc.WitnessScript privKey := m.key @@ -58,7 +58,7 @@ func (m *mockSigner) SignOutputRaw(tx *wire.MsgTx, return nil, err } - return sig[:len(sig)-1], nil + return btcec.ParseDERSignature(sig[:len(sig)-1], btcec.S256()) } func (m *mockSigner) ComputeInputScript(tx *wire.MsgTx, diff --git a/netann/channel_update_test.go b/netann/channel_update_test.go index 0bc48e5c..1fff1d51 100644 --- a/netann/channel_update_test.go +++ b/netann/channel_update_test.go @@ -6,6 +6,7 @@ import ( "time" "github.com/btcsuite/btcd/btcec" + "github.com/lightningnetwork/lnd/input" "github.com/lightningnetwork/lnd/lnwallet" "github.com/lightningnetwork/lnd/lnwire" "github.com/lightningnetwork/lnd/netann" @@ -17,7 +18,7 @@ type mockSigner struct { } func (m *mockSigner) SignMessage(pk *btcec.PublicKey, - msg []byte) (*btcec.Signature, error) { + msg []byte) (input.Signature, error) { if m.err != nil { return nil, m.err diff --git a/netann/node_signer.go b/netann/node_signer.go index 8946c2c6..2b97c937 100644 --- a/netann/node_signer.go +++ b/netann/node_signer.go @@ -5,6 +5,7 @@ import ( "github.com/btcsuite/btcd/btcec" "github.com/btcsuite/btcd/chaincfg/chainhash" + "github.com/lightningnetwork/lnd/input" "github.com/lightningnetwork/lnd/lnwallet" ) @@ -31,7 +32,7 @@ func NewNodeSigner(key *btcec.PrivateKey) *NodeSigner { // resident node's private key. If the target public key is _not_ the node's // private key, then an error will be returned. func (n *NodeSigner) SignMessage(pubKey *btcec.PublicKey, - msg []byte) (*btcec.Signature, error) { + msg []byte) (input.Signature, error) { // If this isn't our identity public key, then we'll exit early with an // error as we can't sign with this key. @@ -41,12 +42,12 @@ func (n *NodeSigner) SignMessage(pubKey *btcec.PublicKey, // Otherwise, we'll sign the dsha256 of the target message. digest := chainhash.DoubleHashB(msg) - sign, err := n.privKey.Sign(digest) + sig, err := n.privKey.Sign(digest) if err != nil { return nil, fmt.Errorf("can't sign the message: %v", err) } - return sign, nil + return sig, nil } // SignCompact signs a double-sha256 digest of the msg parameter under the diff --git a/netann/sign.go b/netann/sign.go index 5a669620..6e0bce98 100644 --- a/netann/sign.go +++ b/netann/sign.go @@ -4,6 +4,7 @@ import ( "fmt" "github.com/btcsuite/btcd/btcec" + "github.com/lightningnetwork/lnd/input" "github.com/lightningnetwork/lnd/lnwallet" "github.com/lightningnetwork/lnd/lnwire" ) @@ -11,7 +12,7 @@ import ( // SignAnnouncement signs any type of gossip message that is announced on the // network. func SignAnnouncement(signer lnwallet.MessageSigner, pubKey *btcec.PublicKey, - msg lnwire.Message) (*btcec.Signature, error) { + msg lnwire.Message) (input.Signature, error) { var ( data []byte diff --git a/peer_test.go b/peer_test.go index 14cb1979..4669168b 100644 --- a/peer_test.go +++ b/peer_test.go @@ -96,7 +96,7 @@ func TestPeerChannelClosureAcceptFeeResponder(t *testing.T) { t.Fatalf("error creating close proposal: %v", err) } - parsedSig, err := lnwire.NewSigFromRawSignature(initiatorSig) + parsedSig, err := lnwire.NewSigFromSignature(initiatorSig) if err != nil { t.Fatalf("error parsing signature: %v", err) } @@ -184,7 +184,7 @@ func TestPeerChannelClosureAcceptFeeInitiator(t *testing.T) { if err != nil { t.Fatalf("unable to create close proposal: %v", err) } - parsedSig, err := lnwire.NewSigFromRawSignature(closeSig) + parsedSig, err := lnwire.NewSigFromSignature(closeSig) if err != nil { t.Fatalf("unable to parse signature: %v", err) } @@ -296,7 +296,7 @@ func TestPeerChannelClosureFeeNegotiationsResponder(t *testing.T) { t.Fatalf("error creating close proposal: %v", err) } - parsedSig, err := lnwire.NewSigFromRawSignature(initiatorSig) + parsedSig, err := lnwire.NewSigFromSignature(initiatorSig) if err != nil { t.Fatalf("error parsing signature: %v", err) } @@ -340,7 +340,7 @@ func TestPeerChannelClosureFeeNegotiationsResponder(t *testing.T) { t.Fatalf("error creating close proposal: %v", err) } - parsedSig, err = lnwire.NewSigFromRawSignature(initiatorSig) + parsedSig, err = lnwire.NewSigFromSignature(initiatorSig) if err != nil { t.Fatalf("error parsing signature: %v", err) } @@ -385,7 +385,7 @@ func TestPeerChannelClosureFeeNegotiationsResponder(t *testing.T) { t.Fatalf("error creating close proposal: %v", err) } - parsedSig, err = lnwire.NewSigFromRawSignature(initiatorSig) + parsedSig, err = lnwire.NewSigFromSignature(initiatorSig) if err != nil { t.Fatalf("error parsing signature: %v", err) } @@ -477,7 +477,7 @@ func TestPeerChannelClosureFeeNegotiationsInitiator(t *testing.T) { if err != nil { t.Fatalf("unable to create close proposal: %v", err) } - parsedSig, err := lnwire.NewSigFromRawSignature(closeSig) + parsedSig, err := lnwire.NewSigFromSignature(closeSig) if err != nil { t.Fatalf("unable to parse signature: %v", err) } @@ -543,7 +543,7 @@ func TestPeerChannelClosureFeeNegotiationsInitiator(t *testing.T) { t.Fatalf("error creating close proposal: %v", err) } - parsedSig, err = lnwire.NewSigFromRawSignature(responderSig) + parsedSig, err = lnwire.NewSigFromSignature(responderSig) if err != nil { t.Fatalf("error parsing signature: %v", err) } @@ -589,7 +589,7 @@ func TestPeerChannelClosureFeeNegotiationsInitiator(t *testing.T) { t.Fatalf("error creating close proposal: %v", err) } - parsedSig, err = lnwire.NewSigFromRawSignature(responderSig) + parsedSig, err = lnwire.NewSigFromSignature(responderSig) if err != nil { t.Fatalf("error parsing signature: %v", err) } diff --git a/server.go b/server.go index a1dce6ec..fba2dd6f 100644 --- a/server.go +++ b/server.go @@ -981,7 +981,7 @@ func newServer(listenAddrs []net.Addr, chanDB *channeldb.DB, Notifier: cc.chainNotifier, FeeEstimator: cc.feeEstimator, SignMessage: func(pubKey *btcec.PublicKey, - msg []byte) (*btcec.Signature, error) { + msg []byte) (input.Signature, error) { if pubKey.IsEqual(privKey.PubKey()) { return s.nodeSigner.SignMessage(pubKey, msg) diff --git a/sweep/test_utils.go b/sweep/test_utils.go index 6b9b0d72..7c28710b 100644 --- a/sweep/test_utils.go +++ b/sweep/test_utils.go @@ -6,6 +6,7 @@ import ( "testing" "time" + "github.com/btcsuite/btcd/btcec" "github.com/btcsuite/btcd/chaincfg/chainhash" "github.com/btcsuite/btcd/wire" "github.com/lightningnetwork/lnd/chainntnfs" @@ -18,13 +19,23 @@ var ( mockChainHeight = int32(100) ) +type dummySignature struct{} + +func (s *dummySignature) Serialize() []byte { + return []byte{} +} + +func (s *dummySignature) Verify(_ []byte, _ *btcec.PublicKey) bool { + return true +} + type mockSigner struct { } func (m *mockSigner) SignOutputRaw(tx *wire.MsgTx, - signDesc *input.SignDescriptor) ([]byte, error) { + signDesc *input.SignDescriptor) (input.Signature, error) { - return []byte{}, nil + return &dummySignature{}, nil } func (m *mockSigner) ComputeInputScript(tx *wire.MsgTx, diff --git a/watchtower/lookout/justice_descriptor_test.go b/watchtower/lookout/justice_descriptor_test.go index 7fd93c8c..6785f1b6 100644 --- a/watchtower/lookout/justice_descriptor_test.go +++ b/watchtower/lookout/justice_descriptor_test.go @@ -262,7 +262,7 @@ func testJusticeDescriptor(t *testing.T, blobType blob.Type) { toRemoteSigRaw := toRemoteWitness[0][:len(toRemoteWitness[0])-1] // Convert the DER to-local sig into a fixed-size signature. - toLocalSig, err := lnwire.NewSigFromRawSignature(toLocalSigRaw) + toLocalSig, err := lnwire.NewSigFromSignature(toLocalSigRaw) if err != nil { t.Fatalf("unable to parse to-local signature: %v", err) } @@ -310,7 +310,7 @@ func testJusticeDescriptor(t *testing.T, blobType blob.Type) { // Construct the test's to-local witness. justiceTxn.TxIn[0].Witness = make([][]byte, 3) - justiceTxn.TxIn[0].Witness[0] = append(toLocalSigRaw, + justiceTxn.TxIn[0].Witness[0] = append(toLocalSigRaw.Serialize(), byte(txscript.SigHashAll)) justiceTxn.TxIn[0].Witness[1] = []byte{1} justiceTxn.TxIn[0].Witness[2] = toLocalScript diff --git a/watchtower/wtmock/signer.go b/watchtower/wtmock/signer.go index c41e4f2f..89421d6a 100644 --- a/watchtower/wtmock/signer.go +++ b/watchtower/wtmock/signer.go @@ -30,7 +30,7 @@ func NewMockSigner() *MockSigner { // in the sign descriptor. The returned signature is the raw DER-encoded // signature without the signhash flag. func (s *MockSigner) SignOutputRaw(tx *wire.MsgTx, - signDesc *input.SignDescriptor) ([]byte, error) { + signDesc *input.SignDescriptor) (input.Signature, error) { s.mu.Lock() defer s.mu.Unlock() @@ -50,7 +50,7 @@ func (s *MockSigner) SignOutputRaw(tx *wire.MsgTx, return nil, err } - return sig[:len(sig)-1], nil + return btcec.ParseDERSignature(sig[:len(sig)-1], btcec.S256()) } // ComputeInputScript is not implemented.