multi: use MessageSignerRing where needed

In this commit, we pass the MessageSignerRing around in places where
Schnorr signing will be needed to sign Gossip 1.75 messages.
This commit is contained in:
Elle Mouton
2023-11-16 14:39:48 +02:00
parent 62a2f64eb7
commit dbbf84a1b1
10 changed files with 161 additions and 19 deletions

View File

@@ -262,14 +262,14 @@ type Config struct {
// use to determine which messages need to be resent for a given peer.
MessageStore GossipMessageStore
// AnnSigner is an instance of the MessageSigner interface which will
// be used to manually sign any outgoing channel updates. The signer
// implementation should be backed by the public key of the backing
// Lightning node.
// AnnSigner is an instance of the MessageSignerRing interface which
// will be used to manually sign any outgoing channel updates. The
// signer implementation should be backed by the public key of the
// backing Lightning node.
//
// TODO(roasbeef): extract ann crafting + sign from fundingMgr into
// here?
AnnSigner lnwallet.MessageSigner
AnnSigner keychain.MessageSignerRing
// ScidCloser is an instance of ClosedChannelTracker that helps the
// gossiper cut down on spam channel announcements for already closed

View File

@@ -262,6 +262,12 @@ type SingleKeyMessageSigner interface {
// hashing it first, with the wrapped private key and returns the
// signature in the compact, public key recoverable format.
SignMessageCompact(message []byte, doubleHash bool) ([]byte, error)
// SignMessageSchnorr signs the given message, single or double SHA256
// hashing it first, with the private key described in the key locator
// and the optional Taproot tweak applied to the private key.
SignMessageSchnorr(keyLoc KeyLocator, msg []byte, doubleHash bool,
taprootTweak, tag []byte) (*schnorr.Signature, error)
}
// ECDHRing is an interface that abstracts away basic low-level ECDH shared key

View File

@@ -3,7 +3,9 @@ package keychain
import (
"github.com/btcsuite/btcd/btcec/v2"
"github.com/btcsuite/btcd/btcec/v2/ecdsa"
"github.com/btcsuite/btcd/btcec/v2/schnorr"
"github.com/btcsuite/btcd/chaincfg/chainhash"
"github.com/btcsuite/btcd/txscript"
)
func NewPubKeyMessageSigner(pubKey *btcec.PublicKey, keyLoc KeyLocator,
@@ -42,6 +44,14 @@ func (p *PubKeyMessageSigner) SignMessageCompact(msg []byte,
return p.digestSigner.SignMessageCompact(p.keyLoc, msg, doubleHash)
}
func (p *PubKeyMessageSigner) SignMessageSchnorr(keyLoc KeyLocator, msg []byte,
doubleHash bool, taprootTweak, tag []byte) (*schnorr.Signature, error) {
return p.digestSigner.SignMessageSchnorr(
keyLoc, msg, doubleHash, taprootTweak, tag,
)
}
func NewPrivKeyMessageSigner(privKey *btcec.PrivateKey,
keyLoc KeyLocator) *PrivKeyMessageSigner {
@@ -88,5 +98,28 @@ func (p *PrivKeyMessageSigner) SignMessageCompact(msg []byte,
return ecdsa.SignCompact(p.privKey, digest, true)
}
func (p *PrivKeyMessageSigner) SignMessageSchnorr(_ KeyLocator, msg []byte,
doubleHash bool, taprootTweak, tag []byte) (*schnorr.Signature, error) {
// If a tag was provided, we need to take the tagged hash of the input.
var digest []byte
switch {
case len(tag) > 0:
taggedHash := chainhash.TaggedHash(tag, msg)
digest = taggedHash[:]
case doubleHash:
digest = chainhash.DoubleHashB(msg)
default:
digest = chainhash.HashB(msg)
}
privKey := p.privKey
if len(taprootTweak) > 0 {
privKey = txscript.TweakTaprootPrivKey(*privKey, taprootTweak)
}
return schnorr.Sign(privKey, digest)
}
var _ SingleKeyMessageSigner = (*PubKeyMessageSigner)(nil)
var _ SingleKeyMessageSigner = (*PrivKeyMessageSigner)(nil)

View File

@@ -571,7 +571,7 @@ func AddInvoice(ctx context.Context, cfg *AddInvoiceConfig,
// key is used to sign the invoice so that the sender
// can derive the true pub key of the recipient.
if !blind {
return cfg.NodeSigner.SignMessageCompact(
return cfg.NodeSigner.SignMessageCompactNoKeyLoc( //nolint:lll
msg, false,
)
}

View File

@@ -205,3 +205,68 @@ func (s *SingleSigner) SignMessage(keyLoc keychain.KeyLocator,
}
return ecdsa.Sign(s.Privkey, digest), nil
}
// SignMessageCompact signs the given message, single or double SHA256 hashing
// it first, with the private key described in the key locator and returns the
// signature in the compact, public key recoverable format.
//
// NOTE: This is part of the keychain.MessageSignerRing interface.
func (s *SingleSigner) SignMessageCompact(keyLoc keychain.KeyLocator,
msg []byte, doubleHash bool) ([]byte, error) {
mockKeyLoc := s.KeyLoc
if s.KeyLoc.IsEmpty() {
mockKeyLoc = idKeyLoc
}
if keyLoc != mockKeyLoc {
return nil, fmt.Errorf("unknown public key")
}
var digest []byte
if doubleHash {
digest = chainhash.DoubleHashB(msg)
} else {
digest = chainhash.HashB(msg)
}
return ecdsa.SignCompact(s.Privkey, digest, true)
}
// SignMessageSchnorr signs the given message, single or double SHA256 hashing
// it first, with the private key described in the key locator and the optional
// Taproot tweak applied to the private key.
//
// NOTE: this is part of the keychain.MessageSignerRing interface.
func (s *SingleSigner) SignMessageSchnorr(keyLoc keychain.KeyLocator,
msg []byte, doubleHash bool, taprootTweak, tag []byte) (
*schnorr.Signature, error) {
mockKeyLoc := s.KeyLoc
if s.KeyLoc.IsEmpty() {
mockKeyLoc = idKeyLoc
}
if keyLoc != mockKeyLoc {
return nil, fmt.Errorf("unknown public key")
}
privKey := s.Privkey
if len(taprootTweak) > 0 {
privKey = txscript.TweakTaprootPrivKey(*privKey, taprootTweak)
}
// If a tag was provided, we need to take the tagged hash of the input.
var digest []byte
switch {
case len(tag) > 0:
taggedHash := chainhash.TaggedHash(tag, msg)
digest = taggedHash[:]
case doubleHash:
digest = chainhash.DoubleHashB(msg)
default:
digest = chainhash.HashB(msg)
}
return schnorr.Sign(privKey, digest)
}

View File

@@ -10,7 +10,6 @@ import (
"github.com/lightningnetwork/lnd/chainntnfs"
"github.com/lightningnetwork/lnd/channeldb"
"github.com/lightningnetwork/lnd/keychain"
"github.com/lightningnetwork/lnd/lnwallet"
"github.com/lightningnetwork/lnd/lnwire"
)
@@ -50,7 +49,7 @@ type ChanStatusConfig struct {
OurKeyLoc keychain.KeyLocator
// MessageSigner signs messages that validate under OurPubKey.
MessageSigner lnwallet.MessageSigner
MessageSigner keychain.MessageSignerRing
// BestBlockView gives access to the current best block.
BestBlockView chainntnfs.BestBlockView

View File

@@ -9,7 +9,6 @@ import (
"github.com/btcsuite/btcd/chaincfg/chainhash"
"github.com/lightningnetwork/lnd/channeldb/models"
"github.com/lightningnetwork/lnd/keychain"
"github.com/lightningnetwork/lnd/lnwallet"
"github.com/lightningnetwork/lnd/lnwire"
)
@@ -57,8 +56,9 @@ func ChanUpdSetTimestamp(update *lnwire.ChannelUpdate1) {
// monotonically increase from the prior.
//
// NOTE: This method modifies the given update.
func SignChannelUpdate(signer lnwallet.MessageSigner, keyLoc keychain.KeyLocator,
update *lnwire.ChannelUpdate1, mods ...ChannelUpdateModifier) error {
func SignChannelUpdate(signer keychain.MessageSignerRing,
keyLoc keychain.KeyLocator, update *lnwire.ChannelUpdate1,
mods ...ChannelUpdateModifier) error {
// Apply the requested changes to the channel update.
for _, modifier := range mods {

View File

@@ -14,6 +14,8 @@ import (
)
type mockSigner struct {
keychain.MessageSignerRing
err error
}
@@ -43,7 +45,7 @@ type updateDisableTest struct {
startEnabled bool
disable bool
startTime time.Time
signer lnwallet.MessageSigner
signer keychain.MessageSignerRing
expErr error
}

View File

@@ -4,8 +4,8 @@ import (
"fmt"
"github.com/btcsuite/btcd/btcec/v2/ecdsa"
"github.com/btcsuite/btcd/btcec/v2/schnorr"
"github.com/lightningnetwork/lnd/keychain"
"github.com/lightningnetwork/lnd/lnwallet"
)
// NodeSigner is an implementation of the MessageSigner interface backed by the
@@ -43,15 +43,52 @@ func (n *NodeSigner) SignMessage(keyLoc keychain.KeyLocator,
return sig, nil
}
// SignMessageCompact signs a single or double sha256 digest of the msg
// SignMessageCompactNoKeyLoc signs a single or double sha256 digest of the msg
// parameter under the resident node's private key. The returned signature is a
// pubkey-recoverable signature.
func (n *NodeSigner) SignMessageCompact(msg []byte, doubleHash bool) ([]byte,
error) {
// pubkey-recoverable signature. No key locator is required for this since the
// NodeSigner already has the key to sign with.
func (n *NodeSigner) SignMessageCompactNoKeyLoc(msg []byte, doubleHash bool) (
[]byte, error) {
return n.keySigner.SignMessageCompact(msg, doubleHash)
}
// SignMessageCompact signs the given message, single or double SHA256 hashing
// it first, with the private key described in the key locator and returns the
// signature in the compact, public key recoverable format.
//
// NOTE: this is part of the keychain.MessageSignerRing interface.
func (n *NodeSigner) SignMessageCompact(keyLoc keychain.KeyLocator, msg []byte,
doubleHash bool) ([]byte, 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 keyLoc != n.keySigner.KeyLocator() {
return nil, fmt.Errorf("unknown public key locator")
}
return n.SignMessageCompactNoKeyLoc(msg, doubleHash)
}
// SignMessageSchnorr signs the given message, single or double SHA256 hashing
// it first, with the private key described in the key locator and the optional
// Taproot tweak applied to the private key.
//
// NOTE: this is part of the keychain.MessageSignerRing interface.
func (n *NodeSigner) SignMessageSchnorr(keyLoc keychain.KeyLocator, msg []byte,
doubleHash bool, taprootTweak, tag []byte) (*schnorr.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 keyLoc != n.keySigner.KeyLocator() {
return nil, fmt.Errorf("unknown public key locator")
}
return n.keySigner.SignMessageSchnorr(
keyLoc, msg, doubleHash, taprootTweak, tag,
)
}
// A compile time check to ensure that NodeSigner implements the MessageSigner
// interface.
var _ lnwallet.MessageSigner = (*NodeSigner)(nil)
var _ keychain.MessageSignerRing = (*NodeSigner)(nil)

View File

@@ -1671,7 +1671,7 @@ func (r *rpcServer) SignMessage(_ context.Context,
}
in.Msg = append(signedMsgPrefix, in.Msg...)
sigBytes, err := r.server.nodeSigner.SignMessageCompact(
sigBytes, err := r.server.nodeSigner.SignMessageCompactNoKeyLoc(
in.Msg, !in.SingleHash,
)
if err != nil {