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.
This commit is contained in:
Carla Kirk-Cohen 2024-04-02 09:50:13 -04:00
parent ca6d414308
commit da76d05fa5
No known key found for this signature in database
GPG Key ID: 4CA7FE54A6213C91
4 changed files with 52 additions and 6 deletions

View File

@ -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
}

View File

@ -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
}

View File

@ -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

View File

@ -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