Skip to content

Commit 5ccd10b

Browse files
committed
Fixup: use specific types for remote signature
We create specific types for standard signature (64 bytes) and musig2 partial signatures + nonce.
1 parent a77aa5f commit 5ccd10b

File tree

14 files changed

+37
-43
lines changed

14 files changed

+37
-43
lines changed

eclair-core/src/main/scala/fr/acinq/eclair/channel/Commitments.scala

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -218,7 +218,19 @@ case class HtlcTxAndRemoteSig(htlcTx: HtlcTx, remoteSig: ByteVector64)
218218
case class PartialSignatureWithNonce(partialSig: ByteVector32, nonce: IndividualNonce)
219219

220220
/** We don't store the fully signed transaction, otherwise someone with read access to our database could force-close our channels. */
221-
case class CommitTxAndRemoteSig(commitTx: CommitTx, remoteSig: Either[ByteVector64, PartialSignatureWithNonce])
221+
sealed trait RemoteSignature
222+
object RemoteSignature {
223+
case class FullSignature(sig: ByteVector64) extends RemoteSignature
224+
case class PartialSignature(psig: PartialSignatureWithNonce) extends RemoteSignature
225+
226+
def apply(sig: ByteVector64): RemoteSignature = FullSignature(sig)
227+
}
228+
229+
case class CommitTxAndRemoteSig(commitTx: CommitTx, remoteSig: RemoteSignature)
230+
231+
object CommitTxAndRemoteSig {
232+
def apply(commitTx: CommitTx, remoteSig: ByteVector64): CommitTxAndRemoteSig = CommitTxAndRemoteSig(commitTx, RemoteSignature(remoteSig))
233+
}
222234

223235
/** The local commitment maps to a commitment transaction that we can sign and broadcast if necessary. */
224236
case class LocalCommit(index: Long, spec: CommitmentSpec, commitTxAndRemoteSig: CommitTxAndRemoteSig, htlcTxsAndRemoteSigs: List[HtlcTxAndRemoteSig])
@@ -243,7 +255,7 @@ object LocalCommit {
243255
}
244256
HtlcTxAndRemoteSig(htlcTx, remoteSig)
245257
}
246-
Right(LocalCommit(localCommitIndex, spec, CommitTxAndRemoteSig(localCommitTx, Left(commit.signature)), htlcTxsAndRemoteSigs))
258+
Right(LocalCommit(localCommitIndex, spec, CommitTxAndRemoteSig(localCommitTx, RemoteSignature.FullSignature(commit.signature)), htlcTxsAndRemoteSigs))
247259
}
248260
}
249261

