From da76d05fa59b963807a422f3d023f34bc7e15168 Mon Sep 17 00:00:00 2001 From: Carla Kirk-Cohen Date: Tue, 2 Apr 2024 09:50:13 -0400 Subject: [PATCH] htlcswitch: add NextBlinding to ForwardingInfo and set in UpdateAddHtlc When we have a HTLC that is part of a blinded route, we need to include the next ephemeral blinding point in UpdateAddHtlc for the next hop. The way that we handle the addition of this key is the same for introduction nodes and relaying nodes within the route. --- htlcswitch/hop/forwarding_info.go | 5 +++++ htlcswitch/hop/iterator.go | 32 +++++++++++++++++++++++++++++++ htlcswitch/hop/iterator_test.go | 7 +++++++ htlcswitch/link.go | 14 ++++++++------ 4 files changed, 52 insertions(+), 6 deletions(-) diff --git a/htlcswitch/hop/forwarding_info.go b/htlcswitch/hop/forwarding_info.go index 3ec358a0a..5a1463c48 100644 --- a/htlcswitch/hop/forwarding_info.go +++ b/htlcswitch/hop/forwarding_info.go @@ -22,4 +22,9 @@ type ForwardingInfo struct { // OutgoingCTLV is the specified value of the CTLV timelock to be used // in the outgoing HTLC. OutgoingCTLV uint32 + + // NextBlinding is an optional blinding point to be passed to the next + // node in UpdateAddHtlc. This field is set if the htlc is part of a + // blinded route. + NextBlinding lnwire.BlindingPointRecord } diff --git a/htlcswitch/hop/iterator.go b/htlcswitch/hop/iterator.go index 87691d192..68b08fe42 100644 --- a/htlcswitch/hop/iterator.go +++ b/htlcswitch/hop/iterator.go @@ -131,6 +131,10 @@ type BlindingProcessor interface { // ephemeral key provided. DecryptBlindedHopData(ephemPub *btcec.PublicKey, encryptedData []byte) ([]byte, error) + + // NextEphemeral returns the next hop's ephemeral key, calculated + // from the current ephemeral key provided. + NextEphemeral(*btcec.PublicKey) (*btcec.PublicKey, error) } // BlindingKit contains the components required to extract forwarding @@ -250,12 +254,40 @@ func (b *BlindingKit) DecryptAndValidateFwdInfo(payload *Payload, return nil, err } + // If we have an override for the blinding point for the next node, + // we'll just use it without tweaking (the sender intended to switch + // out directly for this blinding point). Otherwise, we'll tweak our + // blinding point to get the next ephemeral key. + nextEph, err := routeData.NextBlindingOverride.UnwrapOrFuncErr( + func() (tlv.RecordT[tlv.TlvType8, + *btcec.PublicKey], error) { + + next, err := b.Processor.NextEphemeral(blindingPoint) + if err != nil { + // Return a zero record because we expect the + // error to be checked. + return routeData.NextBlindingOverride.Zero(), + err + } + + return tlv.NewPrimitiveRecord[tlv.TlvType8](next), nil + }, + ) + if err != nil { + return nil, err + } + return &ForwardingInfo{ NextHop: routeData.ShortChannelID.Val, AmountToForward: fwdAmt, OutgoingCTLV: b.IncomingCltv - uint32( routeData.RelayInfo.Val.CltvExpiryDelta, ), + // Remap from blinding override type to blinding point type. + NextBlinding: tlv.SomeRecordT( + tlv.NewPrimitiveRecord[lnwire.BlindingPointTlvType]( + nextEph.Val), + ), }, nil } diff --git a/htlcswitch/hop/iterator_test.go b/htlcswitch/hop/iterator_test.go index e39dbb151..60919333b 100644 --- a/htlcswitch/hop/iterator_test.go +++ b/htlcswitch/hop/iterator_test.go @@ -170,6 +170,13 @@ func (m *mockProcessor) DecryptBlindedHopData(_ *btcec.PublicKey, return data, m.decryptErr } +// NextEphemeral mocks getting our next ephemeral key. +func (m *mockProcessor) NextEphemeral(*btcec.PublicKey) (*btcec.PublicKey, + error) { + + return nil, nil +} + // TestDecryptAndValidateFwdInfo tests deriving forwarding info using a // blinding kit. This test does not cover assertions on the calculations of // forwarding information, because this is covered in a test dedicated to those diff --git a/htlcswitch/link.go b/htlcswitch/link.go index 3288584d5..45b9a8729 100644 --- a/htlcswitch/link.go +++ b/htlcswitch/link.go @@ -3348,9 +3348,10 @@ func (l *channelLink) processRemoteAdds(fwdPkg *channeldb.FwdPkg, // Otherwise, it was already processed, we can // can collect it and continue. addMsg := &lnwire.UpdateAddHTLC{ - Expiry: fwdInfo.OutgoingCTLV, - Amount: fwdInfo.AmountToForward, - PaymentHash: pd.RHash, + Expiry: fwdInfo.OutgoingCTLV, + Amount: fwdInfo.AmountToForward, + PaymentHash: pd.RHash, + BlindingPoint: fwdInfo.NextBlinding, } // Finally, we'll encode the onion packet for @@ -3393,9 +3394,10 @@ func (l *channelLink) processRemoteAdds(fwdPkg *channeldb.FwdPkg, // create the outgoing HTLC using the parameters as // specified in the forwarding info. addMsg := &lnwire.UpdateAddHTLC{ - Expiry: fwdInfo.OutgoingCTLV, - Amount: fwdInfo.AmountToForward, - PaymentHash: pd.RHash, + Expiry: fwdInfo.OutgoingCTLV, + Amount: fwdInfo.AmountToForward, + PaymentHash: pd.RHash, + BlindingPoint: fwdInfo.NextBlinding, } // Finally, we'll encode the onion packet for the