@@ -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,89 @@ func TestBolt4Packet(t *testing.T) {
162163 }
163164}
164165
166+ func TestTLVPayloadMessagePacket (t * testing.T ) {
167+ t .Parallel ()
168+
169+ // First, we'll read out the raw JSON file at the target location.
170+ jsonBytes , err := os .ReadFile (testOnionMessageFileName )
171+ require .NoError (t , err )
172+
173+ // Once we have the raw file, we'll unpack it into our jsonTestCase
174+ // struct defined above.
175+ testCase := & onionMessageJsonTestCase {}
176+ require .NoError (t , json .Unmarshal (jsonBytes , testCase ))
177+
178+ // Next, we'll populate a new OnionHop using the information included
179+ // in this test case.
180+ var route PaymentPath
181+ for i , hop := range testCase .Route .Hops {
182+ pubKeyBytes , err := hex .DecodeString (hop .BlindedNodeID )
183+ require .NoError (t , err )
184+
185+ pubKey , err := btcec .ParsePubKey (pubKeyBytes )
186+ require .NoError (t , err )
187+
188+ EncryptedRecipientData , err := hex .DecodeString (
189+ hop .EncryptedRecipientData ,
190+ )
191+ require .NoError (t , err )
192+
193+ // Manually encode our onion payload
194+ records := []tlv.Record {}
195+
196+ if i == len (testCase .Route .Hops )- 1 {
197+ helloBytes := []byte ("hello" )
198+ records = append (records , tlv .MakePrimitiveRecord (
199+ 1 , & helloBytes ,
200+ ))
201+ }
202+
203+ records = append (records , tlv .MakePrimitiveRecord (
204+ 4 , & EncryptedRecipientData ,
205+ ))
206+
207+ stream , err := tlv .NewStream (records ... )
208+ require .NoError (t , err , "new stream" )
209+
210+ b := new (bytes.Buffer )
211+ require .NoError (t , stream .Encode (b ), "encode" )
212+
213+ route [i ] = OnionHop {
214+ NodePub : * pubKey ,
215+ HopPayload : HopPayload {
216+ Type : PayloadTLV ,
217+ Payload : b .Bytes (),
218+ },
219+ }
220+ }
221+
222+ finalPacket , err := hex .DecodeString (
223+ testCase .OnionMessage .OnionMessagePacket ,
224+ )
225+ require .NoError (t , err )
226+
227+ sessionKeyBytes , err := hex .DecodeString (testCase .Generate .SessionKey )
228+
229+ require .NoError (t , err )
230+
231+ // With all the required data assembled, we'll craft a new packet.
232+ sessionKey , _ := btcec .PrivKeyFromBytes (sessionKeyBytes )
233+
234+ pkt , err := NewOnionPacket (
235+ & route , sessionKey , nil , DeterministicPacketFiller ,
236+ )
237+ require .NoError (t , err )
238+
239+ var b bytes.Buffer
240+ require .NoError (t , pkt .Encode (& b ))
241+
242+ // Finally, we expect that our packet matches the packet included in
243+ // the spec's test vectors.
244+ require .Equalf (t , b .Bytes (), finalPacket , "final packet does not " +
245+ "match expected BOLT 4 packet, want: %s, got %s" ,
246+ hex .EncodeToString (finalPacket ), hex .EncodeToString (b .Bytes ()))
247+ }
248+
165249func TestSphinxCorrectness (t * testing.T ) {
166250 nodes , _ , hopDatas , fwdMsg , err := newTestRoute (testLegacyRouteNumHops )
167251 if err != nil {
@@ -755,6 +839,9 @@ const (
755839
756840 // testTLVFileName is the name of the tlv-payload-only onion test file.
757841 testTLVFileName = "testdata/onion-test.json"
842+
843+ // testOnionMessageFileName is the name of the onion message test file.
844+ testOnionMessageFileName = "testdata/blinded-onion-message-onion-test.json"
758845)
759846
760847type jsonHop struct {
0 commit comments