Skip to content

Commit e3f2244

Browse files
committed
multi: return the last ephemeral pub key for a blinded path
Update BuildBlindedPath to also return the very last ephemeral public key of the route. This can be used by the recipient (ie, the path builder) to identify an incoming payment.
1 parent 165eddb commit e3f2244

File tree

5 files changed

+39
-14
lines changed

5 files changed

+39
-14
lines changed

crypto.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -332,7 +332,7 @@ func (o *OnionErrorDecrypter) DecryptError(encryptedData []byte) (
332332
len(encryptedData))
333333
}
334334

335-
sharedSecrets, err := generateSharedSecrets(
335+
sharedSecrets, _, err := generateSharedSecrets(
336336
o.circuit.PaymentPath,
337337
o.circuit.SessionKey,
338338
)

obfuscation_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ func TestOnionFailure(t *testing.T) {
2929
errorPath := paymentPath[:len(paymentPath)-1]
3030

3131
failureData := bytes.Repeat([]byte{'A'}, minOnionErrorLength-sha256.Size)
32-
sharedSecrets, err := generateSharedSecrets(paymentPath, sessionKey)
32+
sharedSecrets, _, err := generateSharedSecrets(paymentPath, sessionKey)
3333
if err != nil {
3434
t.Fatalf("Unexpected error while generating secrets: %v", err)
3535
}
@@ -196,7 +196,7 @@ func TestOnionFailureSpecVector(t *testing.T) {
196196
}
197197

198198
var obfuscatedData []byte
199-
sharedSecrets, err := generateSharedSecrets(paymentPath, sessionKey)
199+
sharedSecrets, _, err := generateSharedSecrets(paymentPath, sessionKey)
200200
if err != nil {
201201
t.Fatalf("Unexpected error while generating secrets: %v", err)
202202
}

path.go

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -163,11 +163,30 @@ func (i *HopInfo) Encrypt(sharedSecret Hash256) (*BlindedHopInfo, error) {
163163
}, nil
164164
}
165165

166+
// BlindedPathInfo holds a BlindedPath and any other items that a path
167+
// constructor may find useful.
168+
type BlindedPathInfo struct {
169+
// Path holds the constructed BlindedPath which holds all info about a
170+
// blinded path that must be communicated to a potential path user.
171+
Path *BlindedPath
172+
173+
// SessionKey holds the private key that was used as the session key
174+
// of the path. This is the private key for the first ephemeral blinding
175+
// key of the path.
176+
SessionKey *btcec.PrivateKey
177+
178+
// LastEphemeralKey is the very last ephemeral blinding key used on the
179+
// path. This may be useful to the path creator as they can use this
180+
// key to uniquely identify the path that was used for an incoming
181+
// payment.
182+
LastEphemeralKey *btcec.PublicKey
183+
}
184+
166185
// BuildBlindedPath creates a new BlindedPath from a session key along with a
167186
// list of HopInfo representing the nodes in the blinded path. The first hop in
168187
// paymentPath is expected to be the introduction node.
169188
func BuildBlindedPath(sessionKey *btcec.PrivateKey,
170-
paymentPath []*HopInfo) (*BlindedPath, error) {
189+
paymentPath []*HopInfo) (*BlindedPathInfo, error) {
171190

172191
if len(paymentPath) < 1 {
173192
return nil, errors.New("at least 1 hop is required to create " +
@@ -185,7 +204,9 @@ func BuildBlindedPath(sessionKey *btcec.PrivateKey,
185204
keys[i] = p.NodePub
186205
}
187206

188-
hopSharedSecrets, err := generateSharedSecrets(keys, sessionKey)
207+
hopSharedSecrets, lastEphem, err := generateSharedSecrets(
208+
keys, sessionKey,
209+
)
189210
if err != nil {
190211
return nil, fmt.Errorf("error generating shared secret: %v",
191212
err)
@@ -200,7 +221,11 @@ func BuildBlindedPath(sessionKey *btcec.PrivateKey,
200221
bp.BlindedHops[i] = blindedInfo
201222
}
202223

203-
return bp, nil
224+
return &BlindedPathInfo{
225+
Path: bp,
226+
SessionKey: sessionKey,
227+
LastEphemeralKey: lastEphem,
228+
}, nil
204229
}
205230

206231
// blindNodeID blinds the given public key using the provided shared secret.

path_test.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -68,10 +68,10 @@ func TestBuildBlindedRoute(t *testing.T) {
6868

6969
// Construct the concatenated path.
7070
path := &BlindedPath{
71-
IntroductionPoint: pathBC.IntroductionPoint,
72-
BlindingPoint: pathBC.BlindingPoint,
73-
BlindedHops: append(pathBC.BlindedHops,
74-
pathED.BlindedHops...),
71+
IntroductionPoint: pathBC.Path.IntroductionPoint,
72+
BlindingPoint: pathBC.Path.BlindingPoint,
73+
BlindedHops: append(pathBC.Path.BlindedHops,
74+
pathED.Path.BlindedHops...),
7575
}
7676

7777
// Check that the constructed path is equal to the test vector path.

sphinx.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@ type OnionPacket struct {
114114
// generateSharedSecrets by the given nodes pubkeys, generates the shared
115115
// secrets.
116116
func generateSharedSecrets(paymentPath []*btcec.PublicKey,
117-
sessionKey *btcec.PrivateKey) ([]Hash256, error) {
117+
sessionKey *btcec.PrivateKey) ([]Hash256, *btcec.PublicKey, error) {
118118

119119
// Each hop performs ECDH with our ephemeral key pair to arrive at a
120120
// shared secret. Additionally, each hop randomizes the group element
@@ -131,7 +131,7 @@ func generateSharedSecrets(paymentPath []*btcec.PublicKey,
131131
sessionKeyECDH := &PrivKeyECDH{PrivKey: sessionKey}
132132
sharedSecret, err := sessionKeyECDH.ECDH(paymentPath[0])
133133
if err != nil {
134-
return nil, err
134+
return nil, nil, err
135135
}
136136
hopSharedSecrets[0] = sharedSecret
137137
lastBlindingFactor := computeBlindingFactor(
@@ -187,7 +187,7 @@ func generateSharedSecrets(paymentPath []*btcec.PublicKey,
187187
)
188188
}
189189

190-
return hopSharedSecrets, nil
190+
return hopSharedSecrets, lastEphemeralPubKey, nil
191191
}
192192

193193
// NewOnionPacket creates a new onion packet which is capable of obliviously
@@ -214,7 +214,7 @@ func NewOnionPacket(paymentPath *PaymentPath, sessionKey *btcec.PrivateKey,
214214
return nil, fmt.Errorf("packet filler must be specified")
215215
}
216216

217-
hopSharedSecrets, err := generateSharedSecrets(
217+
hopSharedSecrets, _, err := generateSharedSecrets(
218218
paymentPath.NodeKeys(), sessionKey,
219219
)
220220
if err != nil {

0 commit comments

Comments
 (0)