Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 23 additions & 2 deletions lnwallet/btcwallet/signer.go
Original file line number Diff line number Diff line change
Expand Up @@ -238,13 +238,34 @@ func (b *BtcWallet) fetchPrivKey(

// maybeTweakPrivKey examines the single and double tweak parameters on the
// passed sign descriptor and may perform a mapping on the passed private key
// in order to utilize the tweaks, if populated.
// in order to utilize the tweaks, if populated. If both tweak parameters are
// set, then both are applied in the following order:
//
// a) double tweak
// b) single tweak
func maybeTweakPrivKey(signDesc *input.SignDescriptor,
privKey *btcec.PrivateKey) (*btcec.PrivateKey, error) {

var retPriv *btcec.PrivateKey
switch {

// If both tweak parameters are set, then apply both.
if signDesc.DoubleTweak != nil && signDesc.SingleTweak != nil {
// First apply the double tweak.
retPriv = input.DeriveRevocationPrivKey(
privKey, signDesc.DoubleTweak,
)

// Then apply the single tweak.
retPriv = input.TweakPrivKey(
retPriv, signDesc.SingleTweak,
)

return retPriv, nil
}

// If only one tweak parameter is set, apply it respectively over the
// provided private key.
switch {
case signDesc.SingleTweak != nil:
retPriv = input.TweakPrivKey(privKey,
signDesc.SingleTweak)
Expand Down
154 changes: 154 additions & 0 deletions lnwallet/btcwallet/signer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -350,3 +350,157 @@ func getChainBackend(t *testing.T, netParams *chaincfg.Params) (chain.Interface,
func hardenedKey(part uint32) uint32 {
return part + hdkeychain.HardenedKeyStart
}

// TestMaybeTweakPrivKey tests the maybeTweakPrivKey function to ensure it
// correctly applies single tweaks, double tweaks, both tweaks combined, and
// handles the case where no tweaks are applied.
func TestMaybeTweakPrivKey(t *testing.T) {
// Create a test private key.
privKeyBytes, err := hex.DecodeString(
"e68abc8e2a7a5b9f0e4a3c7d8b9e6f5" +
"a4b3c2d1e0f9e8d7c6b5a4938271605",
)
require.NoError(t, err)
privKey, _ := btcec.PrivKeyFromBytes(privKeyBytes)

// Create test tweak values.
singleTweakBytes, err := hex.DecodeString(
"1234567890abcdef1234567890abcdef" +
"1234567890abcdef1234567890abcdef",
)
require.NoError(t, err)

doubleTweakBytes, err := hex.DecodeString(
"fedcba0987654321fedcba0987654321" +
"fedcba0987654321fedcba0987654321",
)
require.NoError(t, err)
doubleTweak, _ := btcec.PrivKeyFromBytes(doubleTweakBytes)

testCases := []struct {
name string
singleTweak []byte
doubleTweak *btcec.PrivateKey
validate func(*testing.T, *btcec.PrivateKey)
}{
{
name: "no tweaks applied",
singleTweak: nil,
doubleTweak: nil,
validate: func(t *testing.T, result *btcec.PrivateKey) {
// Should return the original private key
// unchanged.
require.Equal(
t, privKey.Serialize(),
result.Serialize(),
"expected private key to be unchanged",
)
},
},
{
name: "single tweak only",
singleTweak: singleTweakBytes,
doubleTweak: nil,
validate: func(t *testing.T, result *btcec.PrivateKey) {
// Manually apply single tweak to verify.
expected := input.TweakPrivKey(
privKey, singleTweakBytes,
)
require.Equal(
t, expected.Serialize(),
result.Serialize(),
"single tweak not applied correctly",
)
// Ensure it's different from the original.
require.NotEqual(
t, privKey.Serialize(),
result.Serialize(),
"tweaked key should differ from "+
"original",
)
},
},
{
name: "double tweak only",
singleTweak: nil,
doubleTweak: doubleTweak,
validate: func(t *testing.T, result *btcec.PrivateKey) {
// Manually apply double tweak to verify.
expected := input.DeriveRevocationPrivKey(
privKey, doubleTweak,
)
require.Equal(
t, expected.Serialize(),
result.Serialize(),
"double tweak not applied correctly",
)
// Ensure it's different from the original.
require.NotEqual(
t, privKey.Serialize(),
result.Serialize(),
"tweaked key should differ from "+
"original",
)
},
},
{
name: "both tweaks combined",
singleTweak: singleTweakBytes,
doubleTweak: doubleTweak,
validate: func(t *testing.T, result *btcec.PrivateKey) {
// Manually apply both tweaks in order: double
// first, then single.
afterDouble := input.DeriveRevocationPrivKey(
privKey, doubleTweak,
)
expected := input.TweakPrivKey(
afterDouble, singleTweakBytes,
)
require.Equal(
t, expected.Serialize(),
result.Serialize(),
"combined tweaks not applied correctly",
)
// Ensure it's different from single tweak only.
singleOnly := input.TweakPrivKey(
privKey, singleTweakBytes,
)
require.NotEqual(
t, singleOnly.Serialize(),
result.Serialize(),
"combined tweak should differ from "+
"single tweak only",
)
// Ensure it's different from double tweak only.
doubleOnly := input.DeriveRevocationPrivKey(
privKey, doubleTweak,
)
require.NotEqual(
t, doubleOnly.Serialize(),
result.Serialize(),
"combined tweak should differ from "+
"double tweak only",
)
},
},
}

for _, tc := range testCases {
tc := tc
t.Run(tc.name, func(t *testing.T) {
// Create a sign descriptor with the test tweaks.
signDesc := &input.SignDescriptor{
SingleTweak: tc.singleTweak,
DoubleTweak: tc.doubleTweak,
}

// Call the function under test.
result, err := maybeTweakPrivKey(signDesc, privKey)
require.NoError(t, err)
require.NotNil(t, result)

// Validate the result.
tc.validate(t, result)
})
}
}
Loading