htlcswitch: add blinding kit to handle encrypted data in blinded routes
This commit introduces a blinding kits which abstracts over the operations required to decrypt, deserialize and reconstruct forwarding data from an encrypted blob of data included for nodes in blinded routes.
This commit is contained in:
2 files changed
+275
No files matched your search
@@ -3,8 +3,10 @@ package hop
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"testing"
|
||||
|
||||
"github.com/btcsuite/btcd/btcec/v2"
|
||||
"github.com/davecgh/go-spew/spew"
|
||||
sphinx "github.com/lightningnetwork/lightning-onion"
|
||||
"github.com/lightningnetwork/lnd/lnwire"
|
||||
@@ -153,3 +155,140 @@ func TestForwardingAmountCalc(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// mockProcessor is a mocked blinding point processor that just returns the
|
||||
// data that it is called with when "decrypting".
|
||||
type mockProcessor struct {
|
||||
decryptErr error
|
||||
}
|
||||
|
||||
// DecryptBlindedHopData mocks blob decryption, returning the same data that
|
||||
// it was called with and an optionally configured error.
|
||||
func (m *mockProcessor) DecryptBlindedHopData(_ *btcec.PublicKey,
|
||||
data []byte) ([]byte, error) {
|
||||
|
||||
return data, m.decryptErr
|
||||
}
|
||||
|
||||
// TestDecryptAndValidateFwdInfo tests deriving forwarding info using a
|
||||
// blinding kit. This test does not cover assertions on the calculations of
|
||||
// forwarding information, because this is covered in a test dedicated to those
|
||||
// calculations.
|
||||
func TestDecryptAndValidateFwdInfo(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
// Encode valid blinding data that we'll fake decrypting for our test.
|
||||
maxCltv := 1000
|
||||
blindedData := record.NewBlindedRouteData(
|
||||
lnwire.NewShortChanIDFromInt(1500), nil,
|
||||
record.PaymentRelayInfo{
|
||||
CltvExpiryDelta: 10,
|
||||
BaseFee: 100,
|
||||
FeeRate: 0,
|
||||
},
|
||||
&record.PaymentConstraints{
|
||||
MaxCltvExpiry: 1000,
|
||||
HtlcMinimumMsat: lnwire.MilliSatoshi(1),
|
||||
},
|
||||
nil,
|
||||
)
|
||||
|
||||
validData, err := record.EncodeBlindedRouteData(blindedData)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Mocked error.
|
||||
errDecryptFailed := errors.New("could not decrypt")
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
data []byte
|
||||
incomingCLTV uint32
|
||||
updateAddBlinding *btcec.PublicKey
|
||||
payloadBlinding *btcec.PublicKey
|
||||
processor *mockProcessor
|
||||
expectedErr error
|
||||
}{
|
||||
{
|
||||
name: "no blinding point",
|
||||
data: validData,
|
||||
processor: &mockProcessor{},
|
||||
expectedErr: ErrInvalidPayload{
|
||||
Type: record.BlindingPointOnionType,
|
||||
Violation: OmittedViolation,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "both blinding points",
|
||||
data: validData,
|
||||
updateAddBlinding: &btcec.PublicKey{},
|
||||
payloadBlinding: &btcec.PublicKey{},
|
||||
processor: &mockProcessor{},
|
||||
expectedErr: ErrInvalidPayload{
|
||||
Type: record.BlindingPointOnionType,
|
||||
Violation: IncludedViolation,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "decryption failed",
|
||||
data: validData,
|
||||
updateAddBlinding: &btcec.PublicKey{},
|
||||
incomingCLTV: 500,
|
||||
processor: &mockProcessor{
|
||||
decryptErr: errDecryptFailed,
|
||||
},
|
||||
expectedErr: errDecryptFailed,
|
||||
},
|
||||
{
|
||||
name: "decode fails",
|
||||
data: []byte{1, 2, 3},
|
||||
updateAddBlinding: &btcec.PublicKey{},
|
||||
incomingCLTV: 500,
|
||||
processor: &mockProcessor{},
|
||||
expectedErr: ErrDecodeFailed,
|
||||
},
|
||||
{
|
||||
name: "validation fails",
|
||||
data: validData,
|
||||
updateAddBlinding: &btcec.PublicKey{},
|
||||
incomingCLTV: uint32(maxCltv) + 10,
|
||||
processor: &mockProcessor{},
|
||||
expectedErr: ErrInvalidPayload{
|
||||
Type: record.LockTimeOnionType,
|
||||
Violation: InsufficientViolation,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "valid",
|
||||
updateAddBlinding: &btcec.PublicKey{},
|
||||
data: validData,
|
||||
processor: &mockProcessor{},
|
||||
expectedErr: nil,
|
||||
},
|
||||
}
|
||||
|
||||
for _, testCase := range tests {
|
||||
t.Run(testCase.name, func(t *testing.T) {
|
||||
// We don't actually use blinding keys due to our
|
||||
// mocking so they can be nil.
|
||||
kit := BlindingKit{
|
||||
Processor: testCase.processor,
|
||||
IncomingAmount: 10000,
|
||||
IncomingCltv: testCase.incomingCLTV,
|
||||
}
|
||||
|
||||
if testCase.updateAddBlinding != nil {
|
||||
kit.UpdateAddBlinding = tlv.SomeRecordT(
|
||||
//nolint:lll
|
||||
tlv.NewPrimitiveRecord[lnwire.BlindingPointTlvType](testCase.updateAddBlinding),
|
||||
)
|
||||
}
|
||||
_, err := kit.DecryptAndValidateFwdInfo(
|
||||
&Payload{
|
||||
encryptedData: testCase.data,
|
||||
blindingPoint: testCase.payloadBlinding,
|
||||
}, false,
|
||||
)
|
||||
require.ErrorIs(t, err, testCase.expectedErr)
|
||||
})
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user