@@ -20,6 +20,7 @@ import akka.actor.typed.scaladsl.{ActorContext, Behaviors, StashBuffer}
2020import akka .actor .typed .{ActorRef , Behavior }
2121import akka .event .LoggingAdapter
2222import fr .acinq .bitcoin .ScriptFlags
23+ import fr .acinq .bitcoin .crypto .musig2 .{IndividualNonce , SecretNonce }
2324import fr .acinq .bitcoin .psbt .Psbt
2425import fr .acinq .bitcoin .scalacompat .Crypto .PublicKey
2526import fr .acinq .bitcoin .scalacompat .{ByteVector32 , ByteVector64 , LexicographicalOrdering , OutPoint , Satoshi , SatoshiLong , Script , ScriptWitness , Transaction , TxId , TxIn , TxOut }
@@ -32,7 +33,7 @@ import fr.acinq.eclair.channel.fund.InteractiveTxBuilder.Output.Local
3233import fr .acinq .eclair .channel .fund .InteractiveTxBuilder .Purpose
3334import fr .acinq .eclair .channel .fund .InteractiveTxSigningSession .UnsignedLocalCommit
3435import fr .acinq .eclair .crypto .keymanager .ChannelKeyManager
35- import fr .acinq .eclair .transactions .Transactions .{CommitTx , HtlcTx , InputInfo , TxOwner }
36+ import fr .acinq .eclair .transactions .Transactions .{CommitTx , HtlcTx , InputInfo , SimpleTaprootChannelsStagingCommitmentFormat , TxOwner }
3637import fr .acinq .eclair .transactions .{CommitmentSpec , DirectedHtlc , Scripts , Transactions }
3738import fr .acinq .eclair .wire .protocol ._
3839import fr .acinq .eclair .{Logs , MilliSatoshi , MilliSatoshiLong , NodeParams , UInt64 }
@@ -347,7 +348,8 @@ object InteractiveTxBuilder {
347348 purpose : Purpose ,
348349 localPushAmount : MilliSatoshi ,
349350 remotePushAmount : MilliSatoshi ,
350- wallet : OnChainChannelFunder )(implicit ec : ExecutionContext ): Behavior [Command ] = {
351+ wallet : OnChainChannelFunder ,
352+ nextRemoteNonce_opt : Option [IndividualNonce ])(implicit ec : ExecutionContext ): Behavior [Command ] = {
351353 Behaviors .setup { context =>
352354 // The stash is used to buffer messages that arrive while we're funding the transaction.
353355 // Since the interactive-tx protocol is turn-based, we should not have more than one stashed lightning message.
@@ -366,7 +368,7 @@ object InteractiveTxBuilder {
366368 replyTo ! LocalFailure (InvalidFundingBalances (channelParams.channelId, fundingParams.fundingAmount, nextLocalBalance, nextRemoteBalance))
367369 Behaviors .stopped
368370 } else {
369- val actor = new InteractiveTxBuilder (replyTo, sessionId, nodeParams, channelParams, fundingParams, purpose, localPushAmount, remotePushAmount, wallet, stash, context)
371+ val actor = new InteractiveTxBuilder (replyTo, sessionId, nodeParams, channelParams, fundingParams, purpose, localPushAmount, remotePushAmount, wallet, stash, context, nextRemoteNonce_opt )
370372 actor.start()
371373 }
372374 case Abort => Behaviors .stopped
@@ -391,14 +393,18 @@ private class InteractiveTxBuilder(replyTo: ActorRef[InteractiveTxBuilder.Respon
391393 remotePushAmount : MilliSatoshi ,
392394 wallet : OnChainChannelFunder ,
393395 stash : StashBuffer [InteractiveTxBuilder .Command ],
394- context : ActorContext [InteractiveTxBuilder .Command ])(implicit ec : ExecutionContext ) {
396+ context : ActorContext [InteractiveTxBuilder .Command ],
397+ nextRemoteNonce_opt : Option [IndividualNonce ])(implicit ec : ExecutionContext ) {
395398
396399 import InteractiveTxBuilder ._
397400
398401 private val log = context.log
399402 private val keyManager = nodeParams.channelKeyManager
400403 private val localFundingPubKey : PublicKey = keyManager.fundingPublicKey(channelParams.localParams.fundingKeyPath, purpose.fundingTxIndex).publicKey
401- private val fundingPubkeyScript : ByteVector = Script .write(Script .pay2wsh(Scripts .multiSig2of2(localFundingPubKey, fundingParams.remoteFundingPubKey)))
404+ private val fundingPubkeyScript : ByteVector = channelParams.commitmentFormat match {
405+ case SimpleTaprootChannelsStagingCommitmentFormat => Script .write(Scripts .musig2FundingScript(localFundingPubKey, fundingParams.remoteFundingPubKey))
406+ case _ => Script .write(Script .pay2wsh(Scripts .multiSig2of2(localFundingPubKey, fundingParams.remoteFundingPubKey)))
407+ }
402408 private val remoteNodeId = channelParams.remoteParams.nodeId
403409 private val previousTransactions : Seq [InteractiveTxBuilder .SignedSharedTransaction ] = purpose match {
404410 case rbf : PreviousTxRbf => rbf.previousTransactions
@@ -584,7 +590,7 @@ private class InteractiveTxBuilder(replyTo: ActorRef[InteractiveTxBuilder.Respon
584590 replyTo ! RemoteFailure (UnknownSerialId (fundingParams.channelId, removeOutput.serialId))
585591 unlockAndStop(session)
586592 }
587- case _ : TxComplete =>
593+ case txComplete : TxComplete =>
588594 val next = session.copy(txCompleteReceived = true )
589595 if (next.isComplete) {
590596 validateAndSign(next)
@@ -762,10 +768,21 @@ private class InteractiveTxBuilder(replyTo: ActorRef[InteractiveTxBuilder.Respon
762768 case Right ((localSpec, localCommitTx, remoteSpec, remoteCommitTx, sortedHtlcTxs)) =>
763769 require(fundingTx.txOut(fundingOutputIndex).publicKeyScript == localCommitTx.input.txOut.publicKeyScript, " pubkey script mismatch!" )
764770 val fundingPubKey = keyManager.fundingPublicKey(channelParams.localParams.fundingKeyPath, purpose.fundingTxIndex)
765- val localSigOfRemoteTx = keyManager.sign(remoteCommitTx, fundingPubKey, TxOwner .Remote , channelParams.channelFeatures.commitmentFormat)
771+ val localSigOfRemoteTx = channelParams.commitmentFormat match {
772+ case SimpleTaprootChannelsStagingCommitmentFormat => ByteVector64 .Zeroes
773+ case _ => keyManager.sign(remoteCommitTx, fundingPubKey, TxOwner .Remote , channelParams.channelFeatures.commitmentFormat)
774+ }
775+ val tlvStream : TlvStream [CommitSigTlv ] = channelParams.commitmentFormat match {
776+ case SimpleTaprootChannelsStagingCommitmentFormat =>
777+ val localNonce = keyManager.signingNonce(channelParams.localParams.fundingKeyPath, purpose.fundingTxIndex)
778+ val Right (psig) = keyManager.partialSign(remoteCommitTx, fundingPubKey, fundingParams.remoteFundingPubKey, TxOwner .Remote , localNonce, nextRemoteNonce_opt.get)
779+ TlvStream (CommitSigTlv .PartialSignatureWithNonceTlv (PartialSignatureWithNonce (psig, localNonce._2)))
780+ case _ =>
781+ TlvStream .empty
782+ }
766783 val localPerCommitmentPoint = keyManager.htlcPoint(keyManager.keyPath(channelParams.localParams, channelParams.channelConfig))
767784 val htlcSignatures = sortedHtlcTxs.map(keyManager.sign(_, localPerCommitmentPoint, purpose.remotePerCommitmentPoint, TxOwner .Remote , channelParams.commitmentFormat)).toList
768- val localCommitSig = CommitSig (fundingParams.channelId, localSigOfRemoteTx, htlcSignatures)
785+ val localCommitSig = CommitSig (fundingParams.channelId, localSigOfRemoteTx, htlcSignatures, tlvStream )
769786 val localCommit = UnsignedLocalCommit (purpose.localCommitIndex, localSpec, localCommitTx, htlcTxs = Nil )
770787 val remoteCommit = RemoteCommit (purpose.remoteCommitIndex, remoteSpec, remoteCommitTx.tx.txid, purpose.remotePerCommitmentPoint)
771788 signFundingTx(completeTx, localCommitSig, localCommit, remoteCommit)
0 commit comments