mirror of
https://github.com/lightningnetwork/lnd.git
synced 2025-08-29 15:11:09 +02:00
netann: validation and verification funcs for ChannelAnnouncement2
This commit is contained in:
@@ -6,9 +6,26 @@ import (
|
||||
"fmt"
|
||||
|
||||
"github.com/btcsuite/btcd/btcec/v2"
|
||||
"github.com/btcsuite/btcd/btcec/v2/schnorr"
|
||||
"github.com/btcsuite/btcd/btcec/v2/schnorr/musig2"
|
||||
"github.com/btcsuite/btcd/chaincfg/chainhash"
|
||||
"github.com/lightningnetwork/lnd/channeldb/models"
|
||||
"github.com/lightningnetwork/lnd/lnwire"
|
||||
"github.com/lightningnetwork/lnd/tlv"
|
||||
)
|
||||
|
||||
const (
|
||||
// chanAnn2MsgName is a string representing the name of the
|
||||
// ChannelAnnouncement2 message. This string will be used during the
|
||||
// construction of the tagged hash message to be signed when producing
|
||||
// the signature for the ChannelAnnouncement2 message.
|
||||
chanAnn2MsgName = "channel_announcement_2"
|
||||
|
||||
// chanAnn2SigFieldName is the name of the signature field of the
|
||||
// ChannelAnnouncement2 message. This string will be used during the
|
||||
// construction of the tagged hash message to be signed when producing
|
||||
// the signature for the ChannelAnnouncement2 message.
|
||||
chanAnn2SigFieldName = "signature"
|
||||
)
|
||||
|
||||
// CreateChanAnnouncement is a helper function which creates all channel
|
||||
@@ -94,10 +111,14 @@ func CreateChanAnnouncement(chanProof *models.ChannelAuthProof,
|
||||
type FetchPkScript func(*lnwire.ShortChannelID) ([]byte, error)
|
||||
|
||||
// ValidateChannelAnn validates the channel announcement.
|
||||
func ValidateChannelAnn(a lnwire.ChannelAnnouncement, _ FetchPkScript) error {
|
||||
func ValidateChannelAnn(a lnwire.ChannelAnnouncement,
|
||||
fetchPkScript FetchPkScript) error {
|
||||
|
||||
switch ann := a.(type) {
|
||||
case *lnwire.ChannelAnnouncement1:
|
||||
return validateChannelAnn1(ann)
|
||||
case *lnwire.ChannelAnnouncement2:
|
||||
return validateChannelAnn2(ann, fetchPkScript)
|
||||
default:
|
||||
return fmt.Errorf("unhandled implementation of "+
|
||||
"lnwire.ChannelAnnouncement: %T", a)
|
||||
@@ -175,3 +196,96 @@ func validateChannelAnn1(a *lnwire.ChannelAnnouncement1) error {
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// validateChannelAnn2 validates the channel announcement message and checks
|
||||
// that message signature covers the announcement message.
|
||||
func validateChannelAnn2(a *lnwire.ChannelAnnouncement2,
|
||||
fetchPkScript FetchPkScript) error {
|
||||
|
||||
dataHash, err := ChanAnn2DigestToSign(a)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
sig, err := a.Signature.ToSignature()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
nodeKey1, err := btcec.ParsePubKey(a.NodeID1.Val[:])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
nodeKey2, err := btcec.ParsePubKey(a.NodeID2.Val[:])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
keys := []*btcec.PublicKey{
|
||||
nodeKey1, nodeKey2,
|
||||
}
|
||||
|
||||
// If the bitcoin keys are provided in the announcement, then it is
|
||||
// assumed that the signature of the announcement is a 4-of-4 MuSig2
|
||||
// over the bitcoin keys and node ID keys.
|
||||
if a.BitcoinKey1.IsSome() && a.BitcoinKey2.IsSome() {
|
||||
var (
|
||||
btcKey1 tlv.RecordT[tlv.TlvType12, [33]byte]
|
||||
btcKey2 tlv.RecordT[tlv.TlvType14, [33]byte]
|
||||
)
|
||||
|
||||
btcKey1 = a.BitcoinKey1.UnwrapOr(btcKey1)
|
||||
btcKey2 = a.BitcoinKey2.UnwrapOr(btcKey2)
|
||||
|
||||
bitcoinKey1, err := btcec.ParsePubKey(btcKey1.Val[:])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
bitcoinKey2, err := btcec.ParsePubKey(btcKey2.Val[:])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
keys = append(keys, bitcoinKey1, bitcoinKey2)
|
||||
} else {
|
||||
// If bitcoin keys are not provided, then we need to get the
|
||||
// on-chain output key since this will be the 3rd key in the
|
||||
// 3-of-3 MuSig2 signature.
|
||||
pkScript, err := fetchPkScript(&a.ShortChannelID.Val)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
outputKey, err := schnorr.ParsePubKey(pkScript[2:])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
keys = append(keys, outputKey)
|
||||
}
|
||||
|
||||
aggKey, _, _, err := musig2.AggregateKeys(keys, true)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if !sig.Verify(dataHash.CloneBytes(), aggKey.FinalKey) {
|
||||
return fmt.Errorf("invalid sig")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ChanAnn2DigestToSign computes the digest of the message to be signed.
|
||||
func ChanAnn2DigestToSign(a *lnwire.ChannelAnnouncement2) (*chainhash.Hash,
|
||||
error) {
|
||||
|
||||
data, err := a.DataToSign()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return MsgHash(chanAnn2MsgName, chanAnn2SigFieldName, data), nil
|
||||
}
|
||||
|
Reference in New Issue
Block a user