Skip to content

Commit

Permalink
sphinx: return error source as integer
Browse files Browse the repository at this point in the history
Returning as an integer allows a node to occur in the payment path
multiple times.
  • Loading branch information
joostjager committed Jun 11, 2019
1 parent 751fb4d commit 991dab9
Show file tree
Hide file tree
Showing 2 changed files with 16 additions and 15 deletions.
21 changes: 12 additions & 9 deletions crypto.go
Original file line number Diff line number Diff line change
Expand Up @@ -171,11 +171,14 @@ const onionErrorLength = 2 + 2 + 256 + sha256.Size
// DecryptError attempts to decrypt the passed encrypted error response. The
// onion failure is encrypted in backward manner, starting from the node where
// error have occurred. As a result, in order to decrypt the error we need get
// all shared secret and apply decryption in the reverse order.
func (o *OnionErrorDecrypter) DecryptError(encryptedData []byte) (*btcec.PublicKey, []byte, error) {
// all shared secret and apply decryption in the reverse order. An integer is
// returned that represents the position of the error node in the path. Index
// zero is the self node. Using an integer allows to distinguish between errors
// from nodes that occur in the path multiple times.
func (o *OnionErrorDecrypter) DecryptError(encryptedData []byte) (int, []byte, error) {
// Ensure the error message length is as expected.
if len(encryptedData) != onionErrorLength {
return nil, nil, fmt.Errorf("invalid error length: "+
return 0, nil, fmt.Errorf("invalid error length: "+
"expected %v got %v", onionErrorLength,
len(encryptedData))
}
Expand All @@ -186,7 +189,7 @@ func (o *OnionErrorDecrypter) DecryptError(encryptedData []byte) (*btcec.PublicK
)

var (
sender *btcec.PublicKey
sender int
msg []byte
dummySecret Hash256
)
Expand All @@ -202,7 +205,7 @@ func (o *OnionErrorDecrypter) DecryptError(encryptedData []byte) (*btcec.PublicK
// secret to continue decryption attempts to fill out the rest
// of the loop. Otherwise, we'll use the next shared secret in
// line.
if sender != nil || i > len(sharedSecrets)-1 {
if sender != 0 || i > len(sharedSecrets)-1 {
sharedSecret = dummySecret
} else {
sharedSecret = sharedSecrets[i]
Expand All @@ -226,16 +229,16 @@ func (o *OnionErrorDecrypter) DecryptError(encryptedData []byte) (*btcec.PublicK
// If the MAC matches up, then we've found the sender of the
// error and have also obtained the fully decrypted message.
realMac := h.Sum(nil)
if hmac.Equal(realMac, expectedMac) && sender == nil {
sender = o.circuit.PaymentPath[i]
if hmac.Equal(realMac, expectedMac) && sender == 0 {
sender = i + 1
msg = data
}
}

// If the sender pointer is still nil, then we haven't found the
// sender, meaning we've failed to decrypt.
if sender == nil {
return nil, nil, errors.New("unable to retrieve onion failure")
if sender == 0 {
return 0, nil, errors.New("unable to retrieve onion failure")
}

return sender, msg, nil
Expand Down
10 changes: 4 additions & 6 deletions obfuscation_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,14 +59,13 @@ func TestOnionFailure(t *testing.T) {

// Emulate that sender node receive the failure message and trying to
// unwrap it, by applying obfuscation and checking the hmac.
pubKey, deobfuscatedData, err := deobfuscator.DecryptError(obfuscatedData)
source, deobfuscatedData, err := deobfuscator.DecryptError(obfuscatedData)
if err != nil {
t.Fatalf("unable to de-obfuscate the onion failure: %v", err)
}

// We should understand the node from which error have been received.
if !bytes.Equal(pubKey.SerializeCompressed(),
errorPath[len(errorPath)-1].SerializeCompressed()) {
if source != len(errorPath) {
t.Fatalf("unable to properly conclude from which node in " +
"the path we received an error")
}
Expand Down Expand Up @@ -255,7 +254,7 @@ func TestOnionFailureSpecVector(t *testing.T) {

// Emulate that sender node receives the failure message and trying to
// unwrap it, by applying obfuscation and checking the hmac.
pubKey, deobfuscatedData, err := deobfuscator.DecryptError(obfuscatedData)
source, deobfuscatedData, err := deobfuscator.DecryptError(obfuscatedData)
if err != nil {
t.Fatalf("unable to de-obfuscate the onion failure: %v", err)
}
Expand All @@ -267,8 +266,7 @@ func TestOnionFailureSpecVector(t *testing.T) {
}

// We should understand the node from which error have been received.
if !bytes.Equal(pubKey.SerializeCompressed(),
paymentPath[len(paymentPath)-1].SerializeCompressed()) {
if source != len(paymentPath) {
t.Fatalf("unable to properly conclude from which node in " +
"the path we received an error")
}
Expand Down

0 comments on commit 991dab9

Please sign in to comment.