diff --git a/contractcourt/htlc_incoming_contest_resolver.go b/contractcourt/htlc_incoming_contest_resolver.go index 9c45ee7ba..d43a50d90 100644 --- a/contractcourt/htlc_incoming_contest_resolver.go +++ b/contractcourt/htlc_incoming_contest_resolver.go @@ -7,6 +7,7 @@ import ( "fmt" "io" + "github.com/btcsuite/btcd/btcec/v2" "github.com/btcsuite/btcd/btcutil" "github.com/btcsuite/btcd/txscript" "github.com/lightningnetwork/lnd/channeldb" @@ -17,6 +18,7 @@ import ( "github.com/lightningnetwork/lnd/lnwallet" "github.com/lightningnetwork/lnd/lnwire" "github.com/lightningnetwork/lnd/queue" + "github.com/lightningnetwork/lnd/tlv" ) // htlcIncomingContestResolver is a ContractResolver that's able to resolve an @@ -520,9 +522,18 @@ func (h *htlcIncomingContestResolver) Supplement(htlc channeldb.HTLC) { func (h *htlcIncomingContestResolver) decodePayload() (*hop.Payload, []byte, error) { + var blindingPoint *btcec.PublicKey + h.htlc.BlindingPoint.WhenSome( + func(b tlv.RecordT[lnwire.BlindingPointTlvType, + *btcec.PublicKey]) { + + blindingPoint = b.Val + }, + ) + onionReader := bytes.NewReader(h.htlc.OnionBlob[:]) iterator, err := h.OnionProcessor.ReconstructHopIterator( - onionReader, h.htlc.RHash[:], + onionReader, h.htlc.RHash[:], blindingPoint, ) if err != nil { return nil, nil, err diff --git a/contractcourt/htlc_incoming_contest_resolver_test.go b/contractcourt/htlc_incoming_contest_resolver_test.go index e8532abe5..d789858fb 100644 --- a/contractcourt/htlc_incoming_contest_resolver_test.go +++ b/contractcourt/htlc_incoming_contest_resolver_test.go @@ -6,6 +6,7 @@ import ( "io/ioutil" "testing" + "github.com/btcsuite/btcd/btcec/v2" sphinx "github.com/lightningnetwork/lightning-onion" "github.com/lightningnetwork/lnd/chainntnfs" "github.com/lightningnetwork/lnd/channeldb" @@ -288,8 +289,8 @@ type mockOnionProcessor struct { offeredOnionBlob []byte } -func (o *mockOnionProcessor) ReconstructHopIterator(r io.Reader, rHash []byte) ( - hop.Iterator, error) { +func (o *mockOnionProcessor) ReconstructHopIterator(r io.Reader, rHash []byte, + blindingPoint *btcec.PublicKey) (hop.Iterator, error) { data, err := ioutil.ReadAll(r) if err != nil { diff --git a/contractcourt/interfaces.go b/contractcourt/interfaces.go index 45cd75735..146670a41 100644 --- a/contractcourt/interfaces.go +++ b/contractcourt/interfaces.go @@ -4,6 +4,7 @@ import ( "context" "io" + "github.com/btcsuite/btcd/btcec/v2" "github.com/btcsuite/btcd/wire" "github.com/lightningnetwork/lnd/channeldb" "github.com/lightningnetwork/lnd/channeldb/models" @@ -40,7 +41,8 @@ type Registry interface { type OnionProcessor interface { // ReconstructHopIterator attempts to decode a valid sphinx packet from // the passed io.Reader instance. - ReconstructHopIterator(r io.Reader, rHash []byte) (hop.Iterator, error) + ReconstructHopIterator(r io.Reader, rHash []byte, + blindingKey *btcec.PublicKey) (hop.Iterator, error) } // UtxoSweeper defines the sweep functions that contract court requires. diff --git a/htlcswitch/hop/iterator.go b/htlcswitch/hop/iterator.go index 71d8e1b9c..1829522f4 100644 --- a/htlcswitch/hop/iterator.go +++ b/htlcswitch/hop/iterator.go @@ -150,20 +150,27 @@ func (p *OnionProcessor) Stop() error { // ReconstructHopIterator attempts to decode a valid sphinx packet from the passed io.Reader // instance using the rHash as the associated data when checking the relevant // MACs during the decoding process. -func (p *OnionProcessor) ReconstructHopIterator(r io.Reader, rHash []byte) ( - Iterator, error) { +func (p *OnionProcessor) ReconstructHopIterator(r io.Reader, rHash []byte, + blindingPoint *btcec.PublicKey) (Iterator, error) { onionPkt := &sphinx.OnionPacket{} if err := onionPkt.Decode(r); err != nil { return nil, err } + var opts []sphinx.ProcessOnionOpt + if blindingPoint != nil { + opts = append(opts, sphinx.WithBlindingPoint(blindingPoint)) + } + // Attempt to process the Sphinx packet. We include the payment hash of // the HTLC as it's authenticated within the Sphinx packet itself as // associated data in order to thwart attempts a replay attacks. In the // case of a replay, an attacker is *forced* to use the same payment // hash twice, thereby losing their money entirely. - sphinxPacket, err := p.router.ReconstructOnionPacket(onionPkt, rHash) + sphinxPacket, err := p.router.ReconstructOnionPacket( + onionPkt, rHash, opts..., + ) if err != nil { return nil, err }