@@ -26,6 +26,7 @@ import fr.acinq.eclair._
2626import fr .acinq .eclair .blockchain .fee .{ConfirmationTarget , FeeratePerKw }
2727import fr .acinq .eclair .transactions .CommitmentOutput ._
2828import fr .acinq .eclair .transactions .Scripts ._
29+ import fr .acinq .eclair .transactions .Transactions .InputInfo .SegwitInput
2930import fr .acinq .eclair .wire .protocol .UpdateAddHtlc
3031import scodec .bits .ByteVector
3132
@@ -102,14 +103,18 @@ object Transactions {
102103 val publicKeyScript : ByteVector = Script .write(Script .pay2tr(internalKey, Some (scriptTree)))
103104 }
104105
105- case class InputInfo (outPoint : OutPoint , txOut : TxOut , redeemScriptOrScriptTree : Either [ByteVector , ScriptTreeAndInternalKey ]) {
106- val redeemScriptOrEmptyScript : ByteVector = redeemScriptOrScriptTree.swap.getOrElse(ByteVector .empty) // TODO: use the actual script tree for taproot transactions, once we implement them
106+ sealed trait InputInfo {
107+ val outPoint : OutPoint
108+ val txOut : TxOut
107109 }
108110
109111 object InputInfo {
110- def apply (outPoint : OutPoint , txOut : TxOut , redeemScript : ByteVector ) = new InputInfo (outPoint, txOut, Left (redeemScript))
111- def apply (outPoint : OutPoint , txOut : TxOut , redeemScript : Seq [ScriptElt ]) = new InputInfo (outPoint, txOut, Left (Script .write(redeemScript)))
112- def apply (outPoint : OutPoint , txOut : TxOut , scriptTree : ScriptTreeAndInternalKey ) = new InputInfo (outPoint, txOut, Right (scriptTree))
112+ case class SegwitInput (outPoint : OutPoint , txOut : TxOut , redeemScript : ByteVector ) extends InputInfo
113+ case class TaprootInput (outPoint : OutPoint , txOut : TxOut , scriptTreeAndInternalKey : ScriptTreeAndInternalKey ) extends InputInfo
114+
115+ def apply (outPoint : OutPoint , txOut : TxOut , redeemScript : ByteVector ): SegwitInput = SegwitInput (outPoint, txOut, redeemScript)
116+ def apply (outPoint : OutPoint , txOut : TxOut , redeemScript : Seq [ScriptElt ]): SegwitInput = SegwitInput (outPoint, txOut, Script .write(redeemScript))
117+ def apply (outPoint : OutPoint , txOut : TxOut , scriptTree : ScriptTreeAndInternalKey ): TaprootInput = TaprootInput (outPoint, txOut, scriptTree)
113118 }
114119
115120 /** Owner of a given transaction (local/remote). */
@@ -138,24 +143,29 @@ object Transactions {
138143 sign(key, sighash(txOwner, commitmentFormat))
139144 }
140145
141- def sign (key : PrivateKey , sighashType : Int ): ByteVector64 = {
142- // NB: the tx may have multiple inputs, we will only sign the one provided in txinfo.input. Bear in mind that the
143- // signature will be invalidated if other inputs are added *afterwards* and sighashType was SIGHASH_ALL.
144- val inputIndex = tx.txIn.indexWhere(_.outPoint == input.outPoint)
145- val sigDER = Transaction .signInput(tx, inputIndex, input.redeemScriptOrEmptyScript, sighashType, input.txOut.amount, SIGVERSION_WITNESS_V0 , key)
146- val sig64 = Crypto .der2compact(sigDER)
147- sig64
146+ def sign (key : PrivateKey , sighashType : Int ): ByteVector64 = input match {
147+ case _:InputInfo .TaprootInput => ByteVector64 .Zeroes
148+ case InputInfo .SegwitInput (outPoint, txOut, redeemScript) =>
149+ // NB: the tx may have multiple inputs, we will only sign the one provided in txinfo.input. Bear in mind that the
150+ // signature will be invalidated if other inputs are added *afterwards* and sighashType was SIGHASH_ALL.
151+ val inputIndex = tx.txIn.indexWhere(_.outPoint == outPoint)
152+ val sigDER = Transaction .signInput(tx, inputIndex, redeemScript, sighashType, txOut.amount, SIGVERSION_WITNESS_V0 , key)
153+ val sig64 = Crypto .der2compact(sigDER)
154+ sig64
148155 }
149156
150- def checkSig (sig : ByteVector64 , pubKey : PublicKey , txOwner : TxOwner , commitmentFormat : CommitmentFormat ): Boolean = {
151- val sighash = this .sighash(txOwner, commitmentFormat)
152- val inputIndex = tx.txIn.indexWhere(_.outPoint == input.outPoint)
153- if (inputIndex >= 0 ) {
154- val data = Transaction .hashForSigning(tx, inputIndex, input.redeemScriptOrEmptyScript, sighash, input.txOut.amount, SIGVERSION_WITNESS_V0 )
155- Crypto .verifySignature(data, sig, pubKey)
156- } else {
157- false
158- }
157+ def checkSig (sig : ByteVector64 , pubKey : PublicKey , txOwner : TxOwner , commitmentFormat : CommitmentFormat ): Boolean = input match {
158+
159+ case _:InputInfo .TaprootInput => false
160+ case InputInfo .SegwitInput (outPoint, txOut, redeemScript) =>
161+ val sighash = this .sighash(txOwner, commitmentFormat)
162+ val inputIndex = tx.txIn.indexWhere(_.outPoint == outPoint)
163+ if (inputIndex >= 0 ) {
164+ val data = Transaction .hashForSigning(tx, inputIndex, redeemScript, sighash, txOut.amount, SIGVERSION_WITNESS_V0 )
165+ Crypto .verifySignature(data, sig, pubKey)
166+ } else {
167+ false
168+ }
159169 }
160170 }
161171
@@ -891,64 +901,86 @@ object Transactions {
891901 commitTx.copy(tx = commitTx.tx.updateWitness(0 , witness))
892902 }
893903
894- def addSigs (mainPenaltyTx : MainPenaltyTx , revocationSig : ByteVector64 ): MainPenaltyTx = {
895- val witness = Scripts .witnessToLocalDelayedWithRevocationSig(revocationSig, mainPenaltyTx.input.redeemScriptOrEmptyScript)
896- mainPenaltyTx.copy(tx = mainPenaltyTx.tx.updateWitness(0 , witness))
904+ def addSigs (mainPenaltyTx : MainPenaltyTx , revocationSig : ByteVector64 ): MainPenaltyTx = mainPenaltyTx.input match {
905+ case InputInfo .SegwitInput (_, _, redeemScript) =>
906+ val witness = Scripts .witnessToLocalDelayedWithRevocationSig(revocationSig, redeemScript)
907+ mainPenaltyTx.copy(tx = mainPenaltyTx.tx.updateWitness(0 , witness))
908+ case _ => mainPenaltyTx
897909 }
898910
899- def addSigs (htlcPenaltyTx : HtlcPenaltyTx , revocationSig : ByteVector64 , revocationPubkey : PublicKey ): HtlcPenaltyTx = {
900- val witness = Scripts .witnessHtlcWithRevocationSig(revocationSig, revocationPubkey, htlcPenaltyTx.input.redeemScriptOrEmptyScript)
901- htlcPenaltyTx.copy(tx = htlcPenaltyTx.tx.updateWitness(0 , witness))
911+ def addSigs (htlcPenaltyTx : HtlcPenaltyTx , revocationSig : ByteVector64 , revocationPubkey : PublicKey ): HtlcPenaltyTx = htlcPenaltyTx.input match {
912+ case InputInfo .SegwitInput (_, _, redeemScript) =>
913+ val witness = Scripts .witnessHtlcWithRevocationSig(revocationSig, revocationPubkey, redeemScript)
914+ htlcPenaltyTx.copy(tx = htlcPenaltyTx.tx.updateWitness(0 , witness))
915+ case _ => htlcPenaltyTx
902916 }
903917
904- def addSigs (htlcSuccessTx : HtlcSuccessTx , localSig : ByteVector64 , remoteSig : ByteVector64 , paymentPreimage : ByteVector32 , commitmentFormat : CommitmentFormat ): HtlcSuccessTx = {
905- val witness = witnessHtlcSuccess(localSig, remoteSig, paymentPreimage, htlcSuccessTx.input.redeemScriptOrEmptyScript, commitmentFormat)
906- htlcSuccessTx.copy(tx = htlcSuccessTx.tx.updateWitness(0 , witness))
918+ def addSigs (htlcSuccessTx : HtlcSuccessTx , localSig : ByteVector64 , remoteSig : ByteVector64 , paymentPreimage : ByteVector32 , commitmentFormat : CommitmentFormat ): HtlcSuccessTx = htlcSuccessTx.input match {
919+ case InputInfo .SegwitInput (_, _, redeemScript) =>
920+ val witness = witnessHtlcSuccess(localSig, remoteSig, paymentPreimage, redeemScript, commitmentFormat)
921+ htlcSuccessTx.copy(tx = htlcSuccessTx.tx.updateWitness(0 , witness))
922+ case _ => htlcSuccessTx
907923 }
908924
909- def addSigs (htlcTimeoutTx : HtlcTimeoutTx , localSig : ByteVector64 , remoteSig : ByteVector64 , commitmentFormat : CommitmentFormat ): HtlcTimeoutTx = {
910- val witness = witnessHtlcTimeout(localSig, remoteSig, htlcTimeoutTx.input.redeemScriptOrEmptyScript, commitmentFormat)
911- htlcTimeoutTx.copy(tx = htlcTimeoutTx.tx.updateWitness(0 , witness))
925+ def addSigs (htlcTimeoutTx : HtlcTimeoutTx , localSig : ByteVector64 , remoteSig : ByteVector64 , commitmentFormat : CommitmentFormat ): HtlcTimeoutTx = htlcTimeoutTx.input match {
926+ case InputInfo .SegwitInput (_, _, redeemScript) =>
927+ val witness = witnessHtlcTimeout(localSig, remoteSig, redeemScript, commitmentFormat)
928+ htlcTimeoutTx.copy(tx = htlcTimeoutTx.tx.updateWitness(0 , witness))
929+ case _ => htlcTimeoutTx
912930 }
913931
914- def addSigs (claimHtlcSuccessTx : ClaimHtlcSuccessTx , localSig : ByteVector64 , paymentPreimage : ByteVector32 ): ClaimHtlcSuccessTx = {
915- val witness = witnessClaimHtlcSuccessFromCommitTx(localSig, paymentPreimage, claimHtlcSuccessTx.input.redeemScriptOrEmptyScript)
916- claimHtlcSuccessTx.copy(tx = claimHtlcSuccessTx.tx.updateWitness(0 , witness))
932+ def addSigs (claimHtlcSuccessTx : ClaimHtlcSuccessTx , localSig : ByteVector64 , paymentPreimage : ByteVector32 ): ClaimHtlcSuccessTx = claimHtlcSuccessTx.input match {
933+ case InputInfo .SegwitInput (_, _, redeemScript) =>
934+ val witness = witnessClaimHtlcSuccessFromCommitTx(localSig, paymentPreimage, redeemScript)
935+ claimHtlcSuccessTx.copy(tx = claimHtlcSuccessTx.tx.updateWitness(0 , witness))
936+ case _ => claimHtlcSuccessTx
917937 }
918938
919- def addSigs (claimHtlcTimeoutTx : ClaimHtlcTimeoutTx , localSig : ByteVector64 ): ClaimHtlcTimeoutTx = {
920- val witness = witnessClaimHtlcTimeoutFromCommitTx(localSig, claimHtlcTimeoutTx.input.redeemScriptOrEmptyScript)
921- claimHtlcTimeoutTx.copy(tx = claimHtlcTimeoutTx.tx.updateWitness(0 , witness))
939+ def addSigs (claimHtlcTimeoutTx : ClaimHtlcTimeoutTx , localSig : ByteVector64 ): ClaimHtlcTimeoutTx = claimHtlcTimeoutTx.input match {
940+ case InputInfo .SegwitInput (_, _, redeemScript) =>
941+ val witness = witnessClaimHtlcTimeoutFromCommitTx(localSig, redeemScript)
942+ claimHtlcTimeoutTx.copy(tx = claimHtlcTimeoutTx.tx.updateWitness(0 , witness))
943+ case _ => claimHtlcTimeoutTx
922944 }
923945
924946 def addSigs (claimP2WPKHOutputTx : ClaimP2WPKHOutputTx , localPaymentPubkey : PublicKey , localSig : ByteVector64 ): ClaimP2WPKHOutputTx = {
925947 val witness = ScriptWitness (Seq (der(localSig), localPaymentPubkey.value))
926948 claimP2WPKHOutputTx.copy(tx = claimP2WPKHOutputTx.tx.updateWitness(0 , witness))
927949 }
928950
929- def addSigs (claimRemoteDelayedOutputTx : ClaimRemoteDelayedOutputTx , localSig : ByteVector64 ): ClaimRemoteDelayedOutputTx = {
930- val witness = witnessClaimToRemoteDelayedFromCommitTx(localSig, claimRemoteDelayedOutputTx.input.redeemScriptOrEmptyScript)
931- claimRemoteDelayedOutputTx.copy(tx = claimRemoteDelayedOutputTx.tx.updateWitness(0 , witness))
951+ def addSigs (claimRemoteDelayedOutputTx : ClaimRemoteDelayedOutputTx , localSig : ByteVector64 ): ClaimRemoteDelayedOutputTx = claimRemoteDelayedOutputTx.input match {
952+ case InputInfo .SegwitInput (_, _, redeemScript) =>
953+ val witness = witnessClaimToRemoteDelayedFromCommitTx(localSig, redeemScript)
954+ claimRemoteDelayedOutputTx.copy(tx = claimRemoteDelayedOutputTx.tx.updateWitness(0 , witness))
955+ case _ => claimRemoteDelayedOutputTx
932956 }
933957
934- def addSigs (claimDelayedOutputTx : ClaimLocalDelayedOutputTx , localSig : ByteVector64 ): ClaimLocalDelayedOutputTx = {
935- val witness = witnessToLocalDelayedAfterDelay(localSig, claimDelayedOutputTx.input.redeemScriptOrEmptyScript)
936- claimDelayedOutputTx.copy(tx = claimDelayedOutputTx.tx.updateWitness(0 , witness))
958+ def addSigs (claimDelayedOutputTx : ClaimLocalDelayedOutputTx , localSig : ByteVector64 ): ClaimLocalDelayedOutputTx = claimDelayedOutputTx.input match {
959+ case InputInfo .SegwitInput (_, _, redeemScript) =>
960+ val witness = witnessToLocalDelayedAfterDelay(localSig, redeemScript)
961+ claimDelayedOutputTx.copy(tx = claimDelayedOutputTx.tx.updateWitness(0 , witness))
962+ case _ => claimDelayedOutputTx
937963 }
938964
939- def addSigs (htlcDelayedTx : HtlcDelayedTx , localSig : ByteVector64 ): HtlcDelayedTx = {
940- val witness = witnessToLocalDelayedAfterDelay(localSig, htlcDelayedTx.input.redeemScriptOrEmptyScript)
941- htlcDelayedTx.copy(tx = htlcDelayedTx.tx.updateWitness(0 , witness))
965+ def addSigs (htlcDelayedTx : HtlcDelayedTx , localSig : ByteVector64 ): HtlcDelayedTx = htlcDelayedTx.input match {
966+ case InputInfo .SegwitInput (_, _, redeemScript) =>
967+ val witness = witnessToLocalDelayedAfterDelay(localSig, redeemScript)
968+ htlcDelayedTx.copy(tx = htlcDelayedTx.tx.updateWitness(0 , witness))
969+ case _ => htlcDelayedTx
942970 }
943971
944- def addSigs (claimAnchorOutputTx : ClaimLocalAnchorOutputTx , localSig : ByteVector64 ): ClaimLocalAnchorOutputTx = {
945- val witness = witnessAnchor(localSig, claimAnchorOutputTx.input.redeemScriptOrEmptyScript)
946- claimAnchorOutputTx.copy(tx = claimAnchorOutputTx.tx.updateWitness(0 , witness))
972+ def addSigs (claimAnchorOutputTx : ClaimLocalAnchorOutputTx , localSig : ByteVector64 ): ClaimLocalAnchorOutputTx = claimAnchorOutputTx.input match {
973+ case InputInfo .SegwitInput (_, _, redeemScript) =>
974+ val witness = witnessAnchor(localSig, redeemScript)
975+ claimAnchorOutputTx.copy(tx = claimAnchorOutputTx.tx.updateWitness(0 , witness))
976+ case _ => claimAnchorOutputTx
947977 }
948978
949- def addSigs (claimHtlcDelayedPenalty : ClaimHtlcDelayedOutputPenaltyTx , revocationSig : ByteVector64 ): ClaimHtlcDelayedOutputPenaltyTx = {
950- val witness = Scripts .witnessToLocalDelayedWithRevocationSig(revocationSig, claimHtlcDelayedPenalty.input.redeemScriptOrEmptyScript)
951- claimHtlcDelayedPenalty.copy(tx = claimHtlcDelayedPenalty.tx.updateWitness(0 , witness))
979+ def addSigs (claimHtlcDelayedPenalty : ClaimHtlcDelayedOutputPenaltyTx , revocationSig : ByteVector64 ): ClaimHtlcDelayedOutputPenaltyTx = claimHtlcDelayedPenalty.input match {
980+ case InputInfo .SegwitInput (_, _, redeemScript) =>
981+ val witness = Scripts .witnessToLocalDelayedWithRevocationSig(revocationSig, redeemScript)
982+ claimHtlcDelayedPenalty.copy(tx = claimHtlcDelayedPenalty.tx.updateWitness(0 , witness))
983+ case _ => claimHtlcDelayedPenalty
952984 }
953985
954986 def addSigs (closingTx : ClosingTx , localFundingPubkey : PublicKey , remoteFundingPubkey : PublicKey , localSig : ByteVector64 , remoteSig : ByteVector64 ): ClosingTx = {
0 commit comments