@@ -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+
334434type onionBlindingJsonTestCase struct {
335435 Generate generateOnionData `json:"generate"`
336436 Decrypt decryptData `json:"decrypt"`
@@ -369,10 +469,10 @@ type blindingJsonTestCase struct {
369469}
370470
371471type 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
378478type 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+
390494type unblindData struct {
391495 Hops []unblindedHop `json:"hops"`
392496}
0 commit comments