@@ -17,6 +17,14 @@ const (
1717 blindedOnionMessageOnionTestFileName = "testdata/blinded-onion-message-onion-test.json"
1818)
1919
20+ var (
21+ // bolt4PubKeys contains the public keys used in the Bolt 4 spec test
22+ // vectors. We convert them variables named after the commonly used
23+ // names in cryptography.
24+ alicePubKey = bolt4PubKeys [0 ]
25+ bobPubKey = bolt4PubKeys [1 ]
26+ )
27+
2028// TestBuildBlindedRoute tests BuildBlindedRoute and decryptBlindedHopData against
2129// the spec test vectors.
2230func TestBuildBlindedRoute (t * testing.T ) {
@@ -118,8 +126,35 @@ func TestBuildBlindedRoute(t *testing.T) {
118126 }
119127}
120128
121- // TestBuildOnionMessageBlindedRoute tests BuildBlindedRoute,
122- // decryptBlindedHopData and NextEphemeral against the spec test vectors.
129+ // TestBuildOnionMessageBlindedRoute tests the construction of a blinded route
130+ // for an onion message, specifically the concatenation of two blinded paths,
131+ // against the spec test vectors in `blinded-onion-message-onion-test.json`. It
132+ // verifies the correctness of BuildBlindedPath, decryptBlindedHopData, and
133+ // NextEphemeral.
134+ //
135+ // The test setup involves several parties and two distinct blinded paths that
136+ // are combined to form the full route:
137+ //
138+ // 1. Path from Dave: Dave (the receiver) first constructs a blinded path for a
139+ // message to be sent from Bob to himself (Dave).
140+ // The path is: Bob -> Carol -> Dave
141+ //
142+ // 2. Path from Sender: Dave gives his blinded path to a Sender. The Sender
143+ // then creates their own blinded path from themselves to Bob, passing
144+ // through Alice. The path is: Sender -> Alice -> Bob
145+ //
146+ // 3. Path Concatenation: The Sender prepends their path to Dave's path,
147+ // creating a final, concatenated route:
148+ // Sender -> Alice -> Bob -> Carol -> Dave
149+ // To link the two paths, the Sender includes a `next_path_key_override`
150+ // in the payload for Alice. This override is set to the first path key
151+ // (blinding point) of Dave's path, instructing Alice to use it for the next
152+ // hop (Bob) instead of the key that she could derive herself.
153+ //
154+ // The test then asserts that the generated concatenated path matches the test
155+ // vector's expected route. Finally, it simulates the decryption process at each
156+ // hop, verifying that each node can correctly decrypt its payload and derive
157+ // the correct next ephemeral key.
123158func TestBuildOnionMessageBlindedRoute (t * testing.T ) {
124159 t .Parallel ()
125160
@@ -128,43 +163,50 @@ func TestBuildOnionMessageBlindedRoute(t *testing.T) {
128163 require .NoError (t , err )
129164
130165 // Once we have the raw file, we'll unpack it into our
131- // blindingJsonTestCase struct defined below.
166+ // onionMessageJsonTestCase struct defined below.
132167 testCase := & onionMessageJsonTestCase {}
133168 require .NoError (t , json .Unmarshal (jsonBytes , testCase ))
134169 require .Len (t , testCase .Generate .Hops , 4 )
135170
136171 // buildMessagePath is a helper closure used to convert
137172 // hopOnionMessageData objects into HopInfo objects.
138- buildMessagePath := func (h []hopOnionMessageData , e string ) []* HopInfo {
173+ buildMessagePath := func (h []hopOnionMessageData ,
174+ initialHopID string ) []* HopInfo {
175+
139176 path := make ([]* HopInfo , len (h ))
140- currentHop := e
177+ // The json test vector doesn't properly specify the current
178+ // node id, so we need the initial Node ID as a starting point.
179+ currentHop := initialHopID
141180 for i , hop := range h {
142- // The json test vector only specifies the current node
143- // ID as the next node id in the payload of the previous
144- // node, so we get that from the previous hop.
145- nodeIDStr , _ := hex .DecodeString (
146- currentHop ,
147- )
148- nodeID , _ := btcec .ParsePubKey (nodeIDStr )
149- payload , _ := hex .DecodeString (hop .EncryptedDataTlv )
181+ nodeIDStr , err := hex .DecodeString (currentHop )
182+ require .NoError (t , err )
183+ nodeID , err := btcec .ParsePubKey (nodeIDStr )
184+ require .NoError (t , err )
185+ payload , err := hex .DecodeString (hop .EncryptedDataTlv )
186+ require .NoError (t , err )
150187
151188 path [i ] = & HopInfo {
152189 NodePub : nodeID ,
153190 PlainText : payload ,
154191 }
192+
193+ // The json test vector doesn't properly specify the
194+ // current node id. It does specify the next node id. So
195+ // to get the current node id for the next iteration, we
196+ // get the next node id here.
155197 currentHop = hop .EncodedOnionMessageTLVs .NextNodeID
156198 }
157199 return path
158200 }
159201
160202 // First, Dave will build a blinded path from Bob to itself.
161- DaveSessKey := privKeyFromString (
203+ daveSessKey := privKeyFromString (
162204 testCase .Generate .Hops [1 ].PathKeySecret ,
163205 )
164206 daveBobPath := buildMessagePath (
165- testCase .Generate .Hops [1 :], bolt4PubKeys [ 1 ] ,
207+ testCase .Generate .Hops [1 :], bobPubKey ,
166208 )
167- pathDB , err := BuildBlindedPath (DaveSessKey , daveBobPath )
209+ daveBobBlindedPath , err := BuildBlindedPath (daveSessKey , daveBobPath )
168210 require .NoError (t , err )
169211
170212 // At this point, Dave will give his blinded path to the Sender who will
@@ -174,21 +216,27 @@ func TestBuildOnionMessageBlindedRoute(t *testing.T) {
174216 // to the first path key in Dave's blinded route. This will indicate to
175217 // Alice that she should use this point for the next path key instead of
176218 // the next path key that she derives.
219+ // Path created by Dave: Bob -> Carol -> Dave
220+ // Path that the Sender will build: Sender -> Alice -> Bob
177221 aliceBobPath := buildMessagePath (
178- testCase .Generate .Hops [:1 ], bolt4PubKeys [ 0 ] ,
222+ testCase .Generate .Hops [:1 ], alicePubKey ,
179223 )
180224 senderSessKey := privKeyFromString (
181225 testCase .Generate .Hops [0 ].PathKeySecret ,
182226 )
183- pathAB , err := BuildBlindedPath (senderSessKey , aliceBobPath )
227+ aliceBobBlindedPath , err := BuildBlindedPath (
228+ senderSessKey , aliceBobPath ,
229+ )
184230 require .NoError (t , err )
185231
186232 // Construct the concatenated path.
187233 path := & BlindedPath {
188- IntroductionPoint : pathAB .Path .IntroductionPoint ,
189- BlindingPoint : pathAB .Path .BlindingPoint ,
190- BlindedHops : append (pathAB .Path .BlindedHops ,
191- pathDB .Path .BlindedHops ... ),
234+ IntroductionPoint : aliceBobBlindedPath .Path .IntroductionPoint ,
235+ BlindingPoint : aliceBobBlindedPath .Path .BlindingPoint ,
236+ BlindedHops : append (
237+ aliceBobBlindedPath .Path .BlindedHops ,
238+ daveBobBlindedPath .Path .BlindedHops ... ,
239+ ),
192240 }
193241
194242 // Check that the constructed path is equal to the test vector path.
@@ -205,19 +253,15 @@ func TestBuildOnionMessageBlindedRoute(t *testing.T) {
205253 ))
206254
207255 data , _ := hex .DecodeString (hop .EncryptedRecipientData )
208- require .True (
209- t , bytes .Equal (data , path .BlindedHops [i ].CipherText ),
210- )
256+ require .Equal (t , data , path .BlindedHops [i ].CipherText )
211257 }
212258
213259 // Assert that each hop is able to decode the encrypted data meant for
214260 // it.
215261 for i , hop := range testCase .Decrypt .Hops {
216262 genData := testCase .Generate .Hops [i ]
217263 priv := privKeyFromString (hop .PrivKey )
218- ephem := pubKeyFromString (
219- genData .EphemeralPubKey ,
220- )
264+ ephem := pubKeyFromString (genData .EphemeralPubKey )
221265
222266 // Now we'll decrypt the blinded hop data using the private key
223267 // and the ephemeral public key.
@@ -227,9 +271,9 @@ func TestBuildOnionMessageBlindedRoute(t *testing.T) {
227271 )
228272 require .NoError (t , err )
229273
230- // check if the decrypted data is what we expect it to be.
231- decoded , _ := hex .DecodeString (genData .EncryptedDataTlv )
232- require .True (t , bytes . Equal ( data , decoded ) )
274+ // Check if the decrypted data is what we expect it to be.
275+ dataExpected , _ := hex .DecodeString (genData .EncryptedDataTlv )
276+ require .Equal (t , data , dataExpected )
233277
234278 nextEphem , err := NextEphemeral (& PrivKeyECDH {priv }, ephem )
235279 require .NoError (t , err )
0 commit comments