lightningd: use bip86 derivation for anchor spend change outputs
What changed, and why it matters
This small change updates how Core Lightning creates the 'change' output when spending an anchor output in a Lightning channel. It now uses a newer, Taproot-specific key derivation method (BIP86) when available, instead of the older BIP32 method. The change itself is a correctness/hardening improvement for Taproot key handling, not a fix for an active exploit or a clearly disclosed vulnerability.
Treat as a routine correctness/hardening patch. Review related anchor-spend and wallet derivation code to ensure BIP86 is consistently used for all Taproot outputs and that the fallback BIP32 path is still acceptable. No urgent security response is indicated by this commit alone.
Security signals we found
Change in key derivation path for on-chain Taproot change output
Conditional fallback to legacy BIP32 derivation preserves backward compatibility
No explicit security bug, overflow, or authentication bypass visible in diff
No references to CVE, disclosure, or security advisory in commit metadata
Evidence from the diff
In anchor_psbt(), the code previously always derived the final_key via bip32_pubkey() and then wrapped it as a P2TR (Taproot) output. The patch checks whether ld->bip86_base is set; if so, it derives the key with bip86_pubkey(), otherwise falls back to bip32_pubkey(). BIP86 is the standard derivation path for single-key Taproot outputs (m/86’/0’/…), so this aligns the change output’s key derivation with the P2TR script type. The diff does not show any bounds check, memory safety, or cryptographic flaw being fixed; it is a derivation-path correctness change.
Changed components
lightningd/anchorspend.canchor spend change-output key derivationP2TR (Taproot) output constructionInspect captured patch +6 / −1
diff --git a/lightningd/anchorspend.c b/lightningd/anchorspend.c
index a194702..89cf224 100644
--- a/lightningd/anchorspend.c
+++ b/lightningd/anchorspend.c
@@ -276,7 +276,12 @@ static struct wally_psbt *anchor_psbt(const tal_t *ctx,
change = chainparams->dust_limit;
}
- bip32_pubkey(ld, &final_key, channel->final_key_idx);
+ /* Use BIP86 derivation for P2TR if available, otherwise BIP32 */
+ if (ld->bip86_base) {
+ bip86_pubkey(ld, &final_key, channel->final_key_idx);
+ } else {
+ bip32_pubkey(ld, &final_key, channel->final_key_idx);
+ }
psbt_append_output(psbt,
scriptpubkey_p2tr(tmpctx, &final_key),
change);
Why this scored 23/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.