Skip to content

Commit 4a64e47

Browse files
committed
sphinx: update NewOnionPacket to use the new PaymentPath type
In this commit, we update the NewOnionPacket function to use the new PaymentPath type. We also update all the tests as they need to reference this new type themselves.
1 parent 7b63003 commit 4a64e47

File tree

3 files changed

+93
-70
lines changed

3 files changed

+93
-70
lines changed

bench_test.go

Lines changed: 20 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -14,37 +14,40 @@ var (
1414

1515
func BenchmarkPathPacketConstruction(b *testing.B) {
1616
b.StopTimer()
17-
route := make([]*btcec.PublicKey, NumMaxHops)
18-
for i := 0; i < NumMaxHops; i++ {
19-
privKey, err := btcec.NewPrivateKey(btcec.S256())
20-
if err != nil {
21-
b.Fatalf("unable to generate key: %v", privKey)
22-
}
23-
24-
route[i] = privKey.PubKey()
25-
}
2617

2718
var (
2819
err error
2920
sphinxPacket *OnionPacket
21+
route PaymentPath
3022
)
3123

32-
var hopsData []HopData
33-
for i := 0; i < len(route); i++ {
34-
hopsData = append(hopsData, HopData{
35-
Realm: [RealmByteSize]byte{0x00},
24+
for i := 0; i < NumMaxHops; i++ {
25+
privKey, err := btcec.NewPrivateKey(btcec.S256())
26+
if err != nil {
27+
b.Fatalf("unable to generate key: %v", privKey)
28+
}
29+
30+
hopData := HopData{
31+
Realm: [1]byte{0x00},
3632
ForwardAmount: uint64(i),
3733
OutgoingCltv: uint32(i),
38-
})
39-
copy(hopsData[i].NextAddress[:], bytes.Repeat([]byte{byte(i)}, 8))
34+
}
35+
copy(hopData.NextAddress[:], bytes.Repeat([]byte{byte(i)}, 8))
36+
37+
route[i] = OnionHop{
38+
NodePub: *privKey.PubKey(),
39+
HopData: hopData,
40+
}
4041
}
4142

4243
d, _ := btcec.PrivKeyFromBytes(btcec.S256(), bytes.Repeat([]byte{'A'}, 32))
44+
4345
b.ReportAllocs()
46+
4447
b.StartTimer()
4548

4649
for i := 0; i < b.N; i++ {
47-
sphinxPacket, err = NewOnionPacket(route, d, hopsData, nil)
50+
sphinxPacket, err = NewOnionPacket(&route, d, nil)
4851
if err != nil {
4952
b.Fatalf("unable to create packet: %v", err)
5053
}
@@ -55,7 +58,7 @@ func BenchmarkPathPacketConstruction(b *testing.B) {
5558

5659
func BenchmarkProcessPacket(b *testing.B) {
5760
b.StopTimer()
58-
path, _, sphinxPacket, err := newTestRoute(1)
61+
path, _, _, sphinxPacket, err := newTestRoute(1)
5962
if err != nil {
6063
b.Fatalf("unable to create test route: %v", err)
6164
}

sphinx.go

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -289,14 +289,16 @@ func generateSharedSecrets(paymentPath []*btcec.PublicKey,
289289
return hopSharedSecrets
290290
}
291291

292-
// NewOnionPacket creates a new onion packet which is capable of
293-
// obliviously routing a message through the mix-net path outline by
294-
// 'paymentPath'.
295-
func NewOnionPacket(paymentPath []*btcec.PublicKey, sessionKey *btcec.PrivateKey,
296-
hopsData []HopData, assocData []byte) (*OnionPacket, error) {
292+
// NewOnionPacket creates a new onion packet which is capable of obliviously
293+
// routing a message through the mix-net path outline by 'paymentPath'.
294+
func NewOnionPacket(paymentPath *PaymentPath, sessionKey *btcec.PrivateKey,
295+
assocData []byte) (*OnionPacket, error) {
297296

298-
numHops := len(paymentPath)
299-
hopSharedSecrets := generateSharedSecrets(paymentPath, sessionKey)
297+
numHops := paymentPath.TrueRouteLength()
298+
299+
hopSharedSecrets := generateSharedSecrets(
300+
paymentPath.NodeKeys(), sessionKey,
301+
)
300302

301303
// Generate the padding, called "filler strings" in the paper.
302304
filler := generateHeaderPadding(
@@ -323,7 +325,7 @@ func NewOnionPacket(paymentPath []*btcec.PublicKey, sessionKey *btcec.PrivateKey
323325
// The HMAC for the final hop is simply zeroes. This allows the
324326
// last hop to recognize that it is the destination for a
325327
// particular payment.
326-
hopsData[i].HMAC = nextHmac
328+
paymentPath[i].HopData.HMAC = nextHmac
327329

328330
// Next, using the key dedicated for our stream cipher, we'll
329331
// generate enough bytes to obfuscate this layer of the onion
@@ -338,7 +340,8 @@ func NewOnionPacket(paymentPath []*btcec.PublicKey, sessionKey *btcec.PrivateKey
338340
// With the mix header right-shifted, we'll encode the current
339341
// hop data into a buffer we'll re-use during the packet
340342
// construction.
341-
if err := hopsData[i].Encode(&hopDataBuf); err != nil {
343+
err := paymentPath[i].HopData.Encode(&hopDataBuf)
344+
if err != nil {
342345
return nil, err
343346
}
344347
copy(mixHeader[:], hopDataBuf.Bytes())

sphinx_test.go

Lines changed: 61 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -86,63 +86,91 @@ var (
8686
"baaa7d63ad64199f4664813b955cff954949076dcf"
8787
)
8888

89-
func newTestRoute(numHops int) ([]*Router, *[]HopData, *OnionPacket, error) {
89+
func newTestRoute(numHops int) ([]*Router, *PaymentPath, *[]HopData, *OnionPacket, error) {
9090
nodes := make([]*Router, numHops)
9191

9292
// Create numHops random sphinx nodes.
9393
for i := 0; i < len(nodes); i++ {
9494
privKey, err := btcec.NewPrivateKey(btcec.S256())
9595
if err != nil {
96-
return nil, nil, nil, fmt.Errorf("Unable to generate"+
97-
" random key for sphinx node: %v", err)
96+
return nil, nil, nil, nil, fmt.Errorf("Unable to "+
97+
"generate random key for sphinx node: %v", err)
9898
}
9999

100-
nodes[i] = NewRouter(privKey, &chaincfg.MainNetParams,
101-
NewMemoryReplayLog())
100+
nodes[i] = NewRouter(
101+
privKey, &chaincfg.MainNetParams, NewMemoryReplayLog(),
102+
)
102103
}
103104

104105
// Gather all the pub keys in the path.
105-
route := make([]*btcec.PublicKey, len(nodes))
106+
var (
107+
route PaymentPath
108+
)
106109
for i := 0; i < len(nodes); i++ {
107-
route[i] = nodes[i].onionKey.PubKey()
108-
}
109-
110-
var hopsData []HopData
111-
for i := 0; i < numHops; i++ {
112-
hopsData = append(hopsData, HopData{
113-
Realm: 0x00,
110+
hopData := HopData{
111+
Realm: [1]byte{0x00},
114112
ForwardAmount: uint64(i),
115113
OutgoingCltv: uint32(i),
116-
})
117-
copy(hopsData[i].NextAddress[:], bytes.Repeat([]byte{byte(i)}, 8))
118-
copy(hopsData[i].ExtraBytes[:], bytes.Repeat([]byte{byte(i)}, padSize))
114+
}
115+
116+
copy(hopData.NextAddress[:], bytes.Repeat([]byte{byte(i)}, 8))
117+
118+
route[i] = OnionHop{
119+
NodePub: *nodes[i].onionKey.PubKey(),
120+
HopData: hopData,
121+
}
119122
}
120123

121124
// Generate a forwarding message to route to the final node via the
122125
// generated intermdiates nodes above. Destination should be Hash160,
123126
// adding padding so parsing still works.
124-
sessionKey, _ := btcec.PrivKeyFromBytes(btcec.S256(), bytes.Repeat([]byte{'A'}, 32))
125-
fwdMsg, err := NewOnionPacket(route, sessionKey, hopsData, nil)
127+
sessionKey, _ := btcec.PrivKeyFromBytes(
128+
btcec.S256(), bytes.Repeat([]byte{'A'}, 32),
129+
)
130+
fwdMsg, err := NewOnionPacket(&route, sessionKey, nil)
126131
if err != nil {
127-
return nil, nil, nil, fmt.Errorf("Unable to create forwarding "+
128-
"message: %#v", err)
132+
return nil, nil, nil, nil, fmt.Errorf("unable to create "+
133+
"forwarding message: %#v", err)
134+
}
135+
136+
var hopsData []HopData
137+
for i := 0; i < len(nodes); i++ {
138+
hopsData = append(hopsData, route[i].HopData)
129139
}
130140

131-
return nodes, &hopsData, fwdMsg, nil
141+
return nodes, &route, &hopsData, fwdMsg, nil
132142
}
133143

134144
func TestBolt4Packet(t *testing.T) {
135-
var route = make([]*btcec.PublicKey, len(bolt4PubKeys))
145+
var (
146+
route PaymentPath
147+
hopsData []HopData
148+
)
136149
for i, pubKeyHex := range bolt4PubKeys {
137150
pubKeyBytes, err := hex.DecodeString(pubKeyHex)
138151
if err != nil {
139152
t.Fatalf("unable to decode BOLT 4 hex pubkey #%d: %v", i, err)
140153
}
141154

142-
route[i], err = btcec.ParsePubKey(pubKeyBytes, btcec.S256())
155+
pubKey, err := btcec.ParsePubKey(pubKeyBytes, btcec.S256())
143156
if err != nil {
144157
t.Fatalf("unable to parse BOLT 4 pubkey #%d: %v", i, err)
145158
}
159+
160+
hopData := HopData{
161+
Realm: [1]byte{0x00},
162+
ForwardAmount: uint64(i),
163+
OutgoingCltv: uint32(i),
164+
}
165+
copy(hopData.NextAddress[:], bytes.Repeat([]byte{byte(i)}, 8))
166+
hopsData = append(hopsData, hopData)
167+
168+
pubKey.Curve = nil
169+
170+
route[i] = OnionHop{
171+
NodePub: *pubKey,
172+
HopData: hopData,
173+
}
146174
}
147175

148176
finalPacket, err := hex.DecodeString(bolt4FinalPacketHex)
@@ -151,18 +179,8 @@ func TestBolt4Packet(t *testing.T) {
151179
"%v", err)
152180
}
153181

154-
var hopsData []HopData
155-
for i := range route {
156-
hopsData = append(hopsData, HopData{
157-
Realm: 0x00,
158-
ForwardAmount: uint64(i),
159-
OutgoingCltv: uint32(i),
160-
})
161-
copy(hopsData[i].NextAddress[:], bytes.Repeat([]byte{byte(i)}, 8))
162-
}
163-
164182
sessionKey, _ := btcec.PrivKeyFromBytes(btcec.S256(), bolt4SessionKey)
165-
pkt, err := NewOnionPacket(route, sessionKey, hopsData, bolt4AssocData)
183+
pkt, err := NewOnionPacket(&route, sessionKey, bolt4AssocData)
166184
if err != nil {
167185
t.Fatalf("unable to construct onion packet: %v", err)
168186
}
@@ -180,7 +198,7 @@ func TestBolt4Packet(t *testing.T) {
180198
}
181199

182200
func TestSphinxCorrectness(t *testing.T) {
183-
nodes, hopDatas, fwdMsg, err := newTestRoute(NumMaxHops)
201+
nodes, _, hopDatas, fwdMsg, err := newTestRoute(NumMaxHops)
184202
if err != nil {
185203
t.Fatalf("unable to create random onion packet: %v", err)
186204
}
@@ -229,7 +247,7 @@ func TestSphinxCorrectness(t *testing.T) {
229247

230248
// The next hop should have been parsed as node[i+1].
231249
parsedNextHop := onionPacket.ForwardingInstructions.NextAddress[:]
232-
expected := bytes.Repeat([]byte{byte(i)}, addressSize)
250+
expected := bytes.Repeat([]byte{byte(i)}, AddressSize)
233251
if !bytes.Equal(parsedNextHop, expected) {
234252
t.Fatalf("Processing error, next hop parsed incorrectly."+
235253
" next hop should be %v, was instead parsed as %v",
@@ -246,8 +264,7 @@ func TestSphinxSingleHop(t *testing.T) {
246264
// We'd like to test the proper behavior of the correctness of onion
247265
// packet processing for "single-hop" payments which bare a full onion
248266
// packet.
249-
250-
nodes, _, fwdMsg, err := newTestRoute(1)
267+
nodes, _, _, fwdMsg, err := newTestRoute(1)
251268
if err != nil {
252269
t.Fatalf("unable to create test route: %v", err)
253270
}
@@ -274,7 +291,7 @@ func TestSphinxSingleHop(t *testing.T) {
274291
func TestSphinxNodeRelpay(t *testing.T) {
275292
// We'd like to ensure that the sphinx node itself rejects all replayed
276293
// packets which share the same shared secret.
277-
nodes, _, fwdMsg, err := newTestRoute(NumMaxHops)
294+
nodes, _, _, fwdMsg, err := newTestRoute(NumMaxHops)
278295
if err != nil {
279296
t.Fatalf("unable to create test route: %v", err)
280297
}
@@ -299,7 +316,7 @@ func TestSphinxNodeRelpay(t *testing.T) {
299316
func TestSphinxNodeRelpaySameBatch(t *testing.T) {
300317
// We'd like to ensure that the sphinx node itself rejects all replayed
301318
// packets which share the same shared secret.
302-
nodes, _, fwdMsg, err := newTestRoute(NumMaxHops)
319+
nodes, _, _, fwdMsg, err := newTestRoute(NumMaxHops)
303320
if err != nil {
304321
t.Fatalf("unable to create test route: %v", err)
305322
}
@@ -345,7 +362,7 @@ func TestSphinxNodeRelpaySameBatch(t *testing.T) {
345362
func TestSphinxNodeRelpayLaterBatch(t *testing.T) {
346363
// We'd like to ensure that the sphinx node itself rejects all replayed
347364
// packets which share the same shared secret.
348-
nodes, _, fwdMsg, err := newTestRoute(NumMaxHops)
365+
nodes, _, _, fwdMsg, err := newTestRoute(NumMaxHops)
349366
if err != nil {
350367
t.Fatalf("unable to create test route: %v", err)
351368
}
@@ -390,7 +407,7 @@ func TestSphinxNodeRelpayLaterBatch(t *testing.T) {
390407
func TestSphinxNodeReplayBatchIdempotency(t *testing.T) {
391408
// We'd like to ensure that the sphinx node itself rejects all replayed
392409
// packets which share the same shared secret.
393-
nodes, _, fwdMsg, err := newTestRoute(NumMaxHops)
410+
nodes, _, _, fwdMsg, err := newTestRoute(NumMaxHops)
394411
if err != nil {
395412
t.Fatalf("unable to create test route: %v", err)
396413
}
@@ -441,7 +458,7 @@ func TestSphinxNodeReplayBatchIdempotency(t *testing.T) {
441458
func TestSphinxAssocData(t *testing.T) {
442459
// We want to make sure that the associated data is considered in the
443460
// HMAC creation
444-
nodes, _, fwdMsg, err := newTestRoute(5)
461+
nodes, _, _, fwdMsg, err := newTestRoute(5)
445462
if err != nil {
446463
t.Fatalf("unable to create random onion packet: %v", err)
447464
}
@@ -460,7 +477,7 @@ func TestSphinxAssocData(t *testing.T) {
460477
func TestSphinxEncodeDecode(t *testing.T) {
461478
// Create some test data with a randomly populated, yet valid onion
462479
// forwarding message.
463-
_, _, fwdMsg, err := newTestRoute(5)
480+
_, _, _, fwdMsg, err := newTestRoute(5)
464481
if err != nil {
465482
t.Fatalf("unable to create random onion packet: %v", err)
466483
}

0 commit comments

Comments
 (0)