Skip to content

Commit 3c7725d

Browse files
committed
fixup! multi: Support custom size onion packets
1 parent 6a45294 commit 3c7725d

File tree

3 files changed

+51
-45
lines changed

3 files changed

+51
-45
lines changed

cmd/main.go

Lines changed: 8 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -70,11 +70,12 @@ func main() {
7070
"data.",
7171
Value: defaultHopDataPath,
7272
},
73-
cli.BoolFlag{
74-
Name: "onion-message",
75-
Usage: "Create an onion message " +
76-
"packet rather than a " +
77-
"payment onion.",
73+
cli.IntFlag{
74+
Name: "payload-size",
75+
Usage: "The size for a payload for a " +
76+
"single hop. Defaults to the " +
77+
"max routing payload size",
78+
Value: sphinx.MaxRoutingPayloadSize,
7879
},
7980
},
8081
},
@@ -209,18 +210,10 @@ func generate(ctx *cli.Context) error {
209210
return fmt.Errorf("could not peel onion spec: %v", err)
210211
}
211212

212-
payloadSizes := []int{
213-
sphinx.MaxRoutingPayloadSize,
214-
}
215-
if ctx.Bool("onion-message") {
216-
payloadSizes = append(
217-
payloadSizes,
218-
sphinx.MaxOnionMessagePayloadSize,
219-
)
220-
}
213+
payloadSize := ctx.Int("payload-size")
221214
msg, err := sphinx.NewOnionPacket(
222215
path, sessionKey, assocData, sphinx.DeterministicPacketFiller,
223-
payloadSizes...,
216+
sphinx.WithMaxPayloadSize(payloadSize),
224217
)
225218
if err != nil {
226219
return fmt.Errorf("error creating message: %v", err)

sphinx.go

Lines changed: 32 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ import (
66
"crypto/sha256"
77
"fmt"
88
"io"
9-
"sort"
109
"sync"
1110

1211
"github.com/btcsuite/btcd/btcec/v2"
@@ -180,14 +179,37 @@ func generateSharedSecrets(paymentPath []*btcec.PublicKey,
180179
return hopSharedSecrets, lastEphemeralPubKey, nil
181180
}
182181

182+
type newOnionPacketCfg struct {
183+
payloadSize int
184+
}
185+
186+
type NewOnionPacketOpt func(cfg *newOnionPacketCfg)
187+
188+
func WithMaxPayloadSize(size int) NewOnionPacketOpt {
189+
return func(cfg *newOnionPacketCfg) {
190+
cfg.payloadSize = size
191+
}
192+
}
193+
183194
// NewOnionPacket creates a new onion packet which is capable of obliviously
184195
// routing a message through the mix-net path outline by 'paymentPath'. The
185196
// total size of the onion 'clicks' to the first value in payloadSizes that is
186197
// bigger than the total payload size of the path. If no size is given, it
187198
// defaults to the maximum routing payload size.
188199
func NewOnionPacket(paymentPath *PaymentPath, sessionKey *btcec.PrivateKey,
189200
assocData []byte, pktFiller PacketFiller,
190-
payloadSizes ...int) (*OnionPacket, error) {
201+
opts ...NewOnionPacketOpt) (*OnionPacket, error) {
202+
203+
cfg := &newOnionPacketCfg{}
204+
for _, o := range opts {
205+
o(cfg)
206+
}
207+
208+
// We default to the maximum routing payload size if the caller didn't
209+
// provide any payload sizes.
210+
if cfg.payloadSize == 0 {
211+
cfg.payloadSize = MaxRoutingPayloadSize
212+
}
191213

192214
// If we don't actually have a partially populated route, then we'll
193215
// exit early.
@@ -198,29 +220,9 @@ func NewOnionPacket(paymentPath *PaymentPath, sessionKey *btcec.PrivateKey,
198220

199221
totalPayloadSize := paymentPath.TotalPayloadSize()
200222

201-
// We default to the maximum routing payload size if the caller didn't
202-
// provide any payload sizes.
203-
if len(payloadSizes) == 0 {
204-
payloadSizes = []int{MaxRoutingPayloadSize}
205-
}
206-
207-
sort.Ints(payloadSizes)
208-
209-
// We'll now select the smallest payload size that is large enough to
210-
// fit the entire onion payload. If no such size exists, then we'll
211-
// return an error
212-
var payloadSize int
213-
found := false
214-
for _, size := range payloadSizes {
215-
if size >= totalPayloadSize {
216-
payloadSize = size
217-
found = true
218-
break
219-
}
220-
}
221-
222-
// Return an error if we couldn't find a suitable payload size.
223-
if !found {
223+
// Return an error if the actual payload size exceeds the configured
224+
// payload size.
225+
if totalPayloadSize > cfg.payloadSize {
224226
return nil, ErrPayloadSizeExceeded
225227
}
226228

@@ -241,13 +243,13 @@ func NewOnionPacket(paymentPath *PaymentPath, sessionKey *btcec.PrivateKey,
241243

242244
// Generate the padding, called "filler strings" in the paper.
243245
filler := generateHeaderPadding(
244-
"rho", paymentPath, hopSharedSecrets, payloadSize,
246+
"rho", paymentPath, hopSharedSecrets, cfg.payloadSize,
245247
)
246248

247249
// Allocate zero'd out byte slices to store the final mix header packet
248250
// and the hmac for each hop.
249251
var (
250-
mixHeader = make([]byte, payloadSize)
252+
mixHeader = make([]byte, cfg.payloadSize)
251253
nextHmac [HMACSize]byte
252254
hopPayloadBuf bytes.Buffer
253255
)
@@ -274,7 +276,9 @@ func NewOnionPacket(paymentPath *PaymentPath, sessionKey *btcec.PrivateKey,
274276
// Next, using the key dedicated for our stream cipher, we'll
275277
// generate enough bytes to obfuscate this layer of the onion
276278
// packet.
277-
streamBytes := generateCipherStream(rhoKey, uint(payloadSize))
279+
streamBytes := generateCipherStream(
280+
rhoKey, uint(cfg.payloadSize),
281+
)
278282
payload := paymentPath[i].HopPayload
279283

280284
// Before we assemble the packet, we'll shift the current

sphinx_test.go

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -275,11 +275,20 @@ func newOnionMessageRoute(numHops int) (*OnionPacket, *PaymentPath, []*Router,
275275
}
276276
}
277277

278+
// According to BOLT04 we SHOULD set onion_message_packet len to 1366 or
279+
// 32834. This means a payload size of 1300 (MaxRoutingPayloadSize) or
280+
// 32768 (MaxOnionMessagePayloadSize) bytes. By checking the total
281+
// payload size of the route we can determine which one to use.
282+
payloadSize := MaxRoutingPayloadSize
283+
if route.TotalPayloadSize() > MaxRoutingPayloadSize {
284+
payloadSize = MaxOnionMessagePayloadSize
285+
}
286+
278287
// Generate the onion packet.
279288
sessionKey, _ := btcec.NewPrivateKey()
280289
onionPacket, err := NewOnionPacket(
281290
&route, sessionKey, nil, DeterministicPacketFiller,
282-
MaxRoutingPayloadSize, MaxOnionMessagePayloadSize,
291+
WithMaxPayloadSize(payloadSize),
283292
)
284293
if err != nil {
285294
return nil, nil, nil, fmt.Errorf("unable to create onion "+
@@ -898,7 +907,7 @@ func TestCustomPayloadSize(t *testing.T) {
898907
// Now, create the onion packet.
899908
onionPacket, err := NewOnionPacket(
900909
path, sessionKey, nil, DeterministicPacketFiller,
901-
customPayloadSize,
910+
WithMaxPayloadSize(customPayloadSize),
902911
)
903912
require.NoError(t, err)
904913

0 commit comments

Comments
 (0)