Skip to content

Commit 90ace25

Browse files
committed
sphinx_test: add test for blinded route processing
We add TestOnionMessageRouteBlinding which verifies that the onion message packet from the test vector can be processed correctly by the nodes in a blinded route.
1 parent d17321d commit 90ace25

File tree

1 file changed

+108
-4
lines changed

1 file changed

+108
-4
lines changed

path_test.go

Lines changed: 108 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -331,6 +331,106 @@ func TestOnionRouteBlinding(t *testing.T) {
331331
}
332332
}
333333

334+
// TestOnionMessageRouteBlinding tests that an onion message packet can
335+
// correctly be processed by a node in a blinded route.
336+
func TestOnionMessageRouteBlinding(t *testing.T) {
337+
t.Parallel()
338+
339+
// First, we'll read out the raw Json file at the target location.
340+
jsonBytes, err := os.ReadFile(blindedOnionMessageOnionTestFileName)
341+
require.NoError(t, err)
342+
343+
// Once we have the raw file, we'll unpack it into our
344+
// blindingJsonTestCase struct defined above.
345+
testCase := &onionMessageJsonTestCase{}
346+
require.NoError(t, json.Unmarshal(jsonBytes, testCase))
347+
348+
// Extract the original onion message packet to be processed.
349+
onion, err := hex.DecodeString(testCase.OnionMessage.OnionMessagePacket)
350+
require.NoError(t, err)
351+
352+
onionBytes := bytes.NewReader(onion)
353+
onionPacket := &OnionPacket{}
354+
require.NoError(t, onionPacket.Decode(onionBytes))
355+
356+
// peelOnion is a helper closure that can be used to set up a Router
357+
// and use it to process the given onion packet.
358+
peelOnion := func(key *btcec.PrivateKey,
359+
blindingPoint *btcec.PublicKey) *ProcessedPacket {
360+
361+
r := NewRouter(
362+
&PrivKeyECDH{PrivKey: key}, NewMemoryReplayLog(),
363+
)
364+
365+
require.NoError(t, r.Start())
366+
defer r.Stop()
367+
368+
res, err := r.ProcessOnionPacket(
369+
onionPacket, nil, 10,
370+
WithBlindingPoint(blindingPoint),
371+
)
372+
require.NoError(t, err)
373+
374+
return res
375+
}
376+
377+
hops := testCase.Generate.Hops
378+
379+
// There are some things that the processor of the onion packet will
380+
// only be able to determine from the actual contents of the encrypted
381+
// data it receives. These things include the next_blinding_point for
382+
// the introduction point and the next_blinding_override. The decryption
383+
// of this data is dependent on the encoding chosen by higher layers.
384+
// The test uses TLVs. Since the extraction of this data is dependent
385+
// on layers outside the scope of this library, we provide handle these
386+
// cases manually for the sake of the test.
387+
var (
388+
firstBlinding = pubKeyFromString(testCase.Route.FirstPathKey)
389+
390+
concatIndex = 1
391+
blindingOverride = pubKeyFromString(hops[0].EncodedOnionMessageTLVs.NextPathKeyOverride)
392+
)
393+
394+
var blindingPoint *btcec.PublicKey
395+
for i, hop := range testCase.Decrypt.Hops {
396+
buff := bytes.NewBuffer(nil)
397+
require.NoError(t, onionPacket.Encode(buff))
398+
399+
// hop.OnionMessage contains the onion_message hex string. This
400+
// contains the type 513 (two bytes), the path_key (33 bytes)
401+
// and the length of the onion_message_packet (two bytes). We
402+
// are only interested in the onion_message_packet so we only
403+
// check that part.
404+
const onionMessageHexHeaderLen = 74
405+
406+
require.Equal(
407+
t, hop.OnionMessage[onionMessageHexHeaderLen:],
408+
hex.EncodeToString(buff.Bytes()),
409+
)
410+
411+
priv := privKeyFromString(hop.PrivKey)
412+
413+
switch i {
414+
case 0:
415+
// Onion message routes are always entirely blinded, so
416+
// the first hop will always use the first blinding
417+
// point.
418+
blindingPoint = firstBlinding
419+
case concatIndex:
420+
blindingPoint = blindingOverride
421+
}
422+
423+
processedPkt := peelOnion(priv, blindingPoint)
424+
425+
blindingPoint, err = NextEphemeral(
426+
&PrivKeyECDH{priv}, blindingPoint,
427+
)
428+
require.NoError(t, err)
429+
430+
onionPacket = processedPkt.NextPacket
431+
}
432+
}
433+
334434
type onionBlindingJsonTestCase struct {
335435
Generate generateOnionData `json:"generate"`
336436
Decrypt decryptData `json:"decrypt"`
@@ -369,10 +469,10 @@ type blindingJsonTestCase struct {
369469
}
370470

371471
type onionMessageJsonTestCase struct {
372-
Generate generateOnionMessageData `json:"generate"`
373-
Route routeOnionMessageData `json:"route"`
374-
// OnionMessage onionMessageData `json:"onionmessage"`
375-
Decrypt decryptOnionMessageData `json:"decrypt"`
472+
Generate generateOnionMessageData `json:"generate"`
473+
Route routeOnionMessageData `json:"route"`
474+
OnionMessage onionMessageData `json:"onionmessage"`
475+
Decrypt decryptOnionMessageData `json:"decrypt"`
376476
}
377477

378478
type routeData struct {
@@ -387,6 +487,10 @@ type routeOnionMessageData struct {
387487
Hops []blindedOnionMessageHop `json:"hops"`
388488
}
389489

490+
type onionMessageData struct {
491+
OnionMessagePacket string `json:"onion_message_packet"`
492+
}
493+
390494
type unblindData struct {
391495
Hops []unblindedHop `json:"hops"`
392496
}

0 commit comments

Comments
 (0)