77 "github.com/btcsuite/btcd/btcec/v2"
88 "github.com/btcsuite/btcd/btcec/v2/schnorr"
99 "github.com/btcsuite/btcd/btcec/v2/schnorr/musig2"
10+ "github.com/btcsuite/btcd/btcutil"
1011 "github.com/btcsuite/btcd/chaincfg/chainhash"
12+ "github.com/btcsuite/btcd/txscript"
1113 "github.com/lightningnetwork/lnd/graph/db/models"
1214 "github.com/lightningnetwork/lnd/lnwire"
1315 "github.com/lightningnetwork/lnd/tlv"
@@ -104,7 +106,8 @@ func CreateChanAnnouncement(chanProof *models.ChannelAuthProof,
104106
105107// FetchPkScript defines a function that can be used to fetch the output script
106108// for the transaction with the given SCID.
107- type FetchPkScript func (lnwire.ShortChannelID ) ([]byte , error )
109+ type FetchPkScript func (lnwire.ShortChannelID ) (txscript.ScriptClass ,
110+ btcutil.Address , error )
108111
109112// ValidateChannelAnn validates the channel announcement.
110113func ValidateChannelAnn (a lnwire.ChannelAnnouncement ,
@@ -198,24 +201,124 @@ func validateChannelAnn1(a *lnwire.ChannelAnnouncement1) error {
198201func validateChannelAnn2 (a * lnwire.ChannelAnnouncement2 ,
199202 fetchPkScript FetchPkScript ) error {
200203
204+ // Next, we fetch the funding transaction's PK script. We need this so
205+ // that we know what type of channel we will be validating: P2WSH or
206+ // P2TR.
207+ scriptClass , scriptAddr , err := fetchPkScript (a .ShortChannelID .Val )
208+ if err != nil {
209+ return err
210+ }
211+
212+ var keys []* btcec.PublicKey
213+
214+ switch scriptClass {
215+ case txscript .WitnessV0ScriptHashTy :
216+ keys , err = chanAnn2P2WSHMuSig2Keys (a )
217+ if err != nil {
218+ return err
219+ }
220+ case txscript .WitnessV1TaprootTy :
221+ keys , err = chanAnn2P2TRMuSig2Keys (a , scriptAddr )
222+ if err != nil {
223+ return err
224+ }
225+ default :
226+ return fmt .Errorf ("invalid on-chain pk script type for " +
227+ "channel_announcement_2: %s" , scriptClass )
228+ }
229+
230+ // Do a MuSig2 aggregation of the keys to obtain the aggregate key that
231+ // the signature will be validated against.
232+ aggKey , _ , _ , err := musig2 .AggregateKeys (keys , true )
233+ if err != nil {
234+ return err
235+ }
236+
237+ // Get the message that the signature should have signed.
201238 dataHash , err := ChanAnn2DigestToSign (a )
202239 if err != nil {
203240 return err
204241 }
205242
243+ // Obtain the signature.
206244 sig , err := a .Signature .Val .ToSignature ()
207245 if err != nil {
208246 return err
209247 }
210248
249+ // Check that the signature is valid for the aggregate key given the
250+ // message digest.
251+ if ! sig .Verify (dataHash .CloneBytes (), aggKey .FinalKey ) {
252+ return fmt .Errorf ("invalid sig" )
253+ }
254+
255+ return nil
256+ }
257+
258+ // chanAnn2P2WSHMuSig2Keys returns the set of keys that should be used to
259+ // construct the aggregate key that the signature in an
260+ // lnwire.ChannelAnnouncement2 message should be verified against in the case
261+ // where the channel being announced is a P2WSH channel.
262+ func chanAnn2P2WSHMuSig2Keys (a * lnwire.ChannelAnnouncement2 ) (
263+ []* btcec.PublicKey , error ) {
264+
211265 nodeKey1 , err := btcec .ParsePubKey (a .NodeID1 .Val [:])
212266 if err != nil {
213- return err
267+ return nil , err
214268 }
215269
216270 nodeKey2 , err := btcec .ParsePubKey (a .NodeID2 .Val [:])
217271 if err != nil {
218- return err
272+ return nil , err
273+ }
274+
275+ btcKeyMissingErrString := "bitcoin key %d missing for announcement " +
276+ "of a P2WSH channel"
277+
278+ btcKey1Bytes , err := a .BitcoinKey1 .UnwrapOrErr (
279+ fmt .Errorf (btcKeyMissingErrString , 1 ),
280+ )
281+ if err != nil {
282+ return nil , err
283+ }
284+
285+ btcKey1 , err := btcec .ParsePubKey (btcKey1Bytes .Val [:])
286+ if err != nil {
287+ return nil , err
288+ }
289+
290+ btcKey2Bytes , err := a .BitcoinKey2 .UnwrapOrErr (
291+ fmt .Errorf (btcKeyMissingErrString , 2 ),
292+ )
293+ if err != nil {
294+ return nil , err
295+ }
296+
297+ btcKey2 , err := btcec .ParsePubKey (btcKey2Bytes .Val [:])
298+ if err != nil {
299+ return nil , err
300+ }
301+
302+ return []* btcec.PublicKey {
303+ nodeKey1 , nodeKey2 , btcKey1 , btcKey2 ,
304+ }, nil
305+ }
306+
307+ // chanAnn2P2TRMuSig2Keys returns the set of keys that should be used to
308+ // construct the aggregate key that the signature in an
309+ // lnwire.ChannelAnnouncement2 message should be verified against in the case
310+ // where the channel being announced is a P2TR channel.
311+ func chanAnn2P2TRMuSig2Keys (a * lnwire.ChannelAnnouncement2 ,
312+ scriptAddr btcutil.Address ) ([]* btcec.PublicKey , error ) {
313+
314+ nodeKey1 , err := btcec .ParsePubKey (a .NodeID1 .Val [:])
315+ if err != nil {
316+ return nil , err
317+ }
318+
319+ nodeKey2 , err := btcec .ParsePubKey (a .NodeID2 .Val [:])
320+ if err != nil {
321+ return nil , err
219322 }
220323
221324 keys := []* btcec.PublicKey {
@@ -236,42 +339,29 @@ func validateChannelAnn2(a *lnwire.ChannelAnnouncement2,
236339
237340 bitcoinKey1 , err := btcec .ParsePubKey (btcKey1 .Val [:])
238341 if err != nil {
239- return err
342+ return nil , err
240343 }
241344
242345 bitcoinKey2 , err := btcec .ParsePubKey (btcKey2 .Val [:])
243346 if err != nil {
244- return err
347+ return nil , err
245348 }
246349
247350 keys = append (keys , bitcoinKey1 , bitcoinKey2 )
248351 } else {
249- // If bitcoin keys are not provided, then we need to get the
250- // on-chain output key since this will be the 3rd key in the
251- // 3-of-3 MuSig2 signature.
252- pkScript , err := fetchPkScript (a .ShortChannelID .Val )
253- if err != nil {
254- return err
255- }
256-
257- outputKey , err := schnorr .ParsePubKey (pkScript [2 :])
352+ // If bitcoin keys are not provided, then the on-chain output
353+ // key is considered the 3rd key in the 3-of-3 MuSig2 signature.
354+ outputKey , err := schnorr .ParsePubKey (
355+ scriptAddr .ScriptAddress (),
356+ )
258357 if err != nil {
259- return err
358+ return nil , err
260359 }
261360
262361 keys = append (keys , outputKey )
263362 }
264363
265- aggKey , _ , _ , err := musig2 .AggregateKeys (keys , true )
266- if err != nil {
267- return err
268- }
269-
270- if ! sig .Verify (dataHash .CloneBytes (), aggKey .FinalKey ) {
271- return fmt .Errorf ("invalid sig" )
272- }
273-
274- return nil
364+ return keys , nil
275365}
276366
277367// ChanAnn2DigestToSign computes the digest of the message to be signed.
0 commit comments