Skip to content

Commit 1ce3fd7

Browse files
committed
sphinx: remove HopData from OnionHop, expose left over EOB from payload
In this commit, we remove the HopData field from the OnionHop struct as it's no longer needed since we can obtain the HopData via the HopData() method of the HopPayload struct. Additinoally, we also now return the set of unused payload bytes after the HopData encoding, we call these the EOB or extra onion blobs. With this distinction we now provide the caller of ProcessOnionPacket with the forwarding instructions, then the left over EOB bytes. These EOB bytes will then be interpreted using a TLV format or any other arbitrary framing system.
1 parent d70c20f commit 1ce3fd7

File tree

4 files changed

+46
-48
lines changed

4 files changed

+46
-48
lines changed

bench_test.go

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,15 +28,19 @@ func BenchmarkPathPacketConstruction(b *testing.B) {
2828
}
2929

3030
hopData := HopData{
31-
Realm: [1]byte{0x00},
3231
ForwardAmount: uint64(i),
3332
OutgoingCltv: uint32(i),
3433
}
3534
copy(hopData.NextAddress[:], bytes.Repeat([]byte{byte(i)}, 8))
3635

36+
hopPayload, err := NewHopPayload(0, &hopData, nil)
37+
if err != nil {
38+
b.Fatalf("unable to create new hop payload: %v", err)
39+
}
40+
3741
route[i] = OnionHop{
38-
NodePub: *privKey.PubKey(),
39-
HopData: hopData,
42+
NodePub: *privKey.PubKey(),
43+
HopPayload: hopPayload,
4044
}
4145
}
4246

path.go

