@@ -13,6 +13,7 @@ import fr.acinq.eclair.channel.fund.InteractiveTxBuilder.SharedTransaction
1313import fr .acinq .eclair .crypto .keymanager .ChannelKeyManager
1414import fr .acinq .eclair .crypto .{Generators , ShaChain }
1515import fr .acinq .eclair .payment .OutgoingPaymentPacket
16+ import fr .acinq .eclair .transactions .Transactions .TxOwner .{Local , Remote }
1617import fr .acinq .eclair .transactions .Transactions ._
1718import fr .acinq .eclair .transactions ._
1819import fr .acinq .eclair .wire .protocol ._
@@ -227,7 +228,7 @@ case class LocalCommit(index: Long, spec: CommitmentSpec, commitTxAndRemoteSig:
227228object LocalCommit {
228229 def fromCommitSig (keyManager : ChannelKeyManager , params : ChannelParams , fundingTxId : TxId ,
229230 fundingTxIndex : Long , remoteFundingPubKey : PublicKey , commitInput : InputInfo ,
230- commit : CommitSig , localCommitIndex : Long , spec : CommitmentSpec , localPerCommitmentPoint : PublicKey , localNonce_opt : Option [(SecretNonce , IndividualNonce )]): Either [ChannelException , LocalCommit ] = {
231+ commit : CommitSig , localCommitIndex : Long , spec : CommitmentSpec , localPerCommitmentPoint : PublicKey , localNonce_opt : Option [(SecretNonce , IndividualNonce )])( implicit log : LoggingAdapter ) : Either [ChannelException , LocalCommit ] = {
231232 val (localCommitTx, htlcTxs) = Commitment .makeLocalTxs(keyManager, params.channelConfig, params.channelFeatures, localCommitIndex, params.localParams, params.remoteParams, fundingTxIndex, remoteFundingPubKey, commitInput, localPerCommitmentPoint, spec)
232233 if (! localCommitTx.checkSig(commit, remoteFundingPubKey, TxOwner .Remote , params.commitmentFormat)) {
233234 return Left (InvalidCommitmentSignature (params.channelId, fundingTxId, fundingTxIndex, localCommitTx.tx))
@@ -241,6 +242,10 @@ object LocalCommit {
241242 val fundingPubkey = keyManager.fundingPublicKey(params.localParams.fundingKeyPath, fundingTxIndex).publicKey
242243 val Some (localNonce) = localNonce_opt
243244 if (! localCommitTx.checkPartialSignature(psig, fundingPubkey, localNonce._2, remoteFundingPubKey)) {
245+ log.debug(s " fromCommitSig: invalid partial signature $psig fundingPubkey = $fundingPubkey, fundingTxIndex = $fundingTxIndex localCommitIndex = $localCommitIndex localNonce = $localNonce remoteFundingPubKey = $remoteFundingPubKey" )
246+
247+ val localNonce1 = keyManager.verificationNonce(params.localParams.fundingKeyPath, fundingTxIndex, keyManager.keyPath(params.localParams, params.channelConfig), localCommitIndex)
248+ log.debug(s " with $localNonce1 ${localCommitTx.checkPartialSignature(psig, fundingPubkey, localNonce1._2, remoteFundingPubKey)}" )
244249 return Left (InvalidCommitmentSignature (params.channelId, fundingTxId, fundingTxIndex, localCommitTx.tx))
245250 }
246251 }
@@ -265,9 +270,10 @@ case class RemoteCommit(index: Long, spec: CommitmentSpec, txid: TxId, remotePer
265270 def sign (keyManager : ChannelKeyManager , params : ChannelParams , fundingTxIndex : Long , remoteFundingPubKey : PublicKey , commitInput : InputInfo , remoteNonce_opt : Option [IndividualNonce ])(implicit log : LoggingAdapter ): CommitSig = {
266271 val (remoteCommitTx, htlcTxs) = Commitment .makeRemoteTxs(keyManager, params.channelConfig, params.channelFeatures, index, params.localParams, params.remoteParams, fundingTxIndex, remoteFundingPubKey, commitInput, remotePerCommitmentPoint, spec)
267272 val (sig, tlvStream) = if (params.commitmentFormat.useTaproot) {
268- val localNonce = keyManager.verificationNonce (params.localParams.fundingKeyPath, fundingTxIndex, keyManager.keyPath(params.localParams, params.channelConfig), index )
273+ val localNonce = keyManager.signingNonce (params.localParams.fundingKeyPath, fundingTxIndex)
269274 val Some (remoteNonce) = remoteNonce_opt
270275 val Right (localPartialSigOfRemoteTx) = keyManager.partialSign(remoteCommitTx, keyManager.fundingPublicKey(params.localParams.fundingKeyPath, fundingTxIndex), remoteFundingPubKey, TxOwner .Remote , localNonce, remoteNonce)
276+ log.debug(s " RemoteCommit.sign localPartialSigOfRemoteTx = $localPartialSigOfRemoteTx fundingTxIndex = $fundingTxIndex remote commit index = $index remote nonce = $remoteNonce" )
271277 val tlvStream : TlvStream [CommitSigTlv ] = TlvStream (CommitSigTlv .PartialSignatureWithNonceTlv (PartialSignatureWithNonce (localPartialSigOfRemoteTx, localNonce._2)))
272278 (ByteVector64 .Zeroes , tlvStream)
273279 } else {
@@ -659,7 +665,7 @@ case class Commitment(fundingTxIndex: Long,
659665 val localNonce = keyManager.signingNonce(params.localParams.fundingKeyPath, fundingTxIndex)
660666 val Some (remoteNonce) = nextRemoteNonce_opt
661667 val Right (psig) = keyManager.partialSign(remoteCommitTx, keyManager.fundingPublicKey(params.localParams.fundingKeyPath, fundingTxIndex), remoteFundingPubKey, TxOwner .Remote , localNonce, remoteNonce)
662- log.debug(s " sendCommit: creating partial sig $psig for remote commit tx ${remoteCommitTx.tx.txid} with remote nonce $remoteNonce and remoteNextPerCommitmentPoint = $remoteNextPerCommitmentPoint" )
668+ log.debug(s " sendCommit: creating partial sig $psig for remote commit tx ${remoteCommitTx.tx.txid} with fundingTxIndex = $fundingTxIndex remoteCommit.index (should add +1) = ${remoteCommit.index} remote nonce $remoteNonce and remoteNextPerCommitmentPoint = $remoteNextPerCommitmentPoint" )
663669 Set (CommitSigTlv .PartialSignatureWithNonceTlv (PartialSignatureWithNonce (psig, localNonce._2)))
664670 } else {
665671 Set .empty
@@ -1080,6 +1086,10 @@ case class Commitments(params: ChannelParams,
10801086 }
10811087 val channelKeyPath = keyManager.keyPath(params.localParams, params.channelConfig)
10821088 val localPerCommitmentPoint = keyManager.commitmentPoint(channelKeyPath, localCommitIndex + 1 )
1089+
1090+ val fundingIndexes = active.map(_.fundingTxIndex).toSet
1091+ if (fundingIndexes.size > 1 ) log.warning(s " more than 1 funding tx index " )
1092+
10831093 // Signatures are sent in order (most recent first), calling `zip` will drop trailing sigs that are for deactivated/pruned commitments.
10841094 val active1 = active.zip(commits).map { case (commitment, commit) =>
10851095 val localNonce_opt = if (params.commitmentFormat.useTaproot) {
@@ -1226,9 +1236,31 @@ case class Commitments(params: ChannelParams,
12261236 }
12271237
12281238 /** This function should be used to ignore a commit_sig that we've already received. */
1229- def ignoreRetransmittedCommitSig (commitSig : CommitSig ): Boolean = {
1230- val latestRemoteSig = latest.localCommit.commitTxAndRemoteSig.remoteSig
1231- params.channelFeatures.hasFeature(Features .DualFunding ) && commitSig.batchSize == 1 && latestRemoteSig == commitSig.sigOrPartialSig
1239+ def ignoreRetransmittedCommitSig (commitSig : CommitSig , keyManager : ChannelKeyManager ): Boolean = commitSig.sigOrPartialSig match {
1240+ case _ if ! params.channelFeatures.hasFeature(Features .DualFunding ) => false
1241+ case _ if commitSig.batchSize != 1 => false
1242+ case Left (_) =>
1243+ commitSig.sigOrPartialSig == latest.localCommit.commitTxAndRemoteSig.remoteSig
1244+ case Right (psig) if active.size > 1 =>
1245+ // we cannot compare partial signatures directly as they are not deterministic (a new signing nonce is used every time a signature is computed)
1246+ // => instead we simply check that the provided partial signature is valid for our latest commit tx
1247+ val localFundingKey = keyManager.fundingPublicKey(params.localParams.fundingKeyPath, latest.fundingTxIndex).publicKey
1248+ val Some (localNonce) = generateLocalNonce(keyManager, latest.fundingTxIndex, latest.localCommit.index)
1249+ val Right (oldPsig) = latest.localCommit.commitTxAndRemoteSig.remoteSig
1250+ val currentcheck = latest.localCommit.commitTxAndRemoteSig.commitTx.checkPartialSignature(psig, localFundingKey, localNonce, latest.remoteFundingPubKey)
1251+ val oldcheck = latest.localCommit.commitTxAndRemoteSig.commitTx.checkPartialSignature(oldPsig, localFundingKey, localNonce, latest.remoteFundingPubKey)
1252+ require(oldcheck)
1253+ currentcheck
1254+ case Right (psig) =>
1255+ // we cannot compare partial signatures directly as they are not deterministic (a new signing nonce is used every time a signature is computed)
1256+ // => instead we simply check that the provided partial signature is valid for our latest commit tx
1257+ val localFundingKey = keyManager.fundingPublicKey(params.localParams.fundingKeyPath, latest.fundingTxIndex).publicKey
1258+ val Some (localNonce) = generateLocalNonce(keyManager, latest.fundingTxIndex, latest.localCommit.index)
1259+ val Right (oldPsig) = latest.localCommit.commitTxAndRemoteSig.remoteSig
1260+ val currentcheck = latest.localCommit.commitTxAndRemoteSig.commitTx.checkPartialSignature(psig, localFundingKey, localNonce, latest.remoteFundingPubKey)
1261+ val oldcheck = latest.localCommit.commitTxAndRemoteSig.commitTx.checkPartialSignature(oldPsig, localFundingKey, localNonce, latest.remoteFundingPubKey)
1262+ require(oldcheck)
1263+ currentcheck
12321264 }
12331265
12341266 def localFundingSigs (fundingTxId : TxId ): Option [TxSignatures ] = {
@@ -1348,30 +1380,33 @@ case class Commitments(params: ChannelParams,
13481380 }
13491381
13501382 /**
1351- * Create local verification nonces for the next funding tx
1352- * @param keyManager key manager that will generate actual nonces
1353- * @return a list of 2 verification nonces for the next funding tx: one for the current commitment index, one for the next commitment index
1383+ * Generate local verification nonces for a specific funding tx index and commit tx index
1384+ *
1385+ * @param keyManager key manager that will generate actual nonces
1386+ * @param fundingIndex funding tx index
1387+ * @param commitIndex commit tx index
1388+ * @return a public nonce for thr provided fundint tx index and commit tx index if taproot is used, None otherwise
13541389 */
1355- def generateLocalNonces (keyManager : ChannelKeyManager , fundingIndex : Long ): List [IndividualNonce ] = {
1390+ def generateLocalNonce (keyManager : ChannelKeyManager , fundingIndex : Long , commitIndex : Long ): Option [IndividualNonce ] = {
13561391 if (latest.params.commitmentFormat.useTaproot) {
1357-
1358- def localNonce (commitIndex : Long ) = {
1359- val (_, nonce) = keyManager.verificationNonce(params.localParams.fundingKeyPath, fundingIndex, keyManager.keyPath(params.localParams, params.channelConfig), commitIndex)
1360- nonce
1361- }
1362-
1363- List (localNonce(localCommitIndex), localNonce(localCommitIndex + 1 ))
1392+ Some (keyManager.verificationNonce(params.localParams.fundingKeyPath, fundingIndex, keyManager.keyPath(params.localParams, params.channelConfig), commitIndex)._2)
13641393 } else {
1365- List .empty
1394+ None
13661395 }
13671396 }
13681397
13691398 /**
1370- * Create local verification nonces for the next funding tx
1399+ * Create local verification nonces a specific funding tx index and a range of commit tx indexes
1400+ *
13711401 * @param keyManager key manager that will generate actual nonces
1372- * @return a list of 2 verification nonces for the next funding tx: one for the current commitment index, one for the next commitment index
1402+ * @param fundingIndex funding tx index
1403+ * @param commitIndexes range of commit tx indexes
1404+ * @return a list of nonces if raproot is used, or an empty list
13731405 */
1374- def generateLocalNonces (keyManager : ChannelKeyManager ): List [IndividualNonce ] = generateLocalNonces(keyManager, latest.commitment.fundingTxIndex + 1 )
1406+ def generateLocalNonces (keyManager : ChannelKeyManager , fundingIndex : Long , commitIndexes : Long * ): List [IndividualNonce ] = {
1407+ commitIndexes.toList.flatMap(commitIndex => generateLocalNonce(keyManager, fundingIndex, commitIndex))
1408+ }
1409+
13751410}
13761411
13771412object Commitments {
0 commit comments