@@ -666,7 +678,7 @@ case class Commitment(fundingTxIndex: Long,
666678
def fullySignedLocalCommitTx(params: ChannelParams, keyManager: ChannelKeyManager): CommitTx = {
667679
val unsignedCommitTx = localCommit.commitTxAndRemoteSig.commitTx
668680
val localSig = keyManager.sign(unsignedCommitTx, keyManager.fundingPublicKey(params.localParams.fundingKeyPath, fundingTxIndex), TxOwner.Local, params.commitmentFormat)
669-
val Left(remoteSig) = localCommit.commitTxAndRemoteSig.remoteSig
681+
val RemoteSignature.FullSignature(remoteSig) = localCommit.commitTxAndRemoteSig.remoteSig
670682
val commitTx = addSigs(unsignedCommitTx, keyManager.fundingPublicKey(params.localParams.fundingKeyPath, fundingTxIndex).publicKey, remoteFundingPubKey, localSig, remoteSig)
671683
// We verify the remote signature when receiving their commit_sig, so this check should always pass.
672684
require(checkSpendable(commitTx).isSuccess, "commit signatures are invalid")
@@ -1154,7 +1166,7 @@ case class Commitments(params: ChannelParams,
11541166

11551167
/** This function should be used to ignore a commit_sig that we've already received. */
11561168
def ignoreRetransmittedCommitSig(commitSig: CommitSig): Boolean = {
1157-
val Left(latestRemoteSig) = latest.localCommit.commitTxAndRemoteSig.remoteSig
1169+
val RemoteSignature.FullSignature(latestRemoteSig) = latest.localCommit.commitTxAndRemoteSig.remoteSig
11581170
params.channelFeatures.hasFeature(Features.DualFunding) && commitSig.batchSize == 1 && latestRemoteSig == commitSig.signature
11591171
}
11601172

eclair-core/src/main/scala/fr/acinq/eclair/channel/fsm/ChannelOpenSingleFunded.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -281,7 +281,7 @@ trait ChannelOpenSingleFunded extends SingleFundingHandlers with ErrorHandlers {
281281
remoteFundingPubKey = remoteFundingPubKey,
282282
localFundingStatus = SingleFundedUnconfirmedFundingTx(None),
283283
remoteFundingStatus = RemoteFundingStatus.NotLocked,
284-
localCommit = LocalCommit(0, localSpec, CommitTxAndRemoteSig(localCommitTx, Left(remoteSig)), htlcTxsAndRemoteSigs = Nil),
284+
localCommit = LocalCommit(0, localSpec, CommitTxAndRemoteSig(localCommitTx, remoteSig), htlcTxsAndRemoteSigs = Nil),
285285
remoteCommit = RemoteCommit(0, remoteSpec, remoteCommitTx.tx.txid, remoteFirstPerCommitmentPoint),
286286
nextRemoteCommit_opt = None)
287287
val commitments = Commitments(
@@ -328,7 +328,7 @@ trait ChannelOpenSingleFunded extends SingleFundingHandlers with ErrorHandlers {
328328
remoteFundingPubKey = remoteFundingPubKey,
329329
localFundingStatus = SingleFundedUnconfirmedFundingTx(Some(fundingTx)),
330330
remoteFundingStatus = RemoteFundingStatus.NotLocked,
331-
localCommit = LocalCommit(0, localSpec, CommitTxAndRemoteSig(localCommitTx, Left(remoteSig)), htlcTxsAndRemoteSigs = Nil),
331+
localCommit = LocalCommit(0, localSpec, CommitTxAndRemoteSig(localCommitTx, remoteSig), htlcTxsAndRemoteSigs = Nil),
332332
remoteCommit = remoteCommit,
333333
nextRemoteCommit_opt = None
334334
)

eclair-core/src/main/scala/fr/acinq/eclair/channel/fund/InteractiveTxBuilder.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1008,7 +1008,7 @@ object InteractiveTxSigningSession {
10081008
case class UnsignedLocalCommit(index: Long, spec: CommitmentSpec, commitTx: CommitTx, htlcTxs: List[HtlcTx])
10091009

10101010
private def shouldSignFirst(isInitiator: Boolean, channelParams: ChannelParams, tx: SharedTransaction): Boolean = {
1011-
val sharedAmountIn = tx.sharedInput_opt.map(i => i.localAmount + i.remoteAmount + i.htlcAmount).getOrElse(0 msat).truncateToSatoshi
1011+
val sharedAmountIn = tx.sharedInput_opt.map(_.txOut.amount).getOrElse(0 sat)
10121012
val (localAmountIn, remoteAmountIn) = if (isInitiator) {
10131013
(sharedAmountIn + tx.localInputs.map(i => i.txOut.amount).sum, tx.remoteInputs.map(i => i.txOut.amount).sum)
10141014
} else {

eclair-core/src/main/scala/fr/acinq/eclair/remote/LightningMessageSerializer.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,6 @@
1616

1717
package fr.acinq.eclair.remote
1818

19-
import fr.acinq.eclair.wire.protocol.LightningMessageCodecs.lightningMessageCodec
19+
import fr.acinq.eclair.wire.protocol.LightningMessageCodecs.lightningMessageCodecWithFallback
2020

21-
class LightningMessageSerializer extends ScodecSerializer(42, lightningMessageCodec)
21+
class LightningMessageSerializer extends ScodecSerializer(42, lightningMessageCodecWithFallback)

eclair-core/src/main/scala/fr/acinq/eclair/wire/internal/channel/version0/ChannelTypes0.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,7 @@ private[channel] object ChannelTypes0 {
121121
def migrate(remoteFundingPubKey: PublicKey): channel.LocalCommit = {
122122
val remoteSig = extractRemoteSig(publishableTxs.commitTx, remoteFundingPubKey)
123123
val unsignedCommitTx = publishableTxs.commitTx.modify(_.tx.txIn.each.witness).setTo(ScriptWitness.empty)
124-
val commitTxAndRemoteSig = CommitTxAndRemoteSig(unsignedCommitTx, Left(remoteSig))
124+
val commitTxAndRemoteSig = CommitTxAndRemoteSig(unsignedCommitTx, remoteSig)
125125
val htlcTxsAndRemoteSigs = publishableTxs.htlcTxsAndSigs map {
126126
case HtlcTxAndSigs(htlcTx: HtlcSuccessTx, _, remoteSig) =>
127127
val unsignedHtlcTx = htlcTx.modify(_.tx.txIn.each.witness).setTo(ScriptWitness.empty)

eclair-core/src/main/scala/fr/acinq/eclair/wire/internal/channel/version3/ChannelCodecs3.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -203,7 +203,7 @@ private[channel] object ChannelCodecs3 {
203203

204204
val commitTxAndRemoteSigCodec: Codec[CommitTxAndRemoteSig] = (
205205
("commitTx" | commitTxCodec) ::
206-
("remoteSig" | either(provide(false), bytes64, partialSignatureWithNonce))).as[CommitTxAndRemoteSig]
206+
("remoteSig" | bytes64.as[RemoteSignature.FullSignature].upcast[RemoteSignature])).as[CommitTxAndRemoteSig]
207207

208208
val localCommitCodec: Codec[LocalCommit] = (
209209
("index" | uint64overflow) ::

eclair-core/src/main/scala/fr/acinq/eclair/wire/internal/channel/version4/ChannelCodecs4.scala

Lines changed: 4 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ package fr.acinq.eclair.wire.internal.channel.version4
22

33
import fr.acinq.bitcoin.scalacompat.Crypto.PublicKey
44
import fr.acinq.bitcoin.scalacompat.DeterministicWallet.KeyPath
5-
import fr.acinq.bitcoin.scalacompat.{ByteVector64, OutPoint, ScriptWitness, Transaction, TxOut}
5+
import fr.acinq.bitcoin.scalacompat.{OutPoint, ScriptWitness, Transaction, TxOut}
66
import fr.acinq.eclair.blockchain.fee.{ConfirmationPriority, ConfirmationTarget}
77
import fr.acinq.eclair.channel.LocalFundingStatus._
88
import fr.acinq.eclair.channel._
@@ -183,20 +183,10 @@ private[channel] object ChannelCodecs4 {
183183
val htlcTxsAndRemoteSigsCodec: Codec[HtlcTxAndRemoteSig] = (
184184
("txinfo" | htlcTxCodec) ::
185185
("remoteSig" | bytes64)).as[HtlcTxAndRemoteSig]
186-
187-
private case class CommitTxAndRemoteSigEx(commitTx: CommitTx, remoteSig: ByteVector64, partialSig: Either[ByteVector64, PartialSignatureWithNonce], dummy: Boolean)
188-
189-
// remoteSig is now either a signature or a partial signature with nonce. To retain compatibility with the previous codec, we use remoteSig as a left/right indicator,
190-
// a value of all zeroes meaning right (a valid signature cannot be all zeroes)
191-
private val commitTxAndRemoteSigExCodec: Codec[CommitTxAndRemoteSigEx] = (
186+
187+
val commitTxAndRemoteSigCodec: Codec[CommitTxAndRemoteSig] = (
192188
("commitTx" | commitTxCodec) ::
193-
(("remoteSig" | bytes64) >>:~ { remoteSig => either(provide(remoteSig == ByteVector64.Zeroes), provide(remoteSig), partialSignatureWithNonce) :: ("dummy" | provide(false)) })
194-
).as[CommitTxAndRemoteSigEx]
195-
196-
val commitTxAndRemoteSigCodec: Codec[CommitTxAndRemoteSig] = commitTxAndRemoteSigExCodec.xmap(
197-
ce => CommitTxAndRemoteSig(ce.commitTx, ce.partialSig),
198-
c => CommitTxAndRemoteSigEx(c.commitTx, c.remoteSig.swap.toOption.getOrElse(fr.acinq.bitcoin.scalacompat.ByteVector64.Zeroes), c.remoteSig, false)
199-
)
189+
("remoteSig" | bytes64.as[RemoteSignature.FullSignature].upcast[RemoteSignature])).as[CommitTxAndRemoteSig]
200190

201191
val updateMessageCodec: Codec[UpdateMessage] = lengthDelimited(lightningMessageCodec.narrow[UpdateMessage](f => Attempt.successful(f.asInstanceOf[UpdateMessage]), g => g))
202192

eclair-core/src/main/scala/fr/acinq/eclair/wire/protocol/CommonCodecs.scala

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,10 @@
1616

1717
package fr.acinq.eclair.wire.protocol
1818

19-
import fr.acinq.bitcoin.crypto.musig2.IndividualNonce
2019
import fr.acinq.bitcoin.scalacompat.Crypto.{PrivateKey, PublicKey}
2120
import fr.acinq.bitcoin.scalacompat.{BlockHash, ByteVector32, ByteVector64, Satoshi, Transaction, TxHash, TxId}
2221
import fr.acinq.eclair.blockchain.fee.FeeratePerKw
23-
import fr.acinq.eclair.channel.{ChannelFlags, PartialSignatureWithNonce, RealScidStatus, ShortIds}
22+
import fr.acinq.eclair.channel.{ChannelFlags, RealScidStatus, ShortIds}
2423
import fr.acinq.eclair.crypto.Mac32
2524
import fr.acinq.eclair.{Alias, BlockHeight, CltvExpiry, CltvExpiryDelta, Feature, Features, InitFeature, MilliSatoshi, RealShortChannelId, ShortChannelId, TimestampSecond, UInt64, UnspecifiedShortChannelId}
2625
import org.apache.commons.codec.binary.Base32
@@ -168,13 +167,6 @@ object CommonCodecs {
168167
(wire: BitVector) => bytes(33).decode(wire).map(_.map(b => PublicKey(b)))
169168
)
170169

171-
val publicNonce: Codec[IndividualNonce] = Codec[IndividualNonce](
172-
(pub: IndividualNonce) => bytes(66).encode(ByteVector.view(pub.toByteArray)),
173-
(wire: BitVector) => bytes(66).decode(wire).map(_.map(b => new IndividualNonce(b.toArray)))
174-
)
175-
176-
val partialSignatureWithNonce: Codec[PartialSignatureWithNonce] = (bytes32 :: publicNonce).as[PartialSignatureWithNonce]
177-
178170
val rgb: Codec[Color] = bytes(3).xmap(buf => Color(buf(0), buf(1), buf(2)), t => ByteVector(t.r, t.g, t.b))
179171

180172
val txCodec: Codec[Transaction] = bytes.xmap(d => Transaction.read(d.toArray), d => Transaction.write(d))

eclair-core/src/test/scala/fr/acinq/eclair/channel/CommitmentsSpec.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -491,7 +491,7 @@ object CommitmentsSpec {
491491
val remoteParams = RemoteParams(randomKey().publicKey, dustLimit, UInt64.MaxValue, Some(channelReserve), 1 msat, CltvExpiryDelta(144), 50, randomKey().publicKey, randomKey().publicKey, randomKey().publicKey, randomKey().publicKey, Features.empty, None)
492492
val remoteFundingPubKey = randomKey().publicKey
493493
val commitmentInput = Funding.makeFundingInputInfo(randomTxId(), 0, (toLocal + toRemote).truncateToSatoshi, randomKey().publicKey, remoteFundingPubKey)
494-
val localCommit = LocalCommit(0, CommitmentSpec(Set.empty, feeRatePerKw, toLocal, toRemote), CommitTxAndRemoteSig(CommitTx(commitmentInput, Transaction(2, Nil, Nil, 0)), Left(ByteVector64.Zeroes)), Nil)
494+
val localCommit = LocalCommit(0, CommitmentSpec(Set.empty, feeRatePerKw, toLocal, toRemote), CommitTxAndRemoteSig(CommitTx(commitmentInput, Transaction(2, Nil, Nil, 0)), ByteVector64.Zeroes), Nil)
495495
val remoteCommit = RemoteCommit(0, CommitmentSpec(Set.empty, feeRatePerKw, toRemote, toLocal), randomTxId(), randomKey().publicKey)
496496
Commitments(
497497
ChannelParams(randomBytes32(), ChannelConfig.standard, ChannelFeatures(), localParams, remoteParams, ChannelFlags(announceChannel = announceChannel)),
@@ -510,7 +510,7 @@ object CommitmentsSpec {
510510
val remoteParams = RemoteParams(remoteNodeId, 0 sat, UInt64.MaxValue, Some(channelReserve), 1 msat, CltvExpiryDelta(144), 50, randomKey().publicKey, randomKey().publicKey, randomKey().publicKey, randomKey().publicKey, Features.empty, None)
511511
val remoteFundingPubKey = randomKey().publicKey
512512
val commitmentInput = Funding.makeFundingInputInfo(randomTxId(), 0, (toLocal + toRemote).truncateToSatoshi, randomKey().publicKey, remoteFundingPubKey)
513-
val localCommit = LocalCommit(0, CommitmentSpec(Set.empty, FeeratePerKw(0 sat), toLocal, toRemote), CommitTxAndRemoteSig(CommitTx(commitmentInput, Transaction(2, Nil, Nil, 0)), Left(ByteVector64.Zeroes)), Nil)
513+
val localCommit = LocalCommit(0, CommitmentSpec(Set.empty, FeeratePerKw(0 sat), toLocal, toRemote), CommitTxAndRemoteSig(CommitTx(commitmentInput, Transaction(2, Nil, Nil, 0)), ByteVector64.Zeroes), Nil)
514514
val remoteCommit = RemoteCommit(0, CommitmentSpec(Set.empty, FeeratePerKw(0 sat), toRemote, toLocal), randomTxId(), randomKey().publicKey)
515515
Commitments(
516516
ChannelParams(randomBytes32(), ChannelConfig.standard, ChannelFeatures(), localParams, remoteParams, ChannelFlags(announceChannel = announceChannel)),

eclair-core/src/test/scala/fr/acinq/eclair/channel/publish/ReplaceableTxFunderSpec.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,7 @@ class ReplaceableTxFunderSpec extends TestKitBaseClass with AnyFunSuiteLike {
146146
localParams.dustLimit.returns(1000 sat)
147147
commitment.localParams.returns(localParams)
148148
val localCommit = mock[LocalCommit]
149-
localCommit.commitTxAndRemoteSig.returns(CommitTxAndRemoteSig(commitTx, Left(PlaceHolderSig)))
149+
localCommit.commitTxAndRemoteSig.returns(CommitTxAndRemoteSig(commitTx, PlaceHolderSig))
150150
commitment.localCommit.returns(localCommit)
151151

152152
// We can handle a small feerate update by lowering the change output.

0 commit comments

Comments
 (0)