diff --git a/discovery/gossiper.go b/discovery/gossiper.go index e4d2d7395..075982af8 100644 --- a/discovery/gossiper.go +++ b/discovery/gossiper.go @@ -15,6 +15,7 @@ import ( "github.com/lightningnetwork/lnd/batch" "github.com/lightningnetwork/lnd/chainntnfs" "github.com/lightningnetwork/lnd/channeldb" + "github.com/lightningnetwork/lnd/keychain" "github.com/lightningnetwork/lnd/kvdb" "github.com/lightningnetwork/lnd/lnpeer" "github.com/lightningnetwork/lnd/lnwallet" @@ -316,6 +317,10 @@ type AuthenticatedGossiper struct { // selfKey is the identity public key of the backing Lightning node. selfKey *btcec.PublicKey + // selfKeyLoc is the locator for the identity public key of the backing + // Lightning node. + selfKeyLoc keychain.KeyLocator + // channelMtx is used to restrict the database access to one // goroutine per channel ID. This is done to ensure that when // the gossiper is handling an announcement, the db state stays @@ -355,9 +360,10 @@ type AuthenticatedGossiper struct { // New creates a new AuthenticatedGossiper instance, initialized with the // passed configuration parameters. -func New(cfg Config, selfKey *btcec.PublicKey) *AuthenticatedGossiper { +func New(cfg Config, selfKeyDesc *keychain.KeyDescriptor) *AuthenticatedGossiper { gossiper := &AuthenticatedGossiper{ - selfKey: selfKey, + selfKey: selfKeyDesc.PubKey, + selfKeyLoc: selfKeyDesc.KeyLocator, cfg: &cfg, networkMsgs: make(chan *networkMsg), quit: make(chan struct{}), @@ -2567,7 +2573,7 @@ func (d *AuthenticatedGossiper) updateChannel(info *channeldb.ChannelEdgeInfo, // We'll generate a new signature over a digest of the channel // announcement itself and update the timestamp to ensure it propagate. err := netann.SignChannelUpdate( - d.cfg.AnnSigner, d.selfKey, chanUpdate, + d.cfg.AnnSigner, d.selfKeyLoc, chanUpdate, netann.ChanUpdSetTimestamp, ) if err != nil { diff --git a/discovery/gossiper_test.go b/discovery/gossiper_test.go index 55563018c..ea76d6256 100644 --- a/discovery/gossiper_test.go +++ b/discovery/gossiper_test.go @@ -25,6 +25,7 @@ import ( "github.com/lightningnetwork/lnd/batch" "github.com/lightningnetwork/lnd/chainntnfs" "github.com/lightningnetwork/lnd/channeldb" + "github.com/lightningnetwork/lnd/keychain" "github.com/lightningnetwork/lnd/kvdb" "github.com/lightningnetwork/lnd/lnpeer" "github.com/lightningnetwork/lnd/lntest/mock" @@ -46,11 +47,15 @@ var ( R: new(big.Int), S: new(big.Int), } - _, _ = testSig.R.SetString("63724406601629180062774974542967536251589935445068131219452686511677818569431", 10) - _, _ = testSig.S.SetString("18801056069249825825291287104931333862866033135609736119018462340006816851118", 10) + _, _ = testSig.R.SetString("63724406601629180062774974542967536251589935445068131219452686511677818569431", 10) + _, _ = testSig.S.SetString("18801056069249825825291287104931333862866033135609736119018462340006816851118", 10) + testKeyLoc = keychain.KeyLocator{Family: keychain.KeyFamilyNodeKey} selfKeyPriv, _ = btcec.NewPrivateKey(btcec.S256()) - selfKeyPub = selfKeyPriv.PubKey() + selfKeyDesc = &keychain.KeyDescriptor{ + PubKey: selfKeyPriv.PubKey(), + KeyLocator: testKeyLoc, + } bitcoinKeyPriv1, _ = btcec.NewPrivateKey(btcec.S256()) bitcoinKeyPub1 = bitcoinKeyPriv1.PubKey() @@ -568,7 +573,7 @@ func createNodeAnnouncement(priv *btcec.PrivateKey, } signer := mock.SingleSigner{Privkey: priv} - sig, err := netann.SignAnnouncement(&signer, priv.PubKey(), a) + sig, err := netann.SignAnnouncement(&signer, testKeyLoc, a) if err != nil { return nil, err } @@ -618,9 +623,8 @@ func createUpdateAnnouncement(blockHeight uint32, } func signUpdate(nodeKey *btcec.PrivateKey, a *lnwire.ChannelUpdate) error { - pub := nodeKey.PubKey() signer := mock.SingleSigner{Privkey: nodeKey} - sig, err := netann.SignAnnouncement(&signer, pub, a) + sig, err := netann.SignAnnouncement(&signer, testKeyLoc, a) if err != nil { return err } @@ -667,9 +671,8 @@ func createChannelAnnouncement(blockHeight uint32, key1, key2 *btcec.PrivateKey, a := createAnnouncementWithoutProof(blockHeight, key1.PubKey(), key2.PubKey(), extraBytes...) - pub := key1.PubKey() signer := mock.SingleSigner{Privkey: key1} - sig, err := netann.SignAnnouncement(&signer, pub, a) + sig, err := netann.SignAnnouncement(&signer, testKeyLoc, a) if err != nil { return nil, err } @@ -678,9 +681,8 @@ func createChannelAnnouncement(blockHeight uint32, key1, key2 *btcec.PrivateKey, return nil, err } - pub = key2.PubKey() signer = mock.SingleSigner{Privkey: key2} - sig, err = netann.SignAnnouncement(&signer, pub, a) + sig, err = netann.SignAnnouncement(&signer, testKeyLoc, a) if err != nil { return nil, err } @@ -689,9 +691,8 @@ func createChannelAnnouncement(blockHeight uint32, key1, key2 *btcec.PrivateKey, return nil, err } - pub = bitcoinKeyPriv1.PubKey() signer = mock.SingleSigner{Privkey: bitcoinKeyPriv1} - sig, err = netann.SignAnnouncement(&signer, pub, a) + sig, err = netann.SignAnnouncement(&signer, testKeyLoc, a) if err != nil { return nil, err } @@ -700,9 +701,8 @@ func createChannelAnnouncement(blockHeight uint32, key1, key2 *btcec.PrivateKey, return nil, err } - pub = bitcoinKeyPriv2.PubKey() signer = mock.SingleSigner{Privkey: bitcoinKeyPriv2} - sig, err = netann.SignAnnouncement(&signer, pub, a) + sig, err = netann.SignAnnouncement(&signer, testKeyLoc, a) if err != nil { return nil, err } @@ -785,7 +785,7 @@ func createTestCtx(startHeight uint32) (*testCtx, func(), error) { MinimumBatchSize: 10, MaxChannelUpdateBurst: DefaultMaxChannelUpdateBurst, ChannelUpdateInterval: DefaultChannelUpdateInterval, - }, selfKeyPub) + }, selfKeyDesc) if err := gossiper.Start(); err != nil { cleanUpDb() @@ -1480,7 +1480,10 @@ func TestSignatureAnnouncementRetryAtStartup(t *testing.T) { NumActiveSyncers: 3, MinimumBatchSize: 10, SubBatchDelay: time.Second * 5, - }, ctx.gossiper.selfKey) + }, &keychain.KeyDescriptor{ + PubKey: ctx.gossiper.selfKey, + KeyLocator: ctx.gossiper.selfKeyLoc, + }) if err != nil { t.Fatalf("unable to recreate gossiper: %v", err) } @@ -2056,7 +2059,9 @@ func TestForwardPrivateNodeAnnouncement(t *testing.T) { // We'll start off by processing a channel announcement without a proof // (i.e., an unadvertised channel), followed by a node announcement for // this same channel announcement. - chanAnn := createAnnouncementWithoutProof(startingHeight-2, selfKeyPub, remoteKeyPub1) + chanAnn := createAnnouncementWithoutProof( + startingHeight-2, selfKeyDesc.PubKey, remoteKeyPub1, + ) pubKey := remoteKeyPriv1.PubKey() select { @@ -3671,8 +3676,12 @@ func TestProcessChannelAnnouncementOptionalMsgFields(t *testing.T) { } defer cleanup() - chanAnn1 := createAnnouncementWithoutProof(100, selfKeyPub, remoteKeyPub1) - chanAnn2 := createAnnouncementWithoutProof(101, selfKeyPub, remoteKeyPub1) + chanAnn1 := createAnnouncementWithoutProof( + 100, selfKeyDesc.PubKey, remoteKeyPub1, + ) + chanAnn2 := createAnnouncementWithoutProof( + 101, selfKeyDesc.PubKey, remoteKeyPub1, + ) // assertOptionalMsgFields is a helper closure that ensures the optional // message fields were set as intended. diff --git a/funding/manager.go b/funding/manager.go index 47b7634fa..2d9df837d 100644 --- a/funding/manager.go +++ b/funding/manager.go @@ -294,6 +294,10 @@ type Config struct { // Lightning Network. IDKey *btcec.PublicKey + // IDKeyLoc is the locator for the key that is used to identify this + // node within the LightningNetwork. + IDKeyLoc keychain.KeyLocator + // Wallet handles the parts of the funding process that involves moving // funds from on-chain transaction outputs into Lightning channels. Wallet *lnwallet.LightningWallet @@ -322,8 +326,8 @@ type Config struct { // // TODO(roasbeef): should instead pass on this responsibility to a // distinct sub-system? - SignMessage func(pubKey *btcec.PublicKey, - msg []byte) (input.Signature, error) + SignMessage func(keyLoc keychain.KeyLocator, + msg []byte) (*btcec.Signature, error) // CurrentNodeAnnouncement should return the latest, fully signed node // announcement from the backing Lightning Network node. @@ -2523,7 +2527,7 @@ func (f *Manager) addToRouterGraph(completeChan *channeldb.OpenChannel, ann, err := f.newChanAnnouncement( f.cfg.IDKey, completeChan.IdentityPub, - completeChan.LocalChanCfg.MultiSigKey.PubKey, + &completeChan.LocalChanCfg.MultiSigKey, completeChan.RemoteChanCfg.MultiSigKey.PubKey, *shortChanID, chanID, fwdMinHTLC, fwdMaxHTLC, ) @@ -2686,7 +2690,7 @@ func (f *Manager) annAfterSixConfs(completeChan *channeldb.OpenChannel, // public and usable for other nodes for routing. err = f.announceChannel( f.cfg.IDKey, completeChan.IdentityPub, - completeChan.LocalChanCfg.MultiSigKey.PubKey, + &completeChan.LocalChanCfg.MultiSigKey, completeChan.RemoteChanCfg.MultiSigKey.PubKey, *shortChanID, chanID, ) @@ -2826,10 +2830,11 @@ type chanAnnouncement struct { // identity pub keys of both parties to the channel, and the second segment is // authenticated only by us and contains our directional routing policy for the // channel. -func (f *Manager) newChanAnnouncement(localPubKey, remotePubKey, - localFundingKey, remoteFundingKey *btcec.PublicKey, - shortChanID lnwire.ShortChannelID, chanID lnwire.ChannelID, - fwdMinHTLC, fwdMaxHTLC lnwire.MilliSatoshi) (*chanAnnouncement, error) { +func (f *Manager) newChanAnnouncement(localPubKey, + remotePubKey *btcec.PublicKey, localFundingKey *keychain.KeyDescriptor, + remoteFundingKey *btcec.PublicKey, shortChanID lnwire.ShortChannelID, + chanID lnwire.ChannelID, fwdMinHTLC, + fwdMaxHTLC lnwire.MilliSatoshi) (*chanAnnouncement, error) { chainHash := *f.cfg.Wallet.Cfg.NetParams.GenesisHash @@ -2857,7 +2862,7 @@ func (f *Manager) newChanAnnouncement(localPubKey, remotePubKey, if bytes.Compare(selfBytes, remoteBytes) == -1 { copy(chanAnn.NodeID1[:], localPubKey.SerializeCompressed()) copy(chanAnn.NodeID2[:], remotePubKey.SerializeCompressed()) - copy(chanAnn.BitcoinKey1[:], localFundingKey.SerializeCompressed()) + copy(chanAnn.BitcoinKey1[:], localFundingKey.PubKey.SerializeCompressed()) copy(chanAnn.BitcoinKey2[:], remoteFundingKey.SerializeCompressed()) // If we're the first node then update the chanFlags to @@ -2867,7 +2872,7 @@ func (f *Manager) newChanAnnouncement(localPubKey, remotePubKey, copy(chanAnn.NodeID1[:], remotePubKey.SerializeCompressed()) copy(chanAnn.NodeID2[:], localPubKey.SerializeCompressed()) copy(chanAnn.BitcoinKey1[:], remoteFundingKey.SerializeCompressed()) - copy(chanAnn.BitcoinKey2[:], localFundingKey.SerializeCompressed()) + copy(chanAnn.BitcoinKey2[:], localFundingKey.PubKey.SerializeCompressed()) // If we're the second node then update the chanFlags to // indicate the "direction" of the update. @@ -2906,7 +2911,7 @@ func (f *Manager) newChanAnnouncement(localPubKey, remotePubKey, if err != nil { return nil, err } - sig, err := f.cfg.SignMessage(f.cfg.IDKey, chanUpdateMsg) + sig, err := f.cfg.SignMessage(f.cfg.IDKeyLoc, chanUpdateMsg) if err != nil { return nil, errors.Errorf("unable to generate channel "+ "update announcement signature: %v", err) @@ -2928,12 +2933,14 @@ func (f *Manager) newChanAnnouncement(localPubKey, remotePubKey, if err != nil { return nil, err } - nodeSig, err := f.cfg.SignMessage(f.cfg.IDKey, chanAnnMsg) + nodeSig, err := f.cfg.SignMessage(f.cfg.IDKeyLoc, chanAnnMsg) if err != nil { return nil, errors.Errorf("unable to generate node "+ "signature for channel announcement: %v", err) } - bitcoinSig, err := f.cfg.SignMessage(localFundingKey, chanAnnMsg) + bitcoinSig, err := f.cfg.SignMessage( + localFundingKey.KeyLocator, chanAnnMsg, + ) if err != nil { return nil, errors.Errorf("unable to generate bitcoin "+ "signature for node public key: %v", err) @@ -2969,7 +2976,8 @@ func (f *Manager) newChanAnnouncement(localPubKey, remotePubKey, // the network during its next trickle. // This method is synchronous and will return when all the network requests // finish, either successfully or with an error. -func (f *Manager) announceChannel(localIDKey, remoteIDKey, localFundingKey, +func (f *Manager) announceChannel(localIDKey, remoteIDKey *btcec.PublicKey, + localFundingKey *keychain.KeyDescriptor, remoteFundingKey *btcec.PublicKey, shortChanID lnwire.ShortChannelID, chanID lnwire.ChannelID) error { diff --git a/funding/manager_test.go b/funding/manager_test.go index 8dcb97868..7261ab636 100644 --- a/funding/manager_test.go +++ b/funding/manager_test.go @@ -110,6 +110,8 @@ var ( _, _ = testSig.R.SetString("63724406601629180062774974542967536251589935445068131219452686511677818569431", 10) _, _ = testSig.S.SetString("18801056069249825825291287104931333862866033135609736119018462340006816851118", 10) + testKeyLoc = keychain.KeyLocator{Family: keychain.KeyFamilyNodeKey} + fundingNetParams = chainreg.BitcoinTestNetParams ) @@ -355,11 +357,12 @@ func createTestFundingManager(t *testing.T, privKey *btcec.PrivateKey, fundingCfg := Config{ IDKey: privKey.PubKey(), + IDKeyLoc: testKeyLoc, Wallet: lnw, Notifier: chainNotifier, FeeEstimator: estimator, - SignMessage: func(pubKey *btcec.PublicKey, - msg []byte) (input.Signature, error) { + SignMessage: func(_ keychain.KeyLocator, + _ []byte) (*btcec.Signature, error) { return testSig, nil }, @@ -502,11 +505,13 @@ func recreateAliceFundingManager(t *testing.T, alice *testNode) { f, err := NewFundingManager(Config{ IDKey: oldCfg.IDKey, + IDKeyLoc: oldCfg.IDKeyLoc, Wallet: oldCfg.Wallet, Notifier: oldCfg.Notifier, FeeEstimator: oldCfg.FeeEstimator, - SignMessage: func(pubKey *btcec.PublicKey, - msg []byte) (input.Signature, error) { + SignMessage: func(_ keychain.KeyLocator, + _ []byte) (*btcec.Signature, error) { + return testSig, nil }, SendAnnouncement: func(msg lnwire.Message, diff --git a/keychain/derivation.go b/keychain/derivation.go index 50fefe69c..9a0dc390d 100644 --- a/keychain/derivation.go +++ b/keychain/derivation.go @@ -211,6 +211,10 @@ type SingleKeyMessageSigner interface { // PubKey returns the public key of the wrapped private key. PubKey() *btcec.PublicKey + // KeyLocator returns the locator that describes the wrapped private + // key. + KeyLocator() KeyLocator + // SignMessage signs the given message, single or double SHA256 hashing // it first, with the wrapped private key. SignMessage(message []byte, doubleHash bool) (*btcec.Signature, error) diff --git a/keychain/signer.go b/keychain/signer.go index edd91bc8d..9986edadd 100644 --- a/keychain/signer.go +++ b/keychain/signer.go @@ -25,6 +25,10 @@ func (p *PubKeyMessageSigner) PubKey() *btcec.PublicKey { return p.pubKey } +func (p *PubKeyMessageSigner) KeyLocator() KeyLocator { + return p.keyLoc +} + func (p *PubKeyMessageSigner) SignMessage(message []byte, doubleHash bool) (*btcec.Signature, error) { @@ -37,12 +41,26 @@ func (p *PubKeyMessageSigner) SignMessageCompact(msg []byte, return p.digestSigner.SignMessageCompact(p.keyLoc, msg, doubleHash) } +func NewPrivKeyMessageSigner(privKey *btcec.PrivateKey, + keyLoc KeyLocator) *PrivKeyMessageSigner { + + return &PrivKeyMessageSigner{ + privKey: privKey, + keyLoc: keyLoc, + } +} + type PrivKeyMessageSigner struct { - PrivKey *btcec.PrivateKey + keyLoc KeyLocator + privKey *btcec.PrivateKey } func (p *PrivKeyMessageSigner) PubKey() *btcec.PublicKey { - return p.PrivKey.PubKey() + return p.privKey.PubKey() +} + +func (p *PrivKeyMessageSigner) KeyLocator() KeyLocator { + return p.keyLoc } func (p *PrivKeyMessageSigner) SignMessage(msg []byte, @@ -54,7 +72,7 @@ func (p *PrivKeyMessageSigner) SignMessage(msg []byte, } else { digest = chainhash.HashB(msg) } - return p.PrivKey.Sign(digest) + return p.privKey.Sign(digest) } func (p *PrivKeyMessageSigner) SignMessageCompact(msg []byte, @@ -66,7 +84,7 @@ func (p *PrivKeyMessageSigner) SignMessageCompact(msg []byte, } else { digest = chainhash.HashB(msg) } - return btcec.SignCompact(btcec.S256(), p.PrivKey, digest, true) + return btcec.SignCompact(btcec.S256(), p.privKey, digest, true) } var _ SingleKeyMessageSigner = (*PubKeyMessageSigner)(nil) diff --git a/lntest/mock/signer.go b/lntest/mock/signer.go index c94d4eeb2..ce4dc55f3 100644 --- a/lntest/mock/signer.go +++ b/lntest/mock/signer.go @@ -7,8 +7,12 @@ import ( "github.com/btcsuite/btcd/chaincfg/chainhash" "github.com/btcsuite/btcd/txscript" "github.com/btcsuite/btcd/wire" - "github.com/lightningnetwork/lnd/input" + "github.com/lightningnetwork/lnd/keychain" +) + +var ( + idKeyLoc = keychain.KeyLocator{Family: keychain.KeyFamilyNodeKey} ) // DummySignature is a dummy Signature implementation. @@ -46,6 +50,7 @@ func (d *DummySigner) ComputeInputScript(tx *wire.MsgTx, // everything with a single private key. type SingleSigner struct { Privkey *btcec.PrivateKey + KeyLoc keychain.KeyLocator } // SignOutputRaw generates a signature for the passed transaction using the @@ -110,10 +115,15 @@ func (s *SingleSigner) ComputeInputScript(tx *wire.MsgTx, // SignMessage takes a public key and a message and only signs the message // with the stored private key if the public key matches the private key. -func (s *SingleSigner) SignMessage(pubKey *btcec.PublicKey, - msg []byte) (input.Signature, error) { +func (s *SingleSigner) SignMessage(keyLoc keychain.KeyLocator, + msg []byte) (*btcec.Signature, error) { - if !pubKey.IsEqual(s.Privkey.PubKey()) { + mockKeyLoc := s.KeyLoc + if s.KeyLoc.IsEmpty() { + mockKeyLoc = idKeyLoc + } + + if keyLoc != mockKeyLoc { return nil, fmt.Errorf("unknown public key") } diff --git a/lnwallet/btcwallet/signer.go b/lnwallet/btcwallet/signer.go index bc48360e6..a710565e2 100644 --- a/lnwallet/btcwallet/signer.go +++ b/lnwallet/btcwallet/signer.go @@ -126,11 +126,13 @@ func (b *BtcWallet) deriveKeyByLocator(keyLoc keychain.KeyLocator) (*btcec.Priva // fetchPrivKey attempts to retrieve the raw private key corresponding to the // passed public key if populated, or the key descriptor path (if non-empty). -func (b *BtcWallet) fetchPrivKey(keyDesc *keychain.KeyDescriptor) (*btcec.PrivateKey, error) { +func (b *BtcWallet) fetchPrivKey( + keyDesc *keychain.KeyDescriptor) (*btcec.PrivateKey, error) { + // If the key locator within the descriptor *isn't* empty, then we can // directly derive the keys raw. emptyLocator := keyDesc.KeyLocator.IsEmpty() - if !emptyLocator { + if !emptyLocator || keyDesc.PubKey == nil { return b.deriveKeyByLocator(keyDesc.KeyLocator) } @@ -259,18 +261,18 @@ func (b *BtcWallet) ComputeInputScript(tx *wire.MsgTx, var _ input.Signer = (*BtcWallet)(nil) // SignMessage attempts to sign a target message with the private key that -// corresponds to the passed public key. If the target private key is unable to +// corresponds to the passed key locator. 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. // // NOTE: This is a part of the MessageSigner interface. -func (b *BtcWallet) SignMessage(pubKey *btcec.PublicKey, - msg []byte) (input.Signature, error) { +func (b *BtcWallet) SignMessage(keyLoc keychain.KeyLocator, + msg []byte) (*btcec.Signature, error) { // First attempt to fetch the private key which corresponds to the // specified public key. privKey, err := b.fetchPrivKey(&keychain.KeyDescriptor{ - PubKey: pubKey, + KeyLocator: keyLoc, }) if err != nil { return nil, err diff --git a/lnwallet/interface.go b/lnwallet/interface.go index 4a96cc874..9e94cfa0a 100644 --- a/lnwallet/interface.go +++ b/lnwallet/interface.go @@ -15,7 +15,7 @@ import ( "github.com/btcsuite/btcwallet/waddrmgr" "github.com/btcsuite/btcwallet/wallet/txauthor" "github.com/btcsuite/btcwallet/wtxmgr" - "github.com/lightningnetwork/lnd/input" + "github.com/lightningnetwork/lnd/keychain" "github.com/lightningnetwork/lnd/lnwallet/chainfee" ) @@ -440,10 +440,11 @@ type BlockChainIO interface { // to attest to some message. type MessageSigner interface { // SignMessage attempts to sign a target message with the private key - // 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) (input.Signature, error) + // described in the key locator. 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(keyLoc keychain.KeyLocator, msg []byte) (*btcec.Signature, + error) } // WalletDriver represents a "driver" for a particular concrete diff --git a/lnwire/signature.go b/lnwire/signature.go index 13a2f25c3..2adf26133 100644 --- a/lnwire/signature.go +++ b/lnwire/signature.go @@ -70,6 +70,12 @@ func NewSigFromSignature(e input.Signature) (Sig, error) { return Sig{}, fmt.Errorf("cannot decode empty signature") } + // Nil is still a valid interface, apparently. So we need a more + // explicit check here. + if ecsig, ok := e.(*btcec.Signature); ok && ecsig == nil { + return Sig{}, fmt.Errorf("cannot decode empty signature") + } + // Serialize the signature with all the checks that entails. return NewSigFromRawSignature(e.Serialize()) } diff --git a/netann/chan_status_manager.go b/netann/chan_status_manager.go index 212bd4dae..66d6d9682 100644 --- a/netann/chan_status_manager.go +++ b/netann/chan_status_manager.go @@ -8,6 +8,7 @@ import ( "github.com/btcsuite/btcd/btcec" "github.com/btcsuite/btcd/wire" "github.com/lightningnetwork/lnd/channeldb" + "github.com/lightningnetwork/lnd/keychain" "github.com/lightningnetwork/lnd/lnwallet" "github.com/lightningnetwork/lnd/lnwire" ) @@ -43,6 +44,10 @@ type ChanStatusConfig struct { // OurPubKey is the public key identifying this node on the network. OurPubKey *btcec.PublicKey + // OurKeyLoc is the locator for the public key identifying this node on + // the network. + OurKeyLoc keychain.KeyLocator + // MessageSigner signs messages that validate under OurPubKey. MessageSigner lnwallet.MessageSigner @@ -621,7 +626,7 @@ func (m *ChanStatusManager) signAndSendNextUpdate(outpoint wire.OutPoint, } err = SignChannelUpdate( - m.cfg.MessageSigner, m.cfg.OurPubKey, chanUpdate, + m.cfg.MessageSigner, m.cfg.OurKeyLoc, chanUpdate, ChanUpdSetDisable(disabled), ChanUpdSetTimestamp, ) if err != nil { diff --git a/netann/chan_status_manager_test.go b/netann/chan_status_manager_test.go index 0064dca4f..3e9cd6662 100644 --- a/netann/chan_status_manager_test.go +++ b/netann/chan_status_manager_test.go @@ -19,6 +19,10 @@ import ( "github.com/lightningnetwork/lnd/netann" ) +var ( + testKeyLoc = keychain.KeyLocator{Family: keychain.KeyFamilyNodeKey} +) + // randOutpoint creates a random wire.Outpoint. func randOutpoint(t *testing.T) wire.OutPoint { t.Helper() @@ -310,7 +314,7 @@ func newManagerCfg(t *testing.T, numChannels int, if err != nil { t.Fatalf("unable to generate key pair: %v", err) } - privKeySigner := &keychain.PrivKeyMessageSigner{PrivKey: privKey} + privKeySigner := keychain.NewPrivKeyMessageSigner(privKey, testKeyLoc) graph := newMockGraph( t, numChannels, startEnabled, startEnabled, privKey.PubKey(), @@ -322,6 +326,7 @@ func newManagerCfg(t *testing.T, numChannels int, ChanEnableTimeout: 500 * time.Millisecond, ChanDisableTimeout: time.Second, OurPubKey: privKey.PubKey(), + OurKeyLoc: testKeyLoc, MessageSigner: netann.NewNodeSigner(privKeySigner), IsChannelActive: htlcSwitch.HasActiveLink, ApplyChannelUpdate: graph.ApplyChannelUpdate, diff --git a/netann/channel_update.go b/netann/channel_update.go index a34f7ed93..0fec750f9 100644 --- a/netann/channel_update.go +++ b/netann/channel_update.go @@ -7,6 +7,7 @@ import ( "github.com/btcsuite/btcd/btcec" "github.com/lightningnetwork/lnd/channeldb" + "github.com/lightningnetwork/lnd/keychain" "github.com/lightningnetwork/lnd/lnwallet" "github.com/lightningnetwork/lnd/lnwire" ) @@ -55,7 +56,7 @@ func ChanUpdSetTimestamp(update *lnwire.ChannelUpdate) { // monotonically increase from the prior. // // NOTE: This method modifies the given update. -func SignChannelUpdate(signer lnwallet.MessageSigner, pubKey *btcec.PublicKey, +func SignChannelUpdate(signer lnwallet.MessageSigner, keyLoc keychain.KeyLocator, update *lnwire.ChannelUpdate, mods ...ChannelUpdateModifier) error { // Apply the requested changes to the channel update. @@ -64,7 +65,7 @@ func SignChannelUpdate(signer lnwallet.MessageSigner, pubKey *btcec.PublicKey, } // Create the DER-encoded ECDSA signature over the message digest. - sig, err := SignAnnouncement(signer, pubKey, update) + sig, err := SignAnnouncement(signer, keyLoc, update) if err != nil { return err } diff --git a/netann/channel_update_test.go b/netann/channel_update_test.go index c9e8d0656..5af21540f 100644 --- a/netann/channel_update_test.go +++ b/netann/channel_update_test.go @@ -6,7 +6,6 @@ import ( "time" "github.com/btcsuite/btcd/btcec" - "github.com/lightningnetwork/lnd/input" "github.com/lightningnetwork/lnd/keychain" "github.com/lightningnetwork/lnd/lnwallet" "github.com/lightningnetwork/lnd/lnwire" @@ -18,8 +17,8 @@ type mockSigner struct { err error } -func (m *mockSigner) SignMessage(pk *btcec.PublicKey, - msg []byte) (input.Signature, error) { +func (m *mockSigner) SignMessage(_ keychain.KeyLocator, + _ []byte) (*btcec.Signature, error) { if m.err != nil { return nil, m.err @@ -32,7 +31,7 @@ var _ lnwallet.MessageSigner = (*mockSigner)(nil) var ( privKey, _ = btcec.NewPrivateKey(btcec.S256()) - privKeySigner = &keychain.PrivKeyMessageSigner{PrivKey: privKey} + privKeySigner = keychain.NewPrivKeyMessageSigner(privKey, testKeyLoc) pubKey = privKey.PubKey() @@ -130,7 +129,7 @@ func TestUpdateDisableFlag(t *testing.T) { // Attempt to update and sign the new update, specifying // disabled or enabled as prescribed in the test case. err := netann.SignChannelUpdate( - tc.signer, pubKey, newUpdate, + tc.signer, testKeyLoc, newUpdate, netann.ChanUpdSetDisable(tc.disable), netann.ChanUpdSetTimestamp, ) diff --git a/netann/node_announcement.go b/netann/node_announcement.go index 84a261059..d73b6692f 100644 --- a/netann/node_announcement.go +++ b/netann/node_announcement.go @@ -4,7 +4,7 @@ import ( "net" "time" - "github.com/btcsuite/btcd/btcec" + "github.com/lightningnetwork/lnd/keychain" "github.com/lightningnetwork/lnd/lnwallet" "github.com/lightningnetwork/lnd/lnwire" ) @@ -40,7 +40,7 @@ func NodeAnnSetTimestamp(nodeAnn *lnwire.NodeAnnouncement) { // update should be the most recent, valid update, otherwise the timestamp may // not monotonically increase from the prior. func SignNodeAnnouncement(signer lnwallet.MessageSigner, - pubKey *btcec.PublicKey, nodeAnn *lnwire.NodeAnnouncement, + keyLoc keychain.KeyLocator, nodeAnn *lnwire.NodeAnnouncement, mods ...NodeAnnModifier) error { // Apply the requested changes to the node announcement. @@ -49,7 +49,7 @@ func SignNodeAnnouncement(signer lnwallet.MessageSigner, } // Create the DER-encoded ECDSA signature over the message digest. - sig, err := SignAnnouncement(signer, pubKey, nodeAnn) + sig, err := SignAnnouncement(signer, keyLoc, nodeAnn) if err != nil { return err } diff --git a/netann/node_signer.go b/netann/node_signer.go index 1a04e6380..eb2d813e8 100644 --- a/netann/node_signer.go +++ b/netann/node_signer.go @@ -4,7 +4,6 @@ import ( "fmt" "github.com/btcsuite/btcd/btcec" - "github.com/lightningnetwork/lnd/input" "github.com/lightningnetwork/lnd/keychain" "github.com/lightningnetwork/lnd/lnwallet" ) @@ -24,15 +23,15 @@ func NewNodeSigner(keySigner keychain.SingleKeyMessageSigner) *NodeSigner { } // SignMessage signs a double-sha256 digest of the passed msg under the -// 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) (input.Signature, error) { +// resident node's private key described in the key locator. If the target key +// locator is _not_ the node's private key, then an error will be returned. +func (n *NodeSigner) SignMessage(keyLoc keychain.KeyLocator, + msg []byte) (*btcec.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. - if !pubKey.IsEqual(n.keySigner.PubKey()) { - return nil, fmt.Errorf("unknown public key") + if keyLoc != n.keySigner.KeyLocator() { + return nil, fmt.Errorf("unknown public key locator") } // Otherwise, we'll sign the double-sha256 of the target message. diff --git a/netann/sign.go b/netann/sign.go index 6e0bce981..2ee4d0d08 100644 --- a/netann/sign.go +++ b/netann/sign.go @@ -3,15 +3,15 @@ package netann import ( "fmt" - "github.com/btcsuite/btcd/btcec" "github.com/lightningnetwork/lnd/input" + "github.com/lightningnetwork/lnd/keychain" "github.com/lightningnetwork/lnd/lnwallet" "github.com/lightningnetwork/lnd/lnwire" ) // SignAnnouncement signs any type of gossip message that is announced on the // network. -func SignAnnouncement(signer lnwallet.MessageSigner, pubKey *btcec.PublicKey, +func SignAnnouncement(signer lnwallet.MessageSigner, keyLoc keychain.KeyLocator, msg lnwire.Message) (input.Signature, error) { var ( @@ -33,5 +33,5 @@ func SignAnnouncement(signer lnwallet.MessageSigner, pubKey *btcec.PublicKey, return nil, fmt.Errorf("unable to get data to sign: %v", err) } - return signer.SignMessage(pubKey, data) + return signer.SignMessage(keyLoc, data) } diff --git a/peer/test_utils.go b/peer/test_utils.go index 92fb3b672..bc0d41f4d 100644 --- a/peer/test_utils.go +++ b/peer/test_utils.go @@ -43,6 +43,8 @@ const ( var ( // Just use some arbitrary bytes as delivery script. dummyDeliveryScript = channels.AlicesPrivKey + + testKeyLoc = keychain.KeyLocator{Family: keychain.KeyFamilyNodeKey} ) // noUpdate is a function which can be used as a parameter in createTestPeer to @@ -58,10 +60,15 @@ func createTestPeer(notifier chainntnfs.ChainNotifier, mockSwitch *mockMessageSwitch) ( *Brontide, *lnwallet.LightningChannel, func(), error) { + nodeKeyLocator := keychain.KeyLocator{ + Family: keychain.KeyFamilyNodeKey, + } aliceKeyPriv, aliceKeyPub := btcec.PrivKeyFromBytes( btcec.S256(), channels.AlicesPrivKey, ) - aliceKeySigner := &keychain.PrivKeyMessageSigner{PrivKey: aliceKeyPriv} + aliceKeySigner := keychain.NewPrivKeyMessageSigner( + aliceKeyPriv, nodeKeyLocator, + ) bobKeyPriv, bobKeyPub := btcec.PrivKeyFromBytes( btcec.S256(), channels.BobsPrivKey, ) @@ -325,6 +332,7 @@ func createTestPeer(notifier chainntnfs.ChainNotifier, Graph: dbAlice.ChannelGraph(), MessageSigner: nodeSignerAlice, OurPubKey: aliceKeyPub, + OurKeyLoc: testKeyLoc, IsChannelActive: func(lnwire.ChannelID) bool { return true }, ApplyChannelUpdate: func(*lnwire.ChannelUpdate) error { return nil }, }) diff --git a/server.go b/server.go index fe761a666..89eea2264 100644 --- a/server.go +++ b/server.go @@ -157,6 +157,9 @@ type server struct { // to authenticate any incoming connections. identityECDH keychain.SingleKeyECDH + // identityKeyLoc is the key locator for the above wrapped identity key. + identityKeyLoc keychain.KeyLocator + // nodeSigner is an implementation of the MessageSigner implementation // that's backed by the identity private key of the running lnd node. nodeSigner *netann.NodeSigner @@ -473,7 +476,7 @@ func newServer(cfg *Config, listenAddrs []net.Addr, } var serializedPubKey [33]byte - copy(serializedPubKey[:], nodeKeyECDH.PubKey().SerializeCompressed()) + copy(serializedPubKey[:], nodeKeyDesc.PubKey.SerializeCompressed()) // Initialize the sphinx router. replayLog := htlcswitch.NewDecayedLog( @@ -538,8 +541,9 @@ func newServer(cfg *Config, listenAddrs []net.Addr, dbs.chanStateDB.ChannelStateDB(), ), - identityECDH: nodeKeyECDH, - nodeSigner: netann.NewNodeSigner(nodeKeySigner), + identityECDH: nodeKeyECDH, + identityKeyLoc: nodeKeyDesc.KeyLocator, + nodeSigner: netann.NewNodeSigner(nodeKeySigner), listenAddrs: listenAddrs, @@ -633,7 +637,8 @@ func newServer(cfg *Config, listenAddrs []net.Addr, ChanStatusSampleInterval: cfg.ChanStatusSampleInterval, ChanEnableTimeout: cfg.ChanEnableTimeout, ChanDisableTimeout: cfg.ChanDisableTimeout, - OurPubKey: nodeKeyECDH.PubKey(), + OurPubKey: nodeKeyDesc.PubKey, + OurKeyLoc: nodeKeyDesc.KeyLocator, MessageSigner: s.nodeSigner, IsChannelActive: s.htlcSwitch.HasActiveLink, ApplyChannelUpdate: s.applyChannelUpdate, @@ -761,7 +766,7 @@ func newServer(cfg *Config, listenAddrs []net.Addr, Features: s.featureMgr.Get(feature.SetNodeAnn), Color: color, } - copy(selfNode.PubKeyBytes[:], nodeKeyECDH.PubKey().SerializeCompressed()) + copy(selfNode.PubKeyBytes[:], nodeKeyDesc.PubKey.SerializeCompressed()) // Based on the disk representation of the node announcement generated // above, we'll generate a node announcement that can go out on the @@ -774,7 +779,7 @@ func newServer(cfg *Config, listenAddrs []net.Addr, // With the announcement generated, we'll sign it to properly // authenticate the message on the network. authSig, err := netann.SignAnnouncement( - s.nodeSigner, nodeKeyECDH.PubKey(), nodeAnn, + s.nodeSigner, nodeKeyDesc.KeyLocator, nodeAnn, ) if err != nil { return nil, fmt.Errorf("unable to generate signature for "+ @@ -945,9 +950,7 @@ func newServer(cfg *Config, listenAddrs []net.Addr, PinnedSyncers: cfg.Gossip.PinnedSyncers, MaxChannelUpdateBurst: cfg.Gossip.MaxChannelUpdateBurst, ChannelUpdateInterval: cfg.Gossip.ChannelUpdateInterval, - }, - nodeKeyECDH.PubKey(), - ) + }, nodeKeyDesc) s.localChanMgr = &localchans.Manager{ ForAllOutgoingChannels: s.chanRouter.ForAllOutgoingChannels, @@ -1153,7 +1156,8 @@ func newServer(cfg *Config, listenAddrs []net.Addr, s.fundingMgr, err = funding.NewFundingManager(funding.Config{ NoWumboChans: !cfg.ProtocolOptions.Wumbo(), - IDKey: nodeKeyECDH.PubKey(), + IDKey: nodeKeyDesc.PubKey, + IDKeyLoc: nodeKeyDesc.KeyLocator, Wallet: cc.Wallet, PublishTransaction: cc.Wallet.PublishTransaction, UpdateLabel: func(hash chainhash.Hash, label string) error { @@ -1161,15 +1165,7 @@ func newServer(cfg *Config, listenAddrs []net.Addr, }, Notifier: cc.ChainNotifier, FeeEstimator: cc.FeeEstimator, - SignMessage: func(pubKey *btcec.PublicKey, - msg []byte) (input.Signature, error) { - - if pubKey.IsEqual(nodeKeyECDH.PubKey()) { - return s.nodeSigner.SignMessage(pubKey, msg) - } - - return cc.MsgSigner.SignMessage(pubKey, msg) - }, + SignMessage: cc.MsgSigner.SignMessage, CurrentNodeAnnouncement: func() (lnwire.NodeAnnouncement, error) { return s.genNodeAnnouncement(true) }, @@ -2616,7 +2612,7 @@ func (s *server) genNodeAnnouncement(refresh bool, // Otherwise, we'll sign a new update after applying all of the passed // modifiers. err := netann.SignNodeAnnouncement( - s.nodeSigner, s.identityECDH.PubKey(), s.currentNodeAnn, + s.nodeSigner, s.identityKeyLoc, s.currentNodeAnn, modifiers..., ) if err != nil {