record/routing: set minimum padding size

This commit is contained in:
Elle Mouton 2024-07-26 10:32:47 +02:00
parent 398623bde5
commit 60a856ab65
No known key found for this signature in database
GPG Key ID: D7D916376026F177
4 changed files with 34 additions and 7 deletions

View File

@ -10,6 +10,13 @@ import (
"github.com/lightningnetwork/lnd/tlv" "github.com/lightningnetwork/lnd/tlv"
) )
// AverageDummyHopPayloadSize is the size of a standard blinded path dummy hop
// payload. In most cases, this is larger than the other payload types and so
// to make sure that a sender cannot use this fact to know if a dummy hop is
// present or not, we'll make sure to always pad all payloads to at least this
// size.
const AverageDummyHopPayloadSize = 51
// BlindedRouteData contains the information that is included in a blinded // BlindedRouteData contains the information that is included in a blinded
// route encrypted data blob that is created by the recipient to provide // route encrypted data blob that is created by the recipient to provide
// forwarding information. // forwarding information.

View File

@ -196,6 +196,10 @@ func TestDummyHopBlindedDataEncoding(t *testing.T) {
encoded, err := EncodeBlindedRouteData(routeData) encoded, err := EncodeBlindedRouteData(routeData)
require.NoError(t, err) require.NoError(t, err)
// Assert the size of an average dummy hop payload in case we need to
// update this constant in future.
require.Len(t, encoded, AverageDummyHopPayloadSize)
b := bytes.NewBuffer(encoded) b := bytes.NewBuffer(encoded)
decodedData, err := DecodeBlindedRouteData(b) decodedData, err := DecodeBlindedRouteData(b)
require.NoError(t, err) require.NoError(t, err)

View File

@ -257,7 +257,9 @@ func buildBlindedPaymentPath(cfg *BuildBlindedPathCfg, path *candidatePath) (
// Add padding to each route data instance until the encrypted data // Add padding to each route data instance until the encrypted data
// blobs are all the same size. // blobs are all the same size.
paymentPath, _, err := padHopInfo(hopDataSet, true) paymentPath, _, err := padHopInfo(
hopDataSet, true, record.AverageDummyHopPayloadSize,
)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -731,9 +733,10 @@ type padStats struct {
// edges. The number of iterations that this function takes is also returned for // edges. The number of iterations that this function takes is also returned for
// testing purposes. If prePad is true, then zero byte padding is added to each // testing purposes. If prePad is true, then zero byte padding is added to each
// payload that does not yet have padding. This will save some iterations for // payload that does not yet have padding. This will save some iterations for
// the majority of cases. // the majority of cases. minSize can be used to specify a minimum size that all
func padHopInfo(hopInfo []*hopData, prePad bool) ([]*sphinx.HopInfo, *padStats, // payloads should be.
error) { func padHopInfo(hopInfo []*hopData, prePad bool, minSize int) (
[]*sphinx.HopInfo, *padStats, error) {
var ( var (
paymentPath = make([]*sphinx.HopInfo, len(hopInfo)) paymentPath = make([]*sphinx.HopInfo, len(hopInfo))
@ -759,7 +762,7 @@ func padHopInfo(hopInfo []*hopData, prePad bool) ([]*sphinx.HopInfo, *padStats,
// current largest encoded data blob size. This will be the // current largest encoded data blob size. This will be the
// size we aim to get the others to match. // size we aim to get the others to match.
var ( var (
maxLen int maxLen = minSize
minLen = math.MaxInt8 minLen = math.MaxInt8
) )
for i, hop := range hopInfo { for i, hop := range hopInfo {

View File

@ -237,6 +237,10 @@ func TestPadBlindedHopInfo(t *testing.T) {
// prePad is true if all the hop payloads should be pre-padded // prePad is true if all the hop payloads should be pre-padded
// with a zero length TLV Padding field. // with a zero length TLV Padding field.
prePad bool prePad bool
// minPayloadSize can be used to set the minimum number of bytes
// that the resulting records should be.
minPayloadSize int
}{ }{
{ {
// If there is only one entry, then no padding is // If there is only one entry, then no padding is
@ -250,6 +254,15 @@ func TestPadBlindedHopInfo(t *testing.T) {
// bytes. // bytes.
expectedFinalSize: 12, expectedFinalSize: 12,
}, },
{
// Same as the above example but with a minimum final
// size specified.
name: "single entry with min size",
expectedIterations: 2,
pathIDs: []int{10},
minPayloadSize: 500,
expectedFinalSize: 504,
},
{ {
// All the payloads are the same size from the get go // All the payloads are the same size from the get go
// meaning that no padding is expected. // meaning that no padding is expected.
@ -376,7 +389,7 @@ func TestPadBlindedHopInfo(t *testing.T) {
} }
hopInfo, stats, err := padHopInfo( hopInfo, stats, err := padHopInfo(
hopDataSet, test.prePad, hopDataSet, test.prePad, test.minPayloadSize,
) )
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, test.expectedIterations, require.Equal(t, test.expectedIterations,
@ -400,7 +413,7 @@ func TestPadBlindedHopInfo(t *testing.T) {
// asserts that the resulting padded set always has the same encoded length. // asserts that the resulting padded set always has the same encoded length.
func TestPadBlindedHopInfoBlackBox(t *testing.T) { func TestPadBlindedHopInfoBlackBox(t *testing.T) {
fn := func(data hopDataList) bool { fn := func(data hopDataList) bool {
resultList, _, err := padHopInfo(data, true) resultList, _, err := padHopInfo(data, true, 0)
require.NoError(t, err) require.NoError(t, err)
// There should be a resulting sphinx.HopInfo struct for each // There should be a resulting sphinx.HopInfo struct for each