@@ -11,8 +11,10 @@ import (
1111 "github.com/btcsuite/btcd/btcec/v2/schnorr"
1212 "github.com/btcsuite/btcd/btcec/v2/schnorr/musig2"
1313 "github.com/btcsuite/btcd/btcutil"
14+ "github.com/btcsuite/btcd/chaincfg/chainhash"
1415 "github.com/btcsuite/btcd/txscript"
1516 "github.com/btcsuite/btcd/wire"
17+ "github.com/lightningnetwork/lnd/fn"
1618 "github.com/lightningnetwork/lnd/lnutils"
1719 "golang.org/x/crypto/ripemd160"
1820)
@@ -197,27 +199,59 @@ func GenFundingPkScript(aPub, bPub []byte, amt int64) ([]byte, *wire.TxOut, erro
197199 return witnessScript , wire .NewTxOut (amt , pkScript ), nil
198200}
199201
202+ // fundingScriptOpts is a functional option that can be used to modify the way
203+ // the funding pkScript is created.
204+ type fundingScriptOpts struct {
205+ tapscriptRoot fn.Option [chainhash.Hash ]
206+ }
207+
208+ // FundingScriptOpt is a functional option that can be used to modify the way
209+ // the funding script is created.
210+ type FundingScriptOpt func (* fundingScriptOpts )
211+
212+ // defaultFundingScriptOpts returns a new instance of the default
213+ // fundingScriptOpts.
214+ func defaultFundingScriptOpts () * fundingScriptOpts {
215+ return & fundingScriptOpts {}
216+ }
217+
218+ // WithTapscriptRoot is a functional option that can be used to specify the
219+ // tapscript root for a MuSig2 funding output.
220+ func WithTapscriptRoot (root chainhash.Hash ) FundingScriptOpt {
221+ return func (o * fundingScriptOpts ) {
222+ o .tapscriptRoot = fn .Some (root )
223+ }
224+ }
225+
200226// GenTaprootFundingScript constructs the taproot-native funding output that
201- // uses musig2 to create a single aggregated key to anchor the channel.
227+ // uses MuSig2 to create a single aggregated key to anchor the channel.
202228func GenTaprootFundingScript (aPub , bPub * btcec.PublicKey ,
203- amt int64 ) ([]byte , * wire.TxOut , error ) {
229+ amt int64 , opts ... FundingScriptOpt ) ([]byte , * wire.TxOut , error ) {
230+
231+ options := defaultFundingScriptOpts ()
232+ for _ , optFunc := range opts {
233+ optFunc (options )
234+ }
235+
236+ muSig2Opt := musig2 .WithBIP86KeyTweak ()
237+ options .tapscriptRoot .WhenSome (func (scriptRoot chainhash.Hash ) {
238+ muSig2Opt = musig2 .WithTaprootKeyTweak (scriptRoot [:])
239+ })
204240
205241 // Similar to the existing p2wsh funding script, we'll always make sure
206242 // we sort the keys before any major operations. In order to ensure
207243 // that there's no other way this output can be spent, we'll use a BIP
208- // 86 tweak here during aggregation.
209- //
210- // TODO(roasbeef): revisit if BIP 86 is needed here?
244+ // 86 tweak here during aggregation, unless the user has explicitly
245+ // specified a tapscript root.
211246 combinedKey , _ , _ , err := musig2 .AggregateKeys (
212- []* btcec.PublicKey {aPub , bPub }, true ,
213- musig2 .WithBIP86KeyTweak (),
247+ []* btcec.PublicKey {aPub , bPub }, true , muSig2Opt ,
214248 )
215249 if err != nil {
216250 return nil , nil , fmt .Errorf ("unable to combine keys: %w" , err )
217251 }
218252
219253 // Now that we have the combined key, we can create a taproot pkScript
220- // from this, and then make the txout given the amount.
254+ // from this, and then make the txOut given the amount.
221255 pkScript , err := PayToTaprootScript (combinedKey .FinalKey )
222256 if err != nil {
223257 return nil , nil , fmt .Errorf ("unable to make taproot " +
@@ -227,7 +261,7 @@ func GenTaprootFundingScript(aPub, bPub *btcec.PublicKey,
227261 txOut := wire .NewTxOut (amt , pkScript )
228262
229263 // For the "witness program" we just return the raw pkScript since the
230- // output we create can _only_ be spent with a musig2 signature.
264+ // output we create can _only_ be spent with a MuSig2 signature.
231265 return pkScript , txOut , nil
232266}
233267
0 commit comments