btcwallet: support combined tweak to private key
What changed, and why it matters
This commit adds a new option in LND's Bitcoin wallet signer that lets two different key tweaks be applied one after another to a private key, instead of only allowing one at a time. A tweak is a cryptographic adjustment used in Lightning for things like revocation keys and HTLC indexes. The change is additive and preserves old behavior when only one tweak is provided. There is no direct evidence in the commit that this fixes an active security vulnerability.
Review callers that set both SingleTweak and DoubleTweak to confirm the new combined ordering matches protocol expectations. Treat as a normal code review item rather than an urgent security patch unless additional context emerges.
Security signals we found
Private key derivation logic changed
Combined tweak ordering could affect cryptographic correctness if used incorrectly by callers
No explicit security claim in commit message or diff
Evidence from the diff
The change modifies maybeTweakPrivKey in lnwallet/btcwallet/signer.go. Previously the function handled SingleTweak, DoubleTweak, or neither. Now it also handles the case where both are non-nil by applying DeriveRevocationPrivKey (double tweak) first, then TweakPrivKey (single tweak). The existing single-tweak and double-tweak-only branches remain unchanged. This is a feature/capability expansion rather than a bug fix, and the commit message does not describe a security issue.
Changed components
lnwallet/btcwallet/signer.gomaybeTweakPrivKey functioninput.SignDescriptor tweak handlingInspect captured patch +17 / −5
diff --git a/lnwallet/btcwallet/signer.go b/lnwallet/btcwallet/signer.go
index 69f7ab6..eecea0f 100644
--- a/lnwallet/btcwallet/signer.go
+++ b/lnwallet/btcwallet/signer.go
@@ -238,20 +238,32 @@ 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, apply the double tweak first
+ // (revocation), then the single tweak (HTLC index).
+ case signDesc.DoubleTweak != nil && signDesc.SingleTweak != nil:
+ retPriv = input.DeriveRevocationPrivKey(
+ privKey, signDesc.DoubleTweak,
+ )
+ retPriv = input.TweakPrivKey(retPriv, signDesc.SingleTweak)
case signDesc.SingleTweak != nil:
- retPriv = input.TweakPrivKey(privKey,
- signDesc.SingleTweak)
+ retPriv = input.TweakPrivKey(privKey, signDesc.SingleTweak)
case signDesc.DoubleTweak != nil:
- retPriv = input.DeriveRevocationPrivKey(privKey,
- signDesc.DoubleTweak)
+ retPriv = input.DeriveRevocationPrivKey(
+ privKey, signDesc.DoubleTweak,
+ )
default:
retPriv = privKey
Why this scored 28/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.