Lines changed: 15 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -257,39 +257,30 @@ func (hp *HopPayload) Decode(r io.Reader) error {
257257

258258
// HopData attempts to extract a set of forwarding instructions from the target
259259
// HopPayload. If the realm isn't what we expect, then an error is returned.
260-
func (hp *HopPayload) HopData() (*HopData, error) {
260+
// This method also returns the left over EOB that remain after the hop data
261+
// has been parsed. Callers may want to map this blob into something more
262+
// concrete.
263+
func (hp *HopPayload) HopData() (*HopData, []byte, error) {
261264
// If this isn't the "base" realm, then we can't extract the expected
262265
// hop payload structure from the payload.
263-
if hp.Realm[0]&RealmMaskBytes != 0x00 {
264-
return nil, fmt.Errorf("payload is not a HopData payload, "+
265-
"realm=%d", hp.Realm[0])
266+
if hp.Realm() != 0x00 {
267+
return nil, nil, fmt.Errorf("payload is not a HopData "+
268+
"payload, realm=%d", hp.Realm())
266269
}
267270

268271
// Now that we know the payload has the structure we expect, we'll
269272
// decode the payload into the HopData.
270-
hd := HopData{
271-
Realm: [1]byte{hp.Realm[0] & RealmMaskBytes},
272-
HMAC: hp.HMAC,
273+
var hd HopData
274+
payloadReader := bytes.NewBuffer(hp.Payload)
275+
if err := hd.Decode(payloadReader); err != nil {
276+
return &hd, nil, nil
273277
}
274278

275-
r := bytes.NewBuffer(hp.Payload)
276-
if _, err := io.ReadFull(r, hd.NextAddress[:]); err != nil {
277-
return nil, err
278-
}
279-
280-
if err := binary.Read(r, binary.BigEndian, &hd.ForwardAmount); err != nil {
281-
return nil, err
282-
}
283-
284-
if err := binary.Read(r, binary.BigEndian, &hd.OutgoingCltv); err != nil {
285-
return nil, err
286-
}
279+
// What's left over in the buffer that wasn't parsed as part of the
280+
// forwarding instructions is our lingering EOB.
281+
eob := payloadReader.Bytes()
287282

288-
if _, err := io.ReadFull(r, hd.ExtraBytes[:]); err != nil {
289-
return nil, err
290-
}
291-
292-
return &hd, nil
283+
return &hd, eob, nil
293284
}
294285

295286
// NumMaxHops is the maximum path length. This should be set to an estimate of
@@ -318,10 +309,6 @@ type OnionHop struct {
318309
// internal packet to the next hop.
319310
NodePub btcec.PublicKey
320311

321-
// HopData are the plaintext routing instructions that should be
322-
// delivered to this hop.
323-
HopData HopData
324-
325312
// HopPayload is the opaque payload provided to this node. If the
326313
// HopData above is specified, then it'll be packed into this payload.
327314
HopPayload HopPayload

sphinx.go

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -443,17 +443,19 @@ type ProcessedPacket struct {
443443
// MoreHops.
444444
ForwardingInstructions *HopData
445445

446-
// RawPayload is the raw (plaintext) payload that was passed to the
447-
// processing node in the onion packet. It provides accessors to get
448-
// the parsed and interpreted data.
449-
RawPayload HopPayload
446+
// ExtraOnionBlob is the raw EOB payload unpacked by this hop. This is
447+
// the portion of the payload _without_ the prefixed forwarding
448+
// instructions.
449+
ExtraOnionBlob []byte
450450

451451
// NextPacket is the onion packet that should be forwarded to the next
452452
// hop as denoted by the ForwardingInstructions field.
453453
//
454454
// NOTE: This field will only be populated iff the above Action is
455455
// MoreHops.
456456
NextPacket *OnionPacket
457+
458+
rawPayload HopPayload
457459
}
458460

459461
// Router is an onion router within the Sphinx network. The router is capable
@@ -649,7 +651,7 @@ func processOnionPacket(onionPkt *OnionPacket, sharedSecret *Hash256,
649651
action = ExitNode
650652
}
651653

652-
hopData, err := outerHopPayload.HopData()
654+
hopData, eob, err := outerHopPayload.HopData()
653655
if err != nil {
654656
return nil, err
655657
}
@@ -660,8 +662,9 @@ func processOnionPacket(onionPkt *OnionPacket, sharedSecret *Hash256,
660662
return &ProcessedPacket{
661663
Action: action,
662664
ForwardingInstructions: hopData,
663-
RawPayload: *outerHopPayload,
665+
ExtraOnionBlob: eob,
664666
NextPacket: innerPkt,
667+
rawPayload: *outerHopPayload,
665668
}, nil
666669
}
667670

sphinx_test.go

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -113,11 +113,9 @@ func newTestVarSizeRoute(numHops int, extraPayloadSize []int) ([]*Router, *Payme
113113
)
114114
for i := 0; i < len(nodes); i++ {
115115
hopData := HopData{
116-
Realm: [1]byte{0x00},
117116
ForwardAmount: uint64(i),
118117
OutgoingCltv: uint32(i),
119118
}
120-
121119
copy(hopData.NextAddress[:], bytes.Repeat([]byte{byte(i)}, 8))
122120

123121
var extraData []byte
@@ -157,7 +155,13 @@ func newTestVarSizeRoute(numHops int, extraPayloadSize []int) ([]*Router, *Payme
157155

158156
var hopsData []HopData
159157
for i := 0; i < len(nodes); i++ {
160-
hopsData = append(hopsData, route[i].HopData)
158+
hopData, _, err := route[i].HopPayload.HopData()
159+
if err != nil {
160+
return nil, nil, nil, nil, fmt.Errorf("unable to "+
161+
"gen hop data: %v", err)
162+
}
163+
164+
hopsData = append(hopsData, *hopData)
161165
}
162166

163167
return nodes, &route, &hopsData, fwdMsg, nil
@@ -564,22 +568,22 @@ func TestMultiFrameEncodeDecode(t *testing.T) {
564568
"forwarding message: %v", i, err)
565569
}
566570

567-
// Check that the framecount matches what we expect
568-
frameCount := onionPacket.RawPayload.NumFrames()
571+
// Check that the frame count matches what we expect
572+
frameCount := onionPacket.rawPayload.NumFrames()
569573
if tt.expectedFrames[i] != frameCount {
570-
t.Fatalf("Incorrect number of payload frames: expected %d, got %d",
571-
tt.expectedFrames[i],
572-
frameCount,
574+
t.Fatalf("incorrect number of payload "+
575+
"frames: expected %d, got %d",
576+
tt.expectedFrames[i], frameCount,
573577
)
574578
}
575579

576580
// Check that the payload contents are identical
577581
expected := path[i].HopPayload
578582
if !bytes.Equal(path[i].HopPayload.Payload, expected.Payload) {
579-
t.Fatalf("Processing error, hop-payload parsed incorrectly."+
580-
" expected %x, got %x",
583+
t.Fatalf("processing error, hop-payload "+
584+
"parsed incorrectly. expected %x, got %x",
581585
expected.Payload,
582-
onionPacket.RawPayload.Payload)
586+
onionPacket.rawPayload.Payload)
583587
}
584588

585589
fwdMsg = onionPacket.NextPacket

0 commit comments

Comments
 (0)