Skip to content

Commit

Permalink
Fix HTLC signing process
Browse files Browse the repository at this point in the history
PSBT sign function needs transaction builder for any
non-predefined script templates so we use helper
function currently available in DNL to sign ITimeoutTxs.
  • Loading branch information
aarani authored and knocte committed Dec 2, 2021
1 parent 4241283 commit 37fe5af
Show file tree
Hide file tree
Showing 3 changed files with 21 additions and 25 deletions.
26 changes: 14 additions & 12 deletions src/DotNetLightning.Core/Channel/Channel.fs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ open DotNetLightning.Utils.Aether
open DotNetLightning.Chain
open DotNetLightning.Crypto
open DotNetLightning.Transactions
open DotNetLightning.Transactions.Transactions
open DotNetLightning.Serialization
open DotNetLightning.Serialization.Msgs
open NBitcoin
Expand Down Expand Up @@ -1230,7 +1231,7 @@ and Channel = {
let htlcSigs =
sortedHTLCTXs
|> List.map(
(fun htlc -> channelPrivKeys.SignHtlcTx htlc.Value remoteNextPerCommitmentPoint)
(fun htlc -> signHtlcTx htlc channelPrivKeys remoteNextPerCommitmentPoint)
>> fst
>> (fun txSig -> txSig.Signature)
)
Expand Down Expand Up @@ -1311,29 +1312,30 @@ and Channel = {
let sortedHTLCTXs = Commitments.Helpers.sortBothHTLCs htlcTimeoutTxs htlcSuccessTxs
do! Commitments.checkSignatureCountMismatch sortedHTLCTXs msg

let _localHTLCSigs, sortedHTLCTXs =
let localHtlcSigsAndHTLCTxs =
sortedHTLCTXs |> List.map(fun htlc ->
channelPrivKeys.SignHtlcTx htlc.Value localPerCommitmentPoint
)
localHtlcSigsAndHTLCTxs |> List.map(fst), localHtlcSigsAndHTLCTxs |> List.map(snd) |> Seq.cast<IHTLCTx> |> List.ofSeq
let htlcTxsAndSignatures =
sortedHTLCTXs
|> List.zip (msg.HTLCSignatures)
|> List.map(fun (remoteSig, htlc) ->
htlc, signHtlcTx htlc channelPrivKeys localPerCommitmentPoint |> fst, remoteSig
)

let remoteHTLCPubKey = localPerCommitmentPoint.DeriveHtlcPubKey remoteChannelKeys.HtlcBasepoint

let checkHTLCSig (htlc: IHTLCTx, remoteECDSASig: LNECDSASignature): Result<_, _> =
let remoteS = TransactionSignature(remoteECDSASig.Value, SigHash.All)
let checkHTLCSig (htlc: IHTLCTx, localSignature: TransactionSignature, remoteECDSASig: LNECDSASignature): Result<_, _> =
let remoteSignature = TransactionSignature(remoteECDSASig.Value, SigHash.All)
match htlc with
| :? HTLCTimeoutTx ->
(Transactions.checkTxFinalized (htlc.Value) (0) (seq [(remoteHTLCPubKey.RawPubKey(), remoteS)]))
(htlc :?> HTLCTimeoutTx).Finalize(localSignature, remoteSignature)
|> Result.map(FinalizedTx)
|> Result.map(box)
// we cannot check that htlc-success tx are spendable because we need the payment preimage; thus we only check the remote sig
| :? HTLCSuccessTx ->
(Transactions.checkSigAndAdd (htlc) (remoteS) (remoteHTLCPubKey.RawPubKey()))
Transactions.checkSigAndAdd htlc remoteSignature (remoteHTLCPubKey.RawPubKey())
|> Result.map(box)
| _ -> failwith "Unreachable!"

let! txList =
List.zip sortedHTLCTXs msg.HTLCSignatures
htlcTxsAndSignatures
|> List.map(checkHTLCSig)
|> List.sequenceResultA
|> expectTransactionErrors
Expand Down
13 changes: 0 additions & 13 deletions src/DotNetLightning.Core/Crypto/KeyExtensions.fs
Original file line number Diff line number Diff line change
Expand Up @@ -280,19 +280,6 @@ module KeyExtensions =
| Some signature -> (signature, psbt)
| None -> failwithf "Failed to get signature for %A with funding pub key (%A). This should never happen" psbt fundingPubKey

member this.SignHtlcTx (psbt: PSBT)
(perCommitmentPoint: PerCommitmentPoint)
: TransactionSignature * PSBT =
let htlcPrivKey = perCommitmentPoint.DeriveHtlcPrivKey this.HtlcBasepointSecret
let htlcPubKey = htlcPrivKey.HtlcPubKey()
psbt.SignWithKeys(htlcPrivKey.RawKey()) |> ignore
match psbt.GetMatchingSig(htlcPubKey.RawPubKey()) with
| Some signature -> (signature, psbt)
| None ->
failwithf
"failed to get htlc signature for %A. with htlc pubkey (%A) and perCommitmentPoint (%A)"
psbt htlcPubKey perCommitmentPoint

/// This is the node-wide master key which is also used for
/// transport-level encryption. The channel's keys are derived from
/// this via BIP32 key derivation where `channelIndex` is the child
Expand Down
7 changes: 7 additions & 0 deletions src/DotNetLightning.Core/Transactions/Transactions.fs
Original file line number Diff line number Diff line change
Expand Up @@ -519,6 +519,13 @@ module Transactions =
| Error e -> failwithf "%A" e

let sign(tx, key) = signCore(tx, key, true)
let signHtlcTx (htlc: IHTLCTx) (channelPrivKeys: ChannelPrivKeys) (perCommitmentPoint: PerCommitmentPoint) =
let htlcPrivKey =
perCommitmentPoint.DeriveHtlcPrivKey
channelPrivKeys.HtlcBasepointSecret

sign(htlc, htlcPrivKey.RawKey())

let makeHTLCTimeoutTx (commitTx: Transaction)
(localDustLimit: Money)
(localRevocationPubKey: RevocationPubKey)
Expand Down

0 comments on commit 37fe5af

Please sign in to comment.