From 7fe7d4d1ffbbc336b3a77815431cfee19a10c26f Mon Sep 17 00:00:00 2001 From: sstone Date: Thu, 18 Sep 2025 14:52:20 +0200 Subject: [PATCH 1/3] Use bitcoin-kmp 0.26.0 bitcoin-kmp 0.26.0 uses secp256k1-kmp 0.19.0 which includes https://github.com/ACINQ/secp256k1-kmp/pull/126. --- gradle/libs.versions.toml | 4 +-- .../acinq/lightning/channel/InteractiveTx.kt | 34 +++++++++++++++++-- .../transactions/TransactionsTestsCommon.kt | 5 +-- 3 files changed, 36 insertions(+), 7 deletions(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index eaa29a4e3..64b6ab3b8 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -4,8 +4,8 @@ kotlinx-coroutines = "1.10.2" kotlinx-datetime = "0.6.2" kotlinx-serialization = "1.8.1" ktor = "3.1.2" -bitcoinkmp = "0.25.1" # when upgrading bitcoin-kmp, keep secpjnijvm in sync! -secpjnijvm = "0.18.0" +bitcoinkmp = "0.26.0" # when upgrading bitcoin-kmp, keep secpjnijvm in sync! +secpjnijvm = "0.19.0" kermit = "2.0.5" slf4j = "2.0.16" diff --git a/modules/core/src/commonMain/kotlin/fr/acinq/lightning/channel/InteractiveTx.kt b/modules/core/src/commonMain/kotlin/fr/acinq/lightning/channel/InteractiveTx.kt index 2a48ceef1..6ed570208 100644 --- a/modules/core/src/commonMain/kotlin/fr/acinq/lightning/channel/InteractiveTx.kt +++ b/modules/core/src/commonMain/kotlin/fr/acinq/lightning/channel/InteractiveTx.kt @@ -343,6 +343,7 @@ data class FundingContributions(val inputs: List, v swapInProtocol.userPublicKey, swapInProtocol.serverPublicKey, swapInProtocol.userRefundKey, swapInProtocol.refundDelay ) } + else -> InteractiveTxInput.LocalLegacySwapIn( 0, i.previousTx.stripInputWitnesses(), @@ -714,6 +715,7 @@ data class InteractiveTxSession( Pair(next, InteractiveTxSessionAction.SendMessage(txComplete)) } } + is Either.Left -> { val inputOutgoing = msg.value val txAddInput = when (inputOutgoing) { @@ -722,27 +724,32 @@ data class InteractiveTxSession( val swapInParams = TxAddInputTlv.SwapInParamsLegacy(swapInKeys.userPublicKey, swapInKeys.remoteServerPublicKey, swapInKeys.refundDelay) TxAddInput(fundingParams.channelId, inputOutgoing.serialId, inputOutgoing.previousTx, inputOutgoing.previousTxOutput, inputOutgoing.sequence, TlvStream(swapInParams)) } + is InteractiveTxInput.LocalSwapIn -> { val swapInProtocol = swapInKeys.getSwapInProtocol(inputOutgoing.addressIndex) val swapInParams = TxAddInputTlv.SwapInParams(swapInProtocol.userPublicKey, swapInProtocol.serverPublicKey, swapInProtocol.userRefundKey, swapInProtocol.refundDelay) TxAddInput(fundingParams.channelId, inputOutgoing.serialId, inputOutgoing.previousTx, inputOutgoing.previousTxOutput, inputOutgoing.sequence, TlvStream(swapInParams)) } + is InteractiveTxInput.Shared -> TxAddInput(fundingParams.channelId, inputOutgoing.serialId, inputOutgoing.outPoint, inputOutgoing.sequence) } val nextSecretNonces = when (inputOutgoing) { // Generate a secret nonce for this input if we don't already have one. is InteractiveTxInput.LocalSwapIn -> when (secretNonces[inputOutgoing.serialId]) { null -> { - val secretNonce = Musig2.generateNonce(randomBytes32(), swapInKeys.userPrivateKey, swapInKeys.userPublicKey, listOf(swapInKeys.userPublicKey, swapInKeys.remoteServerPublicKey), null, null) + val secretNonce = Musig2.generateNonce(randomBytes32(), Either.Right(swapInKeys.userPublicKey), listOf(swapInKeys.userPublicKey, swapInKeys.remoteServerPublicKey), null, null) secretNonces + (inputOutgoing.serialId to secretNonce) } + else -> secretNonces } + else -> secretNonces } val next = copy(toSend = toSend.tail(), localInputs = localInputs + msg.value, txCompleteSent = null, secretNonces = nextSecretNonces) Pair(next, InteractiveTxSessionAction.SendMessage(txAddInput)) } + is Either.Right -> { val outputOutgoing = msg.value val next = copy(toSend = toSend.tail(), localOutputs = localOutputs + outputOutgoing, txCompleteSent = null) @@ -796,6 +803,7 @@ data class InteractiveTxSession( message.swapInParams.userRefundKey, message.swapInParams.refundDelay ) + message.swapInParamsLegacy != null -> InteractiveTxInput.RemoteLegacySwapIn( message.serialId, outpoint, @@ -805,6 +813,7 @@ data class InteractiveTxSession( message.swapInParamsLegacy.serverKey, message.swapInParamsLegacy.refundDelay ) + else -> InteractiveTxInput.RemoteOnly(message.serialId, outpoint, txOut, message.sequence) } } @@ -819,11 +828,13 @@ data class InteractiveTxSession( // Generate a secret nonce for this input if we don't already have one. is InteractiveTxInput.RemoteSwapIn -> when (secretNonces[input.serialId]) { null -> { - val secretNonce = Musig2.generateNonce(randomBytes32(), swapInKeys.localServerPrivateKey(remoteNodeId), input.serverKey, listOf(input.userKey, input.serverKey), null, null) + val secretNonce = Musig2.generateNonce(randomBytes32(), Either.Right(input.serverKey), listOf(input.userKey, input.serverKey), null, null) secretNonces + (input.serialId to secretNonce) } + else -> secretNonces } + else -> secretNonces } val session1 = this.copy(remoteInputs = remoteInputs + input, inputsReceivedCount = inputsReceivedCount + 1, txCompleteReceived = null, secretNonces = secretNonces1) @@ -859,12 +870,14 @@ data class InteractiveTxSession( { next -> next.send() } ) } + is TxAddOutput -> { receiveOutput(message).fold( { f -> Pair(this, f) }, { output -> copy(remoteOutputs = remoteOutputs + output, outputsReceivedCount = outputsReceivedCount + 1, txCompleteReceived = null).send() } ) } + is TxRemoveInput -> { val remoteInputs1 = remoteInputs.filterNot { i -> (i as InteractiveTxInput).serialId == message.serialId } if (remoteInputs.size != remoteInputs1.size) { @@ -874,6 +887,7 @@ data class InteractiveTxSession( Pair(this, InteractiveTxSessionAction.UnknownSerialId(message.channelId, message.serialId)) } } + is TxRemoveOutput -> { val remoteOutputs1 = remoteOutputs.filterNot { o -> (o as InteractiveTxOutput).serialId == message.serialId } if (remoteOutputs.size != remoteOutputs1.size) { @@ -883,6 +897,7 @@ data class InteractiveTxSession( Pair(this, InteractiveTxSessionAction.UnknownSerialId(message.channelId, message.serialId)) } } + is TxComplete -> { val next = copy(txCompleteReceived = message) if (next.isComplete) { @@ -1028,6 +1043,7 @@ data class InteractiveTxSigningSession( is Either.Left -> localCommit.value.commitTx.input is Either.Right -> localCommit.value.publishableTxs.commitTx.input } + // This value tells our peer whether we need them to retransmit their commit_sig on reconnection or not. val reconnectNextLocalCommitmentNumber = when (localCommit) { is Either.Left -> localCommit.value.index @@ -1039,7 +1055,8 @@ data class InteractiveTxSigningSession( is Either.Left -> { val localCommitIndex = localCommit.value.index val localPerCommitmentPoint = channelKeys.commitmentPoint(localCommitIndex) - when (val signedLocalCommit = LocalCommit.fromCommitSig(channelKeys, channelParams, fundingTxIndex, fundingParams.remoteFundingPubkey, commitInput, remoteCommitSig, localCommitIndex, localCommit.value.spec, localPerCommitmentPoint, logger)) { + when (val signedLocalCommit = + LocalCommit.fromCommitSig(channelKeys, channelParams, fundingTxIndex, fundingParams.remoteFundingPubkey, commitInput, remoteCommitSig, localCommitIndex, localCommit.value.spec, localPerCommitmentPoint, logger)) { is Either.Left -> { val fundingKey = channelKeys.fundingKey(fundingTxIndex) val localSigOfLocalTx = Transactions.sign(localCommit.value.commitTx, fundingKey) @@ -1051,6 +1068,7 @@ data class InteractiveTxSigningSession( logger.info { "signedLocalCommitTx=$signedLocalCommitTx" } Pair(this, InteractiveTxSigningSessionAction.AbortFundingAttempt(signedLocalCommit.value)) } + is Either.Right -> { if (shouldSignFirst(fundingParams.isInitiator, channelParams, fundingTx.tx)) { val fundingStatus = LocalFundingStatus.UnconfirmedFundingTx(fundingTx, fundingParams, currentBlockHeight) @@ -1063,6 +1081,7 @@ data class InteractiveTxSigningSession( } } } + is Either.Right -> Pair(this, InteractiveTxSigningSessionAction.WaitForTxSigs) } } @@ -1180,6 +1199,7 @@ sealed class QuiescenceNegotiation : SpliceStatus() { abstract class Initiator : QuiescenceNegotiation() { abstract val command: ChannelCommand.Commitment.Splice.Request } + abstract class NonInitiator : QuiescenceNegotiation() } @@ -1188,16 +1208,22 @@ sealed class QuiescentSpliceStatus : SpliceStatus() sealed class SpliceStatus { data object None : SpliceStatus() + /** We stop sending new updates and wait for our updates to be added to the local and remote commitments. */ data class QuiescenceRequested(override val command: ChannelCommand.Commitment.Splice.Request) : QuiescenceNegotiation.Initiator() + /** Our updates have been added to the local and remote commitments, we wait for our peer to do the same. */ data class InitiatorQuiescent(override val command: ChannelCommand.Commitment.Splice.Request) : QuiescenceNegotiation.Initiator() + /** Our peer has asked us to stop sending new updates and wait for our updates to be added to the local and remote commitments. */ data class ReceivedStfu(val stfu: Stfu) : QuiescenceNegotiation.NonInitiator() + /** Our updates have been added to the local and remote commitments, we wait for our peer to use the now quiescent channel. */ data object NonInitiatorQuiescent : QuiescentSpliceStatus() + /** We told our peer we want to splice funds in the channel. */ data class Requested(val command: ChannelCommand.Commitment.Splice.Request, val spliceInit: SpliceInit) : QuiescentSpliceStatus() + /** We both agreed to splice and are building the splice transaction. */ data class InProgress( val replyTo: CompletableDeferred?, @@ -1205,8 +1231,10 @@ sealed class SpliceStatus { val liquidityPurchase: LiquidityAds.Purchase?, val origins: List ) : QuiescentSpliceStatus() + /** The splice transaction has been negotiated, we're exchanging signatures. */ data class WaitingForSigs(val session: InteractiveTxSigningSession, val liquidityPurchase: LiquidityAds.Purchase?, val origins: List) : QuiescentSpliceStatus() + /** The splice attempt was aborted by us, we're waiting for our peer to ack. */ data object Aborted : QuiescentSpliceStatus() } diff --git a/modules/core/src/commonTest/kotlin/fr/acinq/lightning/transactions/TransactionsTestsCommon.kt b/modules/core/src/commonTest/kotlin/fr/acinq/lightning/transactions/TransactionsTestsCommon.kt index 715c3a115..e62e27802 100644 --- a/modules/core/src/commonTest/kotlin/fr/acinq/lightning/transactions/TransactionsTestsCommon.kt +++ b/modules/core/src/commonTest/kotlin/fr/acinq/lightning/transactions/TransactionsTestsCommon.kt @@ -8,6 +8,7 @@ import fr.acinq.bitcoin.Script.pay2wsh import fr.acinq.bitcoin.Script.write import fr.acinq.bitcoin.crypto.Pack import fr.acinq.bitcoin.crypto.musig2.Musig2 +import fr.acinq.bitcoin.utils.Either import fr.acinq.lightning.CltvExpiry import fr.acinq.lightning.CltvExpiryDelta import fr.acinq.lightning.Lightning.randomBytes32 @@ -514,8 +515,8 @@ class TransactionsTestsCommon : LightningTestSuite() { ) // The first step of a musig2 signing session is to exchange nonces. // If participants are disconnected before the end of the signing session, they must start again with fresh nonces. - val userNonce = Musig2.generateNonce(randomBytes32(), userPrivateKey, userPrivateKey.publicKey(), listOf(userPrivateKey.publicKey(), serverPrivateKey.publicKey()), null, null) - val serverNonce = Musig2.generateNonce(randomBytes32(), serverPrivateKey, serverPrivateKey.publicKey(), listOf(serverPrivateKey.publicKey(), userPrivateKey.publicKey()), null, null) + val userNonce = Musig2.generateNonce(randomBytes32(), Either.Right(userPrivateKey.publicKey()), listOf(userPrivateKey.publicKey(), serverPrivateKey.publicKey()), null, null) + val serverNonce = Musig2.generateNonce(randomBytes32(), Either.Right(serverPrivateKey.publicKey()), listOf(serverPrivateKey.publicKey(), userPrivateKey.publicKey()), null, null) // Once they have each other's public nonce, they can produce partial signatures. val userSig = swapInProtocol.signSwapInputUser(tx, 0, swapInTx.txOut, userPrivateKey, userNonce.first, userNonce.second, serverNonce.second).right!! From 7a322ccefd174d48f087a0bb808790cf176c951a Mon Sep 17 00:00:00 2001 From: sstone Date: Mon, 22 Sep 2025 10:15:16 +0200 Subject: [PATCH 2/3] Fixup: remove auto-format changes --- .../acinq/lightning/channel/InteractiveTx.kt | 30 +------------------ 1 file changed, 1 insertion(+), 29 deletions(-) diff --git a/modules/core/src/commonMain/kotlin/fr/acinq/lightning/channel/InteractiveTx.kt b/modules/core/src/commonMain/kotlin/fr/acinq/lightning/channel/InteractiveTx.kt index 6ed570208..3102e94b9 100644 --- a/modules/core/src/commonMain/kotlin/fr/acinq/lightning/channel/InteractiveTx.kt +++ b/modules/core/src/commonMain/kotlin/fr/acinq/lightning/channel/InteractiveTx.kt @@ -343,7 +343,6 @@ data class FundingContributions(val inputs: List, v swapInProtocol.userPublicKey, swapInProtocol.serverPublicKey, swapInProtocol.userRefundKey, swapInProtocol.refundDelay ) } - else -> InteractiveTxInput.LocalLegacySwapIn( 0, i.previousTx.stripInputWitnesses(), @@ -715,7 +714,6 @@ data class InteractiveTxSession( Pair(next, InteractiveTxSessionAction.SendMessage(txComplete)) } } - is Either.Left -> { val inputOutgoing = msg.value val txAddInput = when (inputOutgoing) { @@ -724,13 +722,11 @@ data class InteractiveTxSession( val swapInParams = TxAddInputTlv.SwapInParamsLegacy(swapInKeys.userPublicKey, swapInKeys.remoteServerPublicKey, swapInKeys.refundDelay) TxAddInput(fundingParams.channelId, inputOutgoing.serialId, inputOutgoing.previousTx, inputOutgoing.previousTxOutput, inputOutgoing.sequence, TlvStream(swapInParams)) } - is InteractiveTxInput.LocalSwapIn -> { val swapInProtocol = swapInKeys.getSwapInProtocol(inputOutgoing.addressIndex) val swapInParams = TxAddInputTlv.SwapInParams(swapInProtocol.userPublicKey, swapInProtocol.serverPublicKey, swapInProtocol.userRefundKey, swapInProtocol.refundDelay) TxAddInput(fundingParams.channelId, inputOutgoing.serialId, inputOutgoing.previousTx, inputOutgoing.previousTxOutput, inputOutgoing.sequence, TlvStream(swapInParams)) } - is InteractiveTxInput.Shared -> TxAddInput(fundingParams.channelId, inputOutgoing.serialId, inputOutgoing.outPoint, inputOutgoing.sequence) } val nextSecretNonces = when (inputOutgoing) { @@ -740,16 +736,13 @@ data class InteractiveTxSession( val secretNonce = Musig2.generateNonce(randomBytes32(), Either.Right(swapInKeys.userPublicKey), listOf(swapInKeys.userPublicKey, swapInKeys.remoteServerPublicKey), null, null) secretNonces + (inputOutgoing.serialId to secretNonce) } - else -> secretNonces } - else -> secretNonces } val next = copy(toSend = toSend.tail(), localInputs = localInputs + msg.value, txCompleteSent = null, secretNonces = nextSecretNonces) Pair(next, InteractiveTxSessionAction.SendMessage(txAddInput)) } - is Either.Right -> { val outputOutgoing = msg.value val next = copy(toSend = toSend.tail(), localOutputs = localOutputs + outputOutgoing, txCompleteSent = null) @@ -803,7 +796,6 @@ data class InteractiveTxSession( message.swapInParams.userRefundKey, message.swapInParams.refundDelay ) - message.swapInParamsLegacy != null -> InteractiveTxInput.RemoteLegacySwapIn( message.serialId, outpoint, @@ -813,7 +805,6 @@ data class InteractiveTxSession( message.swapInParamsLegacy.serverKey, message.swapInParamsLegacy.refundDelay ) - else -> InteractiveTxInput.RemoteOnly(message.serialId, outpoint, txOut, message.sequence) } } @@ -831,10 +822,8 @@ data class InteractiveTxSession( val secretNonce = Musig2.generateNonce(randomBytes32(), Either.Right(input.serverKey), listOf(input.userKey, input.serverKey), null, null) secretNonces + (input.serialId to secretNonce) } - else -> secretNonces } - else -> secretNonces } val session1 = this.copy(remoteInputs = remoteInputs + input, inputsReceivedCount = inputsReceivedCount + 1, txCompleteReceived = null, secretNonces = secretNonces1) @@ -870,14 +859,12 @@ data class InteractiveTxSession( { next -> next.send() } ) } - is TxAddOutput -> { receiveOutput(message).fold( { f -> Pair(this, f) }, { output -> copy(remoteOutputs = remoteOutputs + output, outputsReceivedCount = outputsReceivedCount + 1, txCompleteReceived = null).send() } ) } - is TxRemoveInput -> { val remoteInputs1 = remoteInputs.filterNot { i -> (i as InteractiveTxInput).serialId == message.serialId } if (remoteInputs.size != remoteInputs1.size) { @@ -887,7 +874,6 @@ data class InteractiveTxSession( Pair(this, InteractiveTxSessionAction.UnknownSerialId(message.channelId, message.serialId)) } } - is TxRemoveOutput -> { val remoteOutputs1 = remoteOutputs.filterNot { o -> (o as InteractiveTxOutput).serialId == message.serialId } if (remoteOutputs.size != remoteOutputs1.size) { @@ -897,7 +883,6 @@ data class InteractiveTxSession( Pair(this, InteractiveTxSessionAction.UnknownSerialId(message.channelId, message.serialId)) } } - is TxComplete -> { val next = copy(txCompleteReceived = message) if (next.isComplete) { @@ -1043,7 +1028,6 @@ data class InteractiveTxSigningSession( is Either.Left -> localCommit.value.commitTx.input is Either.Right -> localCommit.value.publishableTxs.commitTx.input } - // This value tells our peer whether we need them to retransmit their commit_sig on reconnection or not. val reconnectNextLocalCommitmentNumber = when (localCommit) { is Either.Left -> localCommit.value.index @@ -1055,8 +1039,7 @@ data class InteractiveTxSigningSession( is Either.Left -> { val localCommitIndex = localCommit.value.index val localPerCommitmentPoint = channelKeys.commitmentPoint(localCommitIndex) - when (val signedLocalCommit = - LocalCommit.fromCommitSig(channelKeys, channelParams, fundingTxIndex, fundingParams.remoteFundingPubkey, commitInput, remoteCommitSig, localCommitIndex, localCommit.value.spec, localPerCommitmentPoint, logger)) { + when (val signedLocalCommit = LocalCommit.fromCommitSig(channelKeys, channelParams, fundingTxIndex, fundingParams.remoteFundingPubkey, commitInput, remoteCommitSig, localCommitIndex, localCommit.value.spec, localPerCommitmentPoint, logger)) { is Either.Left -> { val fundingKey = channelKeys.fundingKey(fundingTxIndex) val localSigOfLocalTx = Transactions.sign(localCommit.value.commitTx, fundingKey) @@ -1068,7 +1051,6 @@ data class InteractiveTxSigningSession( logger.info { "signedLocalCommitTx=$signedLocalCommitTx" } Pair(this, InteractiveTxSigningSessionAction.AbortFundingAttempt(signedLocalCommit.value)) } - is Either.Right -> { if (shouldSignFirst(fundingParams.isInitiator, channelParams, fundingTx.tx)) { val fundingStatus = LocalFundingStatus.UnconfirmedFundingTx(fundingTx, fundingParams, currentBlockHeight) @@ -1081,7 +1063,6 @@ data class InteractiveTxSigningSession( } } } - is Either.Right -> Pair(this, InteractiveTxSigningSessionAction.WaitForTxSigs) } } @@ -1199,7 +1180,6 @@ sealed class QuiescenceNegotiation : SpliceStatus() { abstract class Initiator : QuiescenceNegotiation() { abstract val command: ChannelCommand.Commitment.Splice.Request } - abstract class NonInitiator : QuiescenceNegotiation() } @@ -1208,22 +1188,16 @@ sealed class QuiescentSpliceStatus : SpliceStatus() sealed class SpliceStatus { data object None : SpliceStatus() - /** We stop sending new updates and wait for our updates to be added to the local and remote commitments. */ data class QuiescenceRequested(override val command: ChannelCommand.Commitment.Splice.Request) : QuiescenceNegotiation.Initiator() - /** Our updates have been added to the local and remote commitments, we wait for our peer to do the same. */ data class InitiatorQuiescent(override val command: ChannelCommand.Commitment.Splice.Request) : QuiescenceNegotiation.Initiator() - /** Our peer has asked us to stop sending new updates and wait for our updates to be added to the local and remote commitments. */ data class ReceivedStfu(val stfu: Stfu) : QuiescenceNegotiation.NonInitiator() - /** Our updates have been added to the local and remote commitments, we wait for our peer to use the now quiescent channel. */ data object NonInitiatorQuiescent : QuiescentSpliceStatus() - /** We told our peer we want to splice funds in the channel. */ data class Requested(val command: ChannelCommand.Commitment.Splice.Request, val spliceInit: SpliceInit) : QuiescentSpliceStatus() - /** We both agreed to splice and are building the splice transaction. */ data class InProgress( val replyTo: CompletableDeferred?, @@ -1231,10 +1205,8 @@ sealed class SpliceStatus { val liquidityPurchase: LiquidityAds.Purchase?, val origins: List ) : QuiescentSpliceStatus() - /** The splice transaction has been negotiated, we're exchanging signatures. */ data class WaitingForSigs(val session: InteractiveTxSigningSession, val liquidityPurchase: LiquidityAds.Purchase?, val origins: List) : QuiescentSpliceStatus() - /** The splice attempt was aborted by us, we're waiting for our peer to ack. */ data object Aborted : QuiescentSpliceStatus() } From 55610d40d19cbf0c02585cf304cef95b6dd6d427 Mon Sep 17 00:00:00 2001 From: sstone Date: Mon, 22 Sep 2025 11:44:13 +0200 Subject: [PATCH 3/3] Fixup: use private key to generate swap-in nonces as we did before --- .../kotlin/fr/acinq/lightning/channel/InteractiveTx.kt | 2 +- .../acinq/lightning/transactions/TransactionsTestsCommon.kt | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/modules/core/src/commonMain/kotlin/fr/acinq/lightning/channel/InteractiveTx.kt b/modules/core/src/commonMain/kotlin/fr/acinq/lightning/channel/InteractiveTx.kt index 3102e94b9..4cc8ffb80 100644 --- a/modules/core/src/commonMain/kotlin/fr/acinq/lightning/channel/InteractiveTx.kt +++ b/modules/core/src/commonMain/kotlin/fr/acinq/lightning/channel/InteractiveTx.kt @@ -733,7 +733,7 @@ data class InteractiveTxSession( // Generate a secret nonce for this input if we don't already have one. is InteractiveTxInput.LocalSwapIn -> when (secretNonces[inputOutgoing.serialId]) { null -> { - val secretNonce = Musig2.generateNonce(randomBytes32(), Either.Right(swapInKeys.userPublicKey), listOf(swapInKeys.userPublicKey, swapInKeys.remoteServerPublicKey), null, null) + val secretNonce = Musig2.generateNonce(randomBytes32(), Either.Left(swapInKeys.userPrivateKey), listOf(swapInKeys.userPublicKey, swapInKeys.remoteServerPublicKey), null, null) secretNonces + (inputOutgoing.serialId to secretNonce) } else -> secretNonces diff --git a/modules/core/src/commonTest/kotlin/fr/acinq/lightning/transactions/TransactionsTestsCommon.kt b/modules/core/src/commonTest/kotlin/fr/acinq/lightning/transactions/TransactionsTestsCommon.kt index e62e27802..a0411eb1d 100644 --- a/modules/core/src/commonTest/kotlin/fr/acinq/lightning/transactions/TransactionsTestsCommon.kt +++ b/modules/core/src/commonTest/kotlin/fr/acinq/lightning/transactions/TransactionsTestsCommon.kt @@ -515,8 +515,8 @@ class TransactionsTestsCommon : LightningTestSuite() { ) // The first step of a musig2 signing session is to exchange nonces. // If participants are disconnected before the end of the signing session, they must start again with fresh nonces. - val userNonce = Musig2.generateNonce(randomBytes32(), Either.Right(userPrivateKey.publicKey()), listOf(userPrivateKey.publicKey(), serverPrivateKey.publicKey()), null, null) - val serverNonce = Musig2.generateNonce(randomBytes32(), Either.Right(serverPrivateKey.publicKey()), listOf(serverPrivateKey.publicKey(), userPrivateKey.publicKey()), null, null) + val userNonce = Musig2.generateNonce(randomBytes32(), Either.Left(userPrivateKey), listOf(userPrivateKey.publicKey(), serverPrivateKey.publicKey()), null, null) + val serverNonce = Musig2.generateNonce(randomBytes32(), Either.Left(serverPrivateKey), listOf(serverPrivateKey.publicKey(), userPrivateKey.publicKey()), null, null) // Once they have each other's public nonce, they can produce partial signatures. val userSig = swapInProtocol.signSwapInputUser(tx, 0, swapInTx.txOut, userPrivateKey, userNonce.first, userNonce.second, serverNonce.second).right!!