Skip to content

Commit c523559

Browse files
committed
sphinx_test: onion message packet creation
TestTLVPayloadMessagePacket creates a onion message with payload and the blinded route from the test vector. It then checks if the onion packet we create is equal to the one provided in the test vector.
1 parent bc7542a commit c523559

File tree

1 file changed

+95
-0
lines changed

1 file changed

+95
-0
lines changed

sphinx_test.go

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import (
1212

1313
"github.com/btcsuite/btcd/btcec/v2"
1414
"github.com/davecgh/go-spew/spew"
15+
"github.com/lightningnetwork/lnd/tlv"
1516
"github.com/stretchr/testify/require"
1617
)
1718

@@ -162,6 +163,97 @@ func TestBolt4Packet(t *testing.T) {
162163
}
163164
}
164165

166+
// TestTLVPayloadMessagePacket tests the creation and encoding of an onion
167+
// message packet that uses a TLV payload for each hop in the route. This test
168+
// uses the test vectors defined in the BOLT 4 specification. The test reads a
169+
// JSON file containing a predefined route, session key, and the expected final
170+
// onion packet. It then constructs the route hop-by-hop, manually creating the
171+
// TLV payload for each, before creating a new onion packet with NewOnionPacket.
172+
// The test concludes by asserting that the newly encoded packet is identical to
173+
// the one specified in the test vector.
174+
func TestTLVPayloadMessagePacket(t *testing.T) {
175+
t.Parallel()
176+
177+
// First, we'll read out the raw JSON file at the target location.
178+
jsonBytes, err := os.ReadFile(testOnionMessageFileName)
179+
require.NoError(t, err)
180+
181+
// Once we have the raw file, we'll unpack it into our jsonTestCase
182+
// struct defined above.
183+
testCase := &onionMessageJsonTestCase{}
184+
require.NoError(t, json.Unmarshal(jsonBytes, testCase))
185+
186+
// Next, we'll populate a new OnionHop using the information included
187+
// in this test case.
188+
var route PaymentPath
189+
for i, hop := range testCase.Route.Hops {
190+
pubKeyBytes, err := hex.DecodeString(hop.BlindedNodeID)
191+
require.NoError(t, err)
192+
193+
pubKey, err := btcec.ParsePubKey(pubKeyBytes)
194+
require.NoError(t, err)
195+
196+
encryptedRecipientData, err := hex.DecodeString(
197+
hop.EncryptedRecipientData,
198+
)
199+
require.NoError(t, err)
200+
201+
// Manually encode our onion payload
202+
records := []tlv.Record{}
203+
204+
if i == len(testCase.Route.Hops)-1 {
205+
helloBytes := []byte("hello")
206+
records = append(records, tlv.MakePrimitiveRecord(
207+
1, &helloBytes,
208+
))
209+
}
210+
211+
records = append(records, tlv.MakePrimitiveRecord(
212+
4, &encryptedRecipientData,
213+
))
214+
215+
stream, err := tlv.NewStream(records...)
216+
require.NoError(t, err, "new stream")
217+
218+
b := new(bytes.Buffer)
219+
require.NoError(t, stream.Encode(b), "encode")
220+
221+
route[i] = OnionHop{
222+
NodePub: *pubKey,
223+
HopPayload: HopPayload{
224+
Type: PayloadTLV,
225+
Payload: b.Bytes(),
226+
},
227+
}
228+
}
229+
230+
finalPacket, err := hex.DecodeString(
231+
testCase.OnionMessage.OnionMessagePacket,
232+
)
233+
require.NoError(t, err)
234+
235+
sessionKeyBytes, err := hex.DecodeString(testCase.Generate.SessionKey)
236+
237+
require.NoError(t, err)
238+
239+
// With all the required data assembled, we'll craft a new packet.
240+
sessionKey, _ := btcec.PrivKeyFromBytes(sessionKeyBytes)
241+
242+
pkt, err := NewOnionPacket(
243+
&route, sessionKey, nil, DeterministicPacketFiller,
244+
)
245+
require.NoError(t, err)
246+
247+
var b bytes.Buffer
248+
require.NoError(t, pkt.Encode(&b))
249+
250+
// Finally, we expect that our packet matches the packet included in
251+
// the spec's test vectors.
252+
require.Equalf(t, finalPacket, b.Bytes(), "final packet does not "+
253+
"match expected BOLT 4 packet, want: %s, got %s",
254+
hex.EncodeToString(finalPacket), hex.EncodeToString(b.Bytes()))
255+
}
256+
165257
func TestSphinxCorrectness(t *testing.T) {
166258
nodes, _, hopDatas, fwdMsg, err := newTestRoute(testLegacyRouteNumHops)
167259
if err != nil {
@@ -755,6 +847,9 @@ const (
755847

756848
// testTLVFileName is the name of the tlv-payload-only onion test file.
757849
testTLVFileName = "testdata/onion-test.json"
850+
851+
// testOnionMessageFileName is the name of the onion message test file.
852+
testOnionMessageFileName = "testdata/blinded-onion-message-onion-test.json"
758853
)
759854

760855
type jsonHop struct {

0 commit comments

Comments
 (0)