multi: use key locator for lnwallet.MessageSigner

To simplify the message signing API even further, we refactor the
lnwallet.MessageSigner interface to use a key locator instead of the
public key to identify which key should be signed with.
This commit is contained in:
Oliver Gugger 2021-09-23 16:54:30 +02:00
parent afa03f22cc
commit e79d59dd4c
No known key found for this signature in database
GPG key ID: 8E4256593F177720
19 changed files with 184 additions and 102 deletions

View file

@ -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 {

View file

@ -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.

View file

@ -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 {

View file

@ -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,

View file

@ -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)

View file

@ -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)

View file

@ -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")
}

View file

@ -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

View file

@ -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

View file

@ -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())
}

View file

@ -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 {

View file

@ -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,

View file

@ -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
}

View file

@ -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,
)

View file

@ -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
}

View file

@ -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.

View file

@ -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)
}

View file

@ -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 },
})

View file

@ -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 {