LL
← All projectsLightning Labs

LND

Go implementation of a complete Lightning Network node.

BitcoinLightning NetworkNormal
Repository coverage

1235 commits in the local evidence base

Every captured commit receives deterministic security triage and a separate communication-quality score. Security candidates and broader second-pass signals receive full-patch Ollama analysis.

116security candidates168second-pass queue228AI analyses
76commits · 30 days
165commits · 60 days
824commits · 180 days
1226commits · 365 days
Backfill bands
Aug 5 → Feb 6405 seen5 candidatesComplete
Feb 6 → Jun 6665 seen28 candidatesComplete
Jun 6 → Jul 689 seen4 candidatesComplete
Jul 6 → Aug 569 seen0 candidatesComplete
Commit communication

Does the history explain itself?

Message quality measures whether a commit identifies its scope, purpose, rationale, testing, and supporting references. It does not change the security-severity score.

67/100 average clarity
279Strong · 80–100
559Adequate · 60–79
366Thin · 40–59
31Opaque · 0–39
1security candidate with opaque commit messaging
Read the scoring rubric →
Developer activity

Who is changing the project?

Public Git author strings; identities are not independently verified.

DeveloperCommitsCandidatesAnalyzedHigh riskMessage avg.
Olaoluwa Osuntokun1994069274
Elle Mouton2673142067
ziggie4081543064
Erick Cestari26715070
bitromortac4658067
yyforyongyu5537065
saubyk1522070
Oli724057
Suheb322075
elnosh322071
George Tsagkarelis32114066
Gijs van Dam2612071
Analysis record

Published AI watches

Last scanned 31 minutes ago

Moderate 63 AI analysisMessage 58 · Thin
LL Lightning LabsLND BitcoinLightning Network

Merge pull request #11024 from ziggie1984/invoices-update-validation

This commit tightens how LND processes invoice payments, especially for newer multi-path (MPP) and AMP invoices, keysend payments, and replayed payments. It adds checks that ensure the right payment preimage is used for each invoice type a…

Preimage validation added for AMP and regular invoice replaysAMP invoices forced into MPP update path, preventing legacy-path processingLegacy settlement now fails when invoice-level preimage is missing
61f3b5a7by ziggieXXX+482−114 files
No security note in commit
Moderate 59 AI analysisMessage 35 · Opaque
LL Lightning LabsLND BitcoinLightning Network

invoices: refine update handling

This commit tightens how LND handles invoice payment updates, especially for newer 'AMP' invoices and old-style 'keysend' payments. It adds checks so that the wrong kind of payment cannot be processed against the wrong kind of invoice, and…

Added preimage/hash mismatch checks for both regular and AMP invoice replaysAMP records now require an MPP payload, preventing AMP processing on the legacy pathLegacy path now rejects AMP invoices and invoices missing invoice-level preimages
6be6350eby ziggie+476−113 files
No security note in commit
Informational 21 AI analysisMessage 73 · Adequate
LL Lightning LabsLND BitcoinLightning Network

bolt12: add InvoiceError onion message replies

This commit adds support in LND for a new Lightning protocol message called InvoiceError. It is used to politely tell another node why their payment invoice or invoice request was rejected, sent privately through an onion-routed message. T…

New unsigned onion message type added with no cryptographic signature or bech32 formWriter-side validation prevents empty or non-UTF-8 error strings and disallowed suggested_value without erroneous_fieldReader-side BOLT 1 must-understand rule enforced: unknown even TLVs rejected, unknown odd TLVs tolerated
e279cdf1by bitromortac+567−04 files
No security note in commit
Low 36 AI analysisMessage 73 · Adequate
LL Lightning LabsLND BitcoinLightning Network

bolt12: validate Invoice messages

This commit adds validation checks for BOLT 12 invoices in the LND Lightning node software. It ensures invoices contain required fields (creation time, amount, payment hash, node ID, payment paths), match their originating invoice requests…

New validation gate added to Invoice.Encode() to reject malformed invoices before serializationReader rejects unknown even invoice TLV types and unknown even feature bitsReader enforces chain compatibility against activeChain
e0f04f17by bitromortac+1642−74 files
No security note in commit
Informational 12 AI analysisMessage 73 · Adequate
LL Lightning LabsLND BitcoinLightning Network

bolt12: add Invoice struct and TLV codec

This commit adds new code to support BOLT 12 invoices in the LND Lightning node. It introduces a data structure, encoding/decoding logic, and helper functions to filter fallback addresses and blinded payment paths. There is no bug fix or s…

efbeef58by bitromortac+777−02 files
No security note in commit
Informational 15 AI analysisMessage 80 · Strong
LL Lightning LabsLND BitcoinLightning Network

ci: split issue dedupe into find and post jobs

This commit is a hardening and refactoring change to a GitHub Actions workflow that detects duplicate issues. It splits the workflow into two jobs: one that only reads issue data and uses an AI model to find duplicates, and a second that o…

Principle of least privilege: AI/model job no longer holds issues:write or id-token:writeAction dependency pinned to full commit SHA instead of mutable tagpersist-credentials: false set on checkout steps
d1ea8687by Olaoluwa Osuntokun+148−71 file
No security note in commit
Informational 15 AI analysisMessage 85 · Strong
LL Lightning LabsLND BitcoinLightning Network

ci: split PR severity workflow into classify and apply jobs

This commit is a hardening and cleanup of a GitHub Actions workflow that automatically labels pull requests by severity. It does not change any LND node code, wallet logic, or network protocol. Instead, it splits the workflow into two jobs…

Principle of least privilege: write token moved out of the model-bearing jobUntrusted input (model-generated comment) sanitized before privileged API useExternal action pinned to immutable commit SHA instead of mutable tag
05c62527by Olaoluwa Osuntokun+424−593 files
Vendor flagged security relevance
Informational 21 AI analysisMessage 68 · Adequate
LL Lightning LabsLND BitcoinLightning Network

github: bump gateway code-review to v0.5.0

This commit updates a GitHub Actions workflow for an optional code-review bot called 'gateway' from version 0.4.4 to 0.5.0. It adds support for replying to inline review comments (not just regular PR comments) and pins the new action and r…

Workflow-only change with no modifications to LND application codeAction and runtime pinned to immutable commit SHAs (supply-chain mitigation)New pull_request_review_comment trigger added; commit message asserts same fork-PR secret safety as issue_comment
447703a4by saubyk+20−61 file
No security note in commit
Informational 15 AI analysisMessage 78 · Adequate
LL Lightning LabsLND BitcoinLightning Network

lnwallet: use channel state open channel

This commit is a straightforward internal code cleanup: it changes the lnwallet package to use the OpenChannel type from a dedicated chanstate package instead of getting it indirectly through the channeldb package. There is no change to us…

fa31c564by ziggie+59−469 files
No security note in commit
Informational 15 AI analysisMessage 78 · Adequate
LL Lightning LabsLND BitcoinLightning Network

htlcswitch: use channel state open channel

This commit only changes test helper code in LND. It swaps one internal type name (channeldb.OpenChannel) for another (chanstate.OpenChannel) inside test utilities. There is no change to production code, no user-facing behavior change, and…

a4bec71bby ziggie+6−51 file
No security note in commit
Informational 15 AI analysisMessage 68 · Adequate
LL Lightning LabsLND BitcoinLightning Network

funding: use channel state open channel

This commit is a straightforward internal code cleanup in LND's channel-opening machinery. It swaps one internal type name (channeldb.OpenChannel) for another (chanstate.OpenChannel) across function signatures in the funding manager and it…

03daaad4by ziggie+28−272 files
No security note in commit
Informational 15 AI analysisMessage 68 · Adequate
LL Lightning LabsLND BitcoinLightning Network

server: use channel state open channel

This commit is a straightforward internal code cleanup in LND. It changes three places in server.go to use a new internal type name (chanstate.OpenChannel) instead of an old alias (channeldb.OpenChannel). The actual behavior of the code is…

8e709678by ziggie+3−31 file
No security note in commit
Informational 15 AI analysisMessage 68 · Adequate
LL Lightning LabsLND BitcoinLightning Network

chanstate: use channel type in wallet rpc

This is a small internal code cleanup in LND's wallet RPC server. It changes one helper function to use a newer internal package type (chanstate.OpenChannel) instead of an older compatibility alias (channeldb.OpenChannel). There is no user…

8a215d9eby ziggie+3−21 file
No security note in commit
Low 46 AI analysisMessage 56 · Thin
LL Lightning LabsLND BitcoinLightning Network

chanstate: fix htlc copy

This commit fixes a bug in how the Lightning Network Daemon (LND) copies payment channel data. When the program made a copy of an HTLC (a pending payment in a Lightning channel), it failed to copy several important fields and did not prope…

Incomplete deep copy of security-relevant channel stateMissing fields in HTLC clone (RHash, OnionBlob, HtlcIndex, LogIndex)Nil-slice copy bug for Signature and ExtraData
b720fd5cby ziggie+88−42 files
No security note in commit
Informational 15 AI analysisMessage 58 · Thin
LL Lightning LabsLND BitcoinLightning Network

chanstate: remove store generics

This commit is a routine internal code cleanup in the LND Lightning node software. It removes temporary generic type parameters from channel-state database interfaces and replaces them with direct references to the concrete OpenChannel typ…

68ad283dby ziggie+88−8915 files
No security note in commit
Informational 15 AI analysisMessage 78 · Adequate
LL Lightning LabsLND BitcoinLightning Network

chanstate: move taproot channel helpers

This commit is a routine code reorganization: it moves two helper functions and a constant related to Taproot channels from one internal package (channeldb) to another (chanstate), and leaves aliases in the old location so existing callers…

c065aa91by ziggie+93−632 files
No security note in commit
Informational 18 AI analysisMessage 58 · Thin
LL Lightning LabsLND BitcoinLightning Network

channeldb: derive channel packagers

This commit is a code cleanup: it removes a forwarding-package helper object from the in-memory channel state and instead creates it on demand inside database methods. There is no direct security fix or vulnerability being patched. It main…

No security-relevant keywords in commit title or messageNo changes to cryptographic operations, authentication, or network parsingRefactoring only: field removal and localized object construction
0229e0adby ziggie+47−989 files
No security note in commit
Informational 15 AI analysisMessage 68 · Adequate
LL Lightning LabsLND BitcoinLightning Network

chanstate: add remote commit chain store

This commit is a straightforward internal code reorganization. It moves the existing logic for saving a new remote commitment-chain update from one place in the code to another, without changing what the logic actually does. There is no us…

06308e1dby ziggie+21−52 files
No security note in commit
Informational 15 AI analysisMessage 68 · Adequate
LL Lightning LabsLND BitcoinLightning Network

chanstate: make store channel types generic

This commit is a pure internal code reorganization. It moves several small channel-related data types (like channel configuration, status flags, close summaries, and helper types) from the channeldb package into a new chanstate package, th…

f53d615cby ziggie+473−36518 files
No security note in commit
Low 30 AI analysisMessage 73 · Adequate
LL Lightning LabsLND BitcoinLightning Network

lnwallet+walletrpc: add SubmitPackage for v3 CPFP package relay

This commit adds a new RPC called SubmitPackage to LND's WalletKit. It lets users submit a group of related Bitcoin transactions together so a zero-fee parent can be accepted because a later child transaction pays its fee. This is a featur…

New RPC endpoint gated by onchain:write macaroon permissionPackage size bounded to 25 transactions to limit deserialization workFee-rate ceiling passed through to backend; explicit 0 disables limit
f55c0565by Elle Mouton+1019−21517 files
No security note in commit
Repository ledger

Explore captured commits

Expand any commit for its author, full message, clarity score, changed files, triage signals, analysis, and source link.

Lower-priorityserver+docs: construct onion message rate limiters and document configby Olaoluwa Osuntokun · 1db6eb66 · Apr 15, 2026 · 2 filesMessage 85 · StrongTriage 0Details
Commit message · Olaoluwa Osuntokun

server+docs: construct onion message rate limiters and document config

With the limiter primitives, config options, and peer-side enforcement
in place, this commit constructs the per-peer and global onion message
rate limiters inside the server's onion messaging setup block,
composes them with NewIngressLimiter, and threads the resulting
IngressLimiter into peer.Config alongside the existing SpawnOnionActor
factory as a single OnionLimiter field. The limiters are only built
when onion messaging is actually enabled so that the disabled path
allocates nothing.

sample-lnd.conf gains commented-out entries for the four new options
with the default values and a short explanation of the ~5 Mbps
worst-case target. The user-facing release note for this feature is
added in a single consolidated commit at the end of the series rather
than split across the commits that introduce it.

85/100 · StrongMessage clarity
✓ Specific, descriptive subject✓ Names a concrete action or component✓ Provides detailed explanatory context✓ Explains rationale or failure mode
Lower-prioritypeer: enforce onion message rate limits at ingressby Olaoluwa Osuntokun · 9cad57bf · Apr 15, 2026 · 6 filesMessage 95 · StrongTriage 0Details
Commit message · Olaoluwa Osuntokun

peer: enforce onion message rate limits at ingress

This commit plumbs the combined IngressLimiter (per-peer + global)
through peer.Config and consults it from the readHandler's
*lnwire.OnionMessage case. The decision is factored into a small
allowOnionMessage helper so that the ingress policy is directly
unit-testable without standing up a full Brontide harness. Per-peer is
checked first inside the IngressLimiter: if we consulted the global
limiter first, a peer whose own bucket was already empty would still
get to burn a global token on each attempt, letting a single hostile
peer drain the shared budget and starve legitimate peers.

peer.Config carries a single OnionLimiter field of IngressLimiter type;
the brontide readHandler calls a single AllowN per incoming onion
message and dispatches on sentinel errors via errors.Is for the
first-drop log path. Nil limiter values are treated as "disabled"
throughout, which both preserves the pre-change behavior when onion
messaging is entirely turned off and keeps the brontide test harness
from needing to construct real limiters. Per-peer bucket state is
retained across disconnect at the IngressLimiter layer so a peer
cannot cycle the connection to reset its per-peer allowance.

OnionMessage also gains a WireSize method that computes the
on-the-wire size directly from the in-memory fields (no round-trip
through Encode) so the hot ingress path can charge the right number of
byte tokens without paying for a full serialization.

The accompanying unit tests cover the nil/disabled path, the
per-peer-rejects-first ordering invariant (asserting the global
limiter is not consulted when the per-peer bucket is empty), the
global rejection path, per-peer isolation across distinct pubkeys, and
a small concurrent stress test that asserts every attempt is accounted
for as either accepted or dropped and that the total accepted count
equals the configured burst under -race. A property-based rapid test
on WireSize guards against silent divergence from WriteMessage if the
OnionMessage wire format ever gains a TLV extension.

95/100 · StrongMessage clarity
✓ Specific, descriptive subject✓ Names a concrete action or component✓ Provides detailed explanatory context✓ Explains rationale or failure mode✓ Mentions testing or verification
Lower-priorityitest: fix flake in testIntroductionNodeErrorby ziggie · 33cb63f3 · Apr 14, 2026 · 1 fileMessage 100 · StrongTriage 0Details
Commit message · ziggie

itest: fix flake in testIntroductionNodeError

`testRelayingBlindedError` already uses `flakePaymentStreamReturnEarly`
after draining Carol's outgoing liquidity for the same reason:
`drainCarolLiquidity` causes the draining node to originate a payment,
which produces SEND-type HTLC notifier events. Because `SendPaymentV2`
returns SUCCEEDED before the commitment dance (revoke-and-ack exchange)
completes, those events can still be in-flight when the test subscribes
to HTLC events. The htlc notifier's subscribe server races a pending
SendUpdate against the Subscribe call in a single handler goroutine; if
registration wins the random select, the stale SEND events land on the
new subscriber and corrupt the subsequent FORWARD-type assertion.

`testIntroductionNodeError` has the same pattern — Bob drains Carol's
incoming liquidity by originating a payment — but was missing the sleep.
Add `flakePaymentStreamReturnEarly()` to match the existing workaround.

Fixes: https://github.com/lightningnetwork/lnd/actions/runs/24278289474/job/70895848920

100/100 · StrongMessage clarity
✓ Descriptive subject✓ Names a concrete action or component✓ Provides detailed explanatory context✓ Explains rationale or failure mode✓ Mentions testing or verification✓ Links an issue, advisory, or supporting reference✓ Names security-relevant behavior explicitly
Lower-priorityfunding: process channel_ready messages inline in the coordinatorby Olaoluwa Osuntokun · 312dda86 · Apr 13, 2026 · 1 fileMessage 85 · StrongTriage 0Details
Commit message · Olaoluwa Osuntokun

funding: process channel_ready messages inline in the coordinator

In this commit, we refactor how the funding manager handles incoming
channel_ready messages. Previously, every channel_ready message would
unconditionally spawn a new goroutine via `go f.handleChannelReady(...)`,
making it the only message type in the coordinator switch that wasn't
processed inline. We now handle channel_ready the same way as all the
other funding messages: synchronously within the reservation coordinator
loop.

The goroutine was originally needed because handleChannelReady may need
to block on a `localDiscoverySignal` while the channel's funding
confirmation flow completes locally. In this commit, we split the
function into two parts: `handleChannelReady` (the lightweight entry
point that runs inline) and `processChannelReady` (the extracted body
that does the actual DB lookup and channel finalization). The inline
entry point checks whether a `localDiscoverySignal` exists for the given
channel ID, and only in that case do we dispatch a goroutine to wait for
the signal before calling `processChannelReady`. For channels that have
already confirmed (or after a restart), no goroutine is spawned at all.

This short-circuits the common path: the `FindChannel` DB lookup and the
rest of the processing now happen inline in the coordinator for the
majority of channel_ready messages, reducing goroutine churn and keeping
the coordinator's message processing consistent across all message types.

85/100 · StrongMessage clarity
✓ Specific, descriptive subject✓ Names a concrete action or component✓ Provides detailed explanatory context✓ Explains rationale or failure mode
Lower-priorityfunding/test: add test for inline channel_ready processingby Olaoluwa Osuntokun · c68397b9 · Apr 13, 2026 · 1 fileMessage 88 · StrongTriage 0Details
Commit message · Olaoluwa Osuntokun

funding/test: add test for inline channel_ready processing

In this commit, we add TestChannelReadyUnknownChannelID which verifies
that channel_ready messages with unrecognized ChannelIDs are processed
inline in the reservation coordinator without spawning goroutines. The
test sends 100 channel_ready messages with random ChannelIDs, waits for
all of them to be consumed (verified via a FindChannel call counter),
then asserts that the goroutine count hasn't grown proportionally. It
also confirms the coordinator remains responsive by successfully opening
a new channel after the batch completes.

88/100 · StrongMessage clarity
✓ Specific, descriptive subject✓ Names a concrete action or component✓ Provides detailed explanatory context✓ Mentions testing or verification✓ Names security-relevant behavior explicitly
AI review queuedmulti: add SCB restore support for production taproot channelsby Olaoluwa Osuntokun · 85bba2ca · Apr 13, 2026 · 3 filesMessage 95 · StrongModerate 63Details
Commit message · Olaoluwa Osuntokun

multi: add SCB restore support for production taproot channels

Add the missing SimpleTaprootFinalVersion case to
chanrestore.openChannelShell() so that SCB backups created for
production taproot channels can be properly restored. Without this,
the channel type bits were not reconstructed during restore, causing
DLP to fail.

Also add integration tests for both confirmed and zero-conf variants
of production taproot channel backup restoration.

95/100 · StrongMessage clarity
✓ Specific, descriptive subject✓ Names a concrete action or component✓ Provides detailed explanatory context✓ Explains rationale or failure mode✓ Mentions testing or verification
Why it was queued
signing or wallet pathsecond-pass: security-sensitive path
AI analysis · Moderate 63/100

This commit fixes a bug in LND where backups of a new type of Bitcoin Lightning channel (called a 'production taproot channel') could not be properly restored. Without the fix, the channel type information was lost during restore, which could prevent users from recovering their funds through the Data Loss Protection (DLP) protocol. The commit also adds integration tests for both confirmed and unconfirmed (zero-conf) versions of these channels, and updates a warning comment about a test-only randomness option to make clear it must never be used in production because it could leak private keys.

Lower-prioritydocs/release-notes: add release note for production taproot channelsby Olaoluwa Osuntokun · 91e35c4d · Apr 13, 2026 · 1 fileMessage 50 · ThinTriage 0Details
Commit message · Olaoluwa Osuntokun

docs/release-notes: add release note for production taproot channels

50/100 · ThinMessage clarity
✓ Specific, descriptive subject✓ Names a concrete action or component! No meaningful explanatory body
Why it was queued
documentation-only discount
Security candidatelnwallet: add MuSig2 secret nonces and partial sig replay to test vectorsby Olaoluwa Osuntokun · 4c225ddf · Apr 13, 2026 · 1 fileMessage 88 · StrongInformational 12Details
Commit message · Olaoluwa Osuntokun

lnwallet: add MuSig2 secret nonces and partial sig replay to test vectors

In this commit, we extend the taproot test vector generator and verifier
to include MuSig2 secret nonces and a full partial signature replay
test.

For the generator, we now capture the correct nonces for each
commitment transaction: local's verification nonce (from LocalSession)
for local's own commitment, and remote's JIT signing nonce (from
RemoteSession) for the same commitment. Previously, the local nonce was
incorrectly captured from the RemoteSession, which corresponds to a
different commitment transaction.

The new musig2_partial_sig_replay test sub-suite verifies three
properties for each test case:

1. The remote partial sig can be independently reproduced from the
secret nonce and private key using musig2.Sign().

2. The local partial sig can be independently produced and verified
using the local secret nonce.

3. Both partial sigs combine (via the Session API) into the exact
Schnorr signature present in the commitment transaction witness.

This enables interop implementations to validate their MuSig2 signing
logic against the test vectors without needing to match nonce derivation
algorithms across different secp256k1 libraries.

88/100 · StrongMessage clarity
✓ Specific, descriptive subject✓ Names a concrete action or component✓ Provides detailed explanatory context✓ Mentions testing or verification✓ Names security-relevant behavior explicitly
Why it was queued
secret or key materialsigning boundarydefensive validationfuzzing or regression evidencenonce handlingsigning or wallet path
AI analysis · Informational 12/100

This commit only changes test code. It improves the test-vector generator for taproot channels so it records the correct MuSig2 secret nonces, and adds a new test that replays the signing process to confirm the produced signatures match the ones stored in the test vectors. There is no change to production wallet or signing logic, so it does not introduce or fix a live security vulnerability.

Lower-prioritychanbackup: add SimpleTaprootFinalVersion for production taproot backupsby Olaoluwa Osuntokun · 98c086ba · Apr 13, 2026 · 1 fileMessage 73 · AdequateTriage 0Details
Commit message · Olaoluwa Osuntokun

chanbackup: add SimpleTaprootFinalVersion for production taproot backups

Add a dedicated backup version (7) for production taproot channels that
use final scripts with OP_CHECKSIGVERIFY. This distinguishes them from
staging taproot channels in the SCB format, ensuring backup
compatibility is explicit about the channel type.

73/100 · AdequateMessage clarity
✓ Specific, descriptive subject✓ Names a concrete action or component✓ Provides detailed explanatory context
Security candidatemulti: add custom nonce rand support to MuSig2 sessionsby Olaoluwa Osuntokun · 08c42b19 · Apr 13, 2026 · 3 filesMessage 88 · StrongInformational 19Details
Commit message · Olaoluwa Osuntokun

multi: add custom nonce rand support to MuSig2 sessions

In this commit, we add the ability to inject a custom random source
for generating JIT (Just-In-Time) signing nonces in MuSig2 sessions.
By default, MuSig2 signing nonces are generated using crypto/rand,
which makes signatures non-deterministic across runs. For test vector
generation, we need fully reproducible signatures from a fixed seed.

A new `customNonceRand` field is threaded through `MusigSession`,
`MusigSessionCfg`, `MusigPairSession`, and exposed via the
`WithCustomSigningRand` channel option. When set, the custom reader
is passed to `musig2.WithCustomRand()` during JIT nonce generation
in `SignCommit`. All existing callers pass `fn.None[io.Reader]()` to
preserve the current behavior of using the system CSPRNG.

88/100 · StrongMessage clarity
✓ Specific, descriptive subject✓ Names a concrete action or component✓ Provides detailed explanatory context✓ Mentions testing or verification✓ Names security-relevant behavior explicitly
Why it was queued
entropy or randomnesssigning boundaryfuzzing or regression evidencesigning or wallet path
AI analysis · Informational 19/100

This change adds a hidden switch that lets developers plug in a custom random source when creating MuSig2 signing nonces, mainly so tests can produce exactly the same signatures every time. In normal operation the switch is left empty, so the code still uses the operating system's cryptographic random generator. The patch itself is a test-infrastructure feature, not a fix for an active security bug, but any future misuse of the switch could weaken signature security.

Security candidatelnwallet: regenerate test vectors with BIP-340 HTLC signaturesby Olaoluwa Osuntokun · 1866770f · Apr 13, 2026 · 1 fileMessage 83 · StrongInformational 15Details
Commit message · Olaoluwa Osuntokun

lnwallet: regenerate test vectors with BIP-340 HTLC signatures

Regenerate the test vector JSON with HTLC second-level transaction
signatures that use BIP-340 standard nonce derivation (zero auxrand)
instead of RFC6979. This makes the HTLC signatures reproducible across
different Schnorr implementations. The commitment transaction MuSig2
signatures are unchanged.

83/100 · StrongMessage clarity
✓ Specific, descriptive subject✓ Names a concrete action or component✓ Provides detailed explanatory context✓ Mentions testing or verification
Why it was queued
signing boundaryfuzzing or regression evidencesigning or wallet path
AI analysis · Informational 15/100

This commit only updates test data in a single JSON file. It changes the example signatures used in automated tests so they are generated with a standard BIP-340 nonce method instead of an older RFC6979 method. No production wallet code, protocol logic, or user-facing behavior is changed. There is no security vulnerability here.

Security candidatelnwallet: add secret nonce stashing to MusigSession for test vectorsby Olaoluwa Osuntokun · 2148445c · Apr 13, 2026 · 1 fileMessage 83 · StrongInformational 18Details
Commit message · Olaoluwa Osuntokun

lnwallet: add secret nonce stashing to MusigSession for test vectors

In this commit, we add the ability for MusigSession to capture and
expose the raw 97-byte MuSig2 secret nonce generated during JIT signing
nonce creation. This is gated behind the customNonceRand option, so it
only activates in test vector generation mode.

The stashed secret nonce is consumed on read (cleared after access) to
prevent accidental nonce reuse. This enables interop test vectors to
include the raw secret nonces, allowing other implementations to replay
the MuSig2 signing process without needing to match the exact nonce
derivation algorithm used by btcd's musig2 library.

83/100 · StrongMessage clarity
✓ Specific, descriptive subject✓ Names a concrete action or component✓ Provides detailed explanatory context✓ Mentions testing or verification
Why it was queued
signing boundaryfuzzing or regression evidencenonce handlingsigning or wallet path
AI analysis · Informational 18/100

This commit adds a test-only feature that lets LND temporarily save the secret random number (nonce) used in MuSig2 signing when running in a special test-vector generation mode. The saved value is automatically erased after one read to prevent accidental reuse. There is no indication this feature is active in normal production code, and the change is explicitly described as being for interoperability test vectors only.

Security candidatelnwallet: add 3rd-party signature verification for taproot test vectorsby Olaoluwa Osuntokun · 77da917c · Apr 13, 2026 · 1 fileMessage 88 · StrongInformational 12Details
Commit message · Olaoluwa Osuntokun

lnwallet: add 3rd-party signature verification for taproot test vectors

In this commit, we add a `signature_verification` sub-test to the
taproot test vector verifier that performs full script execution against
both the commitment transaction and all HTLC resolution transactions.

This uses `txscript.NewEngine` to execute the taproot witness programs
exactly as a Bitcoin node would, providing an independent check that all
signatures in the test vectors are cryptographically valid. For the
commitment transaction, we verify its witness against the funding output
pkScript. For each HTLC resolution transaction, we verify its witness
against the corresponding commitment output it spends.

This catches issues that the structural comparison tests (hex matching)
cannot: for instance, a transaction can have the correct structure but
carry an invalid signature if the sighash was computed over the wrong
prevout or if the wrong key was used for signing. Running the full
script engine also validates the control block, the tap leaf hash, and
the overall taproot spend path.

88/100 · StrongMessage clarity
✓ Specific, descriptive subject✓ Names a concrete action or component✓ Provides detailed explanatory context✓ Mentions testing or verification✓ Names security-relevant behavior explicitly
Why it was queued
signing boundarydefensive validationfuzzing or regression evidencesigning or wallet path
AI analysis · Informational 12/100

This commit only adds a new test to the project's test suite. It does not change any production code, user-facing behavior, or network protocol. The new test cryptographically checks that example transactions in the project's test data carry valid Bitcoin signatures. It is a defensive quality improvement, not a fix for a known bug or vulnerability.

Lower-prioritymulti: fix lint and itest failures for production taproot channelsby Olaoluwa Osuntokun · fd3b6386 · Apr 13, 2026 · 2 filesMessage 83 · StrongTriage 0Details
Commit message · Olaoluwa Osuntokun

multi: fix lint and itest failures for production taproot channels

Fix line length lint violations in utxonursery.go by adding nolint:ll
directives to long case statements for production taproot witness types.

Fix itest funding negotiation test to handle SIMPLE_TAPROOT_FINAL in
the taproot negotiation failure check. Previously the test only expected
failure when Carol wanted SIMPLE_TAPROOT and Dave lacked taproot
support, but did not handle the symmetric case where Carol wants
SIMPLE_TAPROOT_FINAL.

83/100 · StrongMessage clarity
✓ Specific, descriptive subject✓ Names a concrete action or component✓ Provides detailed explanatory context✓ Mentions testing or verification
Security candidatelnwallet: fix HTLC sig-to-transaction mapping in test vector generatorby Olaoluwa Osuntokun · b78de44d · Apr 13, 2026 · 1 fileMessage 100 · StrongInformational 24Details
Commit message · Olaoluwa Osuntokun

lnwallet: fix HTLC sig-to-transaction mapping in test vector generator

In this commit, we fix two interrelated bugs in the way HTLC signatures
are associated with their corresponding second-level transactions in the
taproot test vector generator.

The first issue was that HtlcSigs are sorted by BIP 69 output index
(matching the commitment transaction's output ordering), but the old
code was assigning signatures using the iteration order of incoming
HTLCs followed by outgoing HTLCs. This meant timeout transaction
signatures were getting paired with success transactions and vice versa
whenever the output ordering didn't happen to match the incoming-first
iteration order. This is the root cause of the invalid HTLC-timeout
signatures that eclair reported when cross-validating.

We now collect all HTLC entries (both incoming and outgoing) into a
single slice, sort them by their commitment output index, then zip them
against the HtlcSigs array so each signature lines up with the correct
second-level transaction.

The second issue was in the HTLC-success preimage extraction path. The
old code read the witness script from index [4] (the control block) and
used a hardcoded byte offset of 69 to locate the payment hash, then
wrote the preimage into index [3] (overwriting the script). The correct
taproot witness layout is [remoteSig, localSig, preimage, script,
controlBlock], so the script lives at [3] and the preimage slot is [2].
We now use `txscript.ScriptTokenizer` to walk the script opcodes and
find OP_HASH160 followed by the 20-byte push data, which is far more
robust than relying on fragile byte offsets that break if the script
template ever changes.

100/100 · StrongMessage clarity
✓ Specific, descriptive subject✓ Names a concrete action or component✓ Provides detailed explanatory context✓ Explains rationale or failure mode✓ Mentions testing or verification✓ Names security-relevant behavior explicitly
Why it was queued
signing boundaryfuzzing or regression evidencesigning or wallet path
AI analysis · Informational 24/100

This commit fixes bugs in a test-data generator used by LND, not in the live Lightning node software itself. The generator produces sample HTLC (multi-hop payment) resolution transactions and signatures that other implementations use to cross-check compatibility. The old code paired signatures with the wrong transactions when HTLC outputs were not ordered 'incoming first,' and it also read preimages from the wrong witness slot using a hardcoded byte offset. These bugs caused invalid test vectors, which another implementation (Eclair) noticed during cross-validation. The fix only changes test code, so it does not create or close a real attack path against running LND nodes.

Security candidatelnwallet: use BIP-340 nonce derivation for HTLC sigs in test vectorsby Olaoluwa Osuntokun · 63450b85 · Apr 13, 2026 · 1 fileMessage 88 · StrongInformational 19Details
Commit message · Olaoluwa Osuntokun

lnwallet: use BIP-340 nonce derivation for HTLC sigs in test vectors

btcd's schnorr.Sign defaults to RFC6979 nonce derivation, while
libsecp256k1 (used by eclair, CLN, etc) uses BIP-340's standard
nonce derivation with zero auxrand. Both are deterministic but produce
different signatures for the same key and message, causing HTLC
signature mismatches in interop test vectors.

This commit introduces a bip340Signer wrapper that overrides
SignOutputRaw for taproot script path spends to use
schnorr.CustomNonce([32]byte{}) — matching BIP-340 deterministic
signing behavior. The wrapper is only used in the test vector
generator; production signing paths are unchanged.

Note that MuSig2 commitment signatures were already using BIP-340
nonces internally (via the musig2.Sign path), so only the HTLC
second-level transaction signatures were affected.

88/100 · StrongMessage clarity
✓ Specific, descriptive subject✓ Names a concrete action or component✓ Provides detailed explanatory context✓ Mentions testing or verification✓ Names security-relevant behavior explicitly
Why it was queued
signing boundaryfuzzing or regression evidencesigning or wallet path
AI analysis · Informational 19/100

This commit changes only a test file in LND. It makes the test-vector generator produce HTLC signatures using the same nonce math as other Lightning implementations (Eclair, Core Lightning), so cross-implementation test vectors match. Production signing code is not touched, so real user funds or network behavior are unaffected. There is no security vulnerability being fixed here; it is a test-infrastructure consistency change.

Security candidatelnwallet: regenerate taproot channel test vectorsby Olaoluwa Osuntokun · 70f189ff · Apr 13, 2026 · 1 fileMessage 78 · AdequateInformational 18Details
Commit message · Olaoluwa Osuntokun

lnwallet: regenerate taproot channel test vectors

Regenerate `test_vectors_taproot.json` to reflect the corrected test
vector generator. Changes include actual 32-byte MuSig2 partial
signatures (replacing the dummy 8-byte DER stubs), 66-byte public
nonces for both local and remote parties, corrected HTLC sig-to-
transaction mapping sorted by BIP 69 output index, proper HTLC-success
witness layout with preimage in the correct witness slot, and the
updated trimming test case which now trims 3 of the 5 test HTLCs below
the 2500 sat dust limit (down from 5 HTLC outputs to 2).

78/100 · AdequateMessage clarity
✓ Descriptive subject✓ Names a concrete action or component✓ Provides detailed explanatory context✓ Mentions testing or verification
Why it was queued
signing boundaryfuzzing or regression evidencesigning or wallet path
AI analysis · Informational 18/100

This commit only updates a single JSON file of test vectors for taproot Lightning channels. It replaces placeholder signature data with realistic values, fixes the order of test transactions, and adjusts a dust-limit test case. There is no change to production wallet or node code, so it does not directly affect live funds or network security. It is essentially a correction to the project's test fixtures.

Lower-priorityitest: extend watchtower breach test to cover production taproot channelsby Olaoluwa Osuntokun · 086f6927 · Apr 13, 2026 · 1 fileMessage 83 · StrongTriage 0Details
Commit message · Olaoluwa Osuntokun

itest: extend watchtower breach test to cover production taproot channels

Add SIMPLE_TAPROOT_FINAL to the watchtower revoked close retribution
test matrix. This exercises the new FlagTaprootFinalChannel blob type
and ensures the watchtower correctly constructs justice transactions
using production taproot scripts with OP_CHECKSIGVERIFY.

83/100 · StrongMessage clarity
✓ Specific, descriptive subject✓ Names a concrete action or component✓ Provides detailed explanatory context✓ Mentions testing or verification
Security candidatelnwallet: regenerate taproot test vectors with secret noncesby Olaoluwa Osuntokun · 50981dfc · Apr 13, 2026 · 1 fileMessage 83 · StrongInformational 12Details
Commit message · Olaoluwa Osuntokun

lnwallet: regenerate taproot test vectors with secret nonces

Regenerate the test vectors JSON to include local_sec_nonce and
remote_sec_nonce fields alongside the existing public nonces. The local
nonce fields now correctly correspond to local's verification nonce for
their own commitment transaction, matching the commitment tx stored in
the test vector.

83/100 · StrongMessage clarity
✓ Specific, descriptive subject✓ Names a concrete action or component✓ Provides detailed explanatory context✓ Mentions testing or verification
Why it was queued
defensive validationfuzzing or regression evidencenonce handlingsigning or wallet path
AI analysis · Informational 12/100

This commit only updates test data in a JSON file used for automated tests of Lightning's new taproot channel features. It adds secret nonce values and corrects public nonce values so the test vectors match the expected commitment transactions. There is no change to production wallet or network code, so it does not introduce a security vulnerability or fix one in running software.

Security candidatelnwallet: emit actual MuSig2 partial sigs and nonces in test vectorsby Olaoluwa Osuntokun · fa97946f · Apr 13, 2026 · 1 fileMessage 88 · StrongInformational 18Details
Commit message · Olaoluwa Osuntokun

lnwallet: emit actual MuSig2 partial sigs and nonces in test vectors

In this commit, we fix the taproot test vector generator to capture and
emit the real MuSig2 partial signatures and public nonces rather than
the dummy `CommitSig` value which is zeroed out for taproot channels.

Previously, the generator was reading from `CommitSig.ToSignatureBytes()`
which yielded a minimal DER encoding of `(0, 0)` (the 8-byte string
`3006020100020100`). For taproot channels the actual signature lives in
the `PartialSig` field of the `CommitSigs` struct, which carries both
the 32-byte partial sig scalar and the 66-byte compressed public nonce
needed by the verifier to reconstruct the combined signature.

We now unwrap the `PartialSig` from both the local and remote commitment
signatures, extract the nonce and sig bytes, and include `local_nonce`
and `remote_nonce` fields alongside `remote_partial_sig` in the emitted
JSON. This gives other implementations (eclair, CLN, etc.) all the
material they need to independently verify commitment transaction
signatures using their own MuSig2 libraries.

88/100 · StrongMessage clarity
✓ Specific, descriptive subject✓ Names a concrete action or component✓ Provides detailed explanatory context✓ Mentions testing or verification✓ Names security-relevant behavior explicitly
Why it was queued
signing boundaryfuzzing or regression evidencesigning or wallet path
AI analysis · Informational 18/100

This commit fixes a test-data generator used by the LND Lightning node. Previously, the generator wrote a placeholder zero-value signature into its JSON test vectors for Taproot channels. Now it writes the real partial signature and public nonce values that other Lightning implementations need to independently check those test vectors. This is a test tooling fix, not a live security bug in production code.

AI review queuedmulti: use feature bits to pick which taproot nonce field to useby Olaoluwa Osuntokun · 5ffcd823 · Apr 13, 2026 · 6 filesMessage 73 · AdequateLow 35Details
Commit message · Olaoluwa Osuntokun

multi: use feature bits to pick which taproot nonce field to use

Before this commit, we'd _always_ set both nonces fields, for both the
staging and the final taproot channels type.

With this commit, we've switched to only setting the new nonce map field
for the final taproot feature bit type.

73/100 · AdequateMessage clarity
✓ Specific, descriptive subject✓ Names a concrete action or component✓ Provides detailed explanatory context
Why it was queued
signing or wallet pathsecond-pass: broader security terminologysecond-pass: security-sensitive path
AI analysis · Low 35/100

This commit changes how Lightning taproot channels send cryptographic nonces during channel recovery and revocation. Previously, both an old single-nonce field and a new map-of-nonces field were always sent. Now, only one is sent depending on whether the channel is a 'staging' or 'final' taproot channel type. This is a protocol-correctness and compatibility change, not a clear security bug fix, though it reduces ambiguity in peer communication.

AI review queuedwatchtower: add production taproot channel support to justice kitby Olaoluwa Osuntokun · 7a18fba6 · Apr 13, 2026 · 10 filesMessage 73 · AdequateModerate 54Details
Commit message · Olaoluwa Osuntokun

watchtower: add production taproot channel support to justice kit

Wire channel type through BreachRetribution and the watchtower blob
system to support production taproot channels with final scripts.

The key changes are:

1. Add ChanType field to BreachRetribution so downstream consumers
(including the watchtower) can determine the script variant.

2. Add FlagTaprootFinalChannel blob type flag and
TypeAltruistTaprootFinalCommit blob type to distinguish production
from staging taproot channels in watchtower backups.

3. Add TaprootFinalCommitment to the watchtower's CommitmentType enum
with appropriate witness type and size mappings.

4. Update taprootJusticeKit to use WithProdScripts() when constructing
script trees for production taproot channels. The isFinal flag is
set during construction from BreachRetribution.ChanType and during
deserialization from the blob's commitment type.

Without this change, the watchtower would construct justice transactions
using staging scripts for production taproot channels, resulting in
invalid witnesses that fail to sweep breached outputs.

73/100 · AdequateMessage clarity
✓ Specific, descriptive subject✓ Names a concrete action or component✓ Provides detailed explanatory context
Why it was queued
signing or wallet pathsecond-pass: broader security terminologysecond-pass: security-sensitive path
AI analysis · Moderate 54/100

This commit fixes a bug in LND's watchtower (a service that helps recover funds if a channel partner tries to cheat) so it correctly handles production taproot channels. Before this fix, the watchtower would use the wrong script variant when building recovery transactions, producing invalid transactions that could not actually sweep the breached funds. The change wires the channel type through several internal data structures and adds a new blob type for final/production taproot channels. A small related change also makes the RBF cooperative close protocol use the current block height instead of a fixed height at startup, and forces RBF cooperative close to be enabled whenever taproot channels are enabled.

AI review queuedmulti: fix linter issuesby Olaoluwa Osuntokun · 890636a1 · Apr 13, 2026 · 6 filesMessage 51 · ThinInformational 15Details
Commit message · Olaoluwa Osuntokun

multi: fix linter issues

Fix gci (extra blank lines) and ll (line length > 80 chars) issues
across contractcourt, input, and watchtower packages.

51/100 · ThinMessage clarity
✓ Subject identifies a change✓ Provides detailed explanatory context
Why it was queued
signing or wallet pathsecond-pass: security-sensitive path
AI analysis · Informational 15/100

This commit is purely a code cleanup: it removes extra blank lines, shortens lines that were too long, and adds linter suppression comments where needed. There are no functional changes to the program's behavior, so it does not fix or introduce any security issue.

AI review queuedlnwallet: return error from AggregateNonces in MusigSessionby Olaoluwa Osuntokun · aaf7c294 · Apr 13, 2026 · 1 fileMessage 65 · AdequateLow 33Details
Commit message · Olaoluwa Osuntokun

lnwallet: return error from AggregateNonces in MusigSession

Fix swallowed error in MusigSession.Refresh where AggregateNonces
failure returned nil instead of the actual error.

65/100 · AdequateMessage clarity
✓ Specific, descriptive subject✓ Names a concrete action or component✓ Provides an explanatory body
Why it was queued
signing or wallet pathsecond-pass: security-sensitive path
AI analysis · Low 33/100

This commit fixes a simple but meaningful bug in LND's MuSig2 signing code: when a cryptographic nonce-combining step failed, the function incorrectly swallowed the error and returned 'no error' instead. That could let a signing session continue in a bad state, potentially causing later signature failures or confusing error handling. It is a defensive correctness fix rather than a clear remote-exploitable vulnerability.

AI review queuedlnwallet: fix HTLC trimming test case to use dust_limit for zero-fee HTLCsby Olaoluwa Osuntokun · 745bdc18 · Apr 13, 2026 · 1 fileMessage 95 · StrongInformational 15Details
Commit message · Olaoluwa Osuntokun

lnwallet: fix HTLC trimming test case to use dust_limit for zero-fee HTLCs

In this commit, we fix the "commitment tx with some HTLCs trimmed" test
case to actually exercise trimming for taproot's zero-fee HTLC
transactions.

With zero-fee second-level HTLCs, the HTLC output value on the
commitment transaction equals the HTLC amount directly (no fee is
deducted). This means trimming is determined solely by whether the HTLC
amount falls below the dust limit, not by the fee rate. The previous
parameters (fee_per_kw=100000, dust_limit=546) didn't actually trim any
of the test HTLCs because even the smallest test HTLC (1000 sats) was
above the 546 sat dust limit.

We now use fee_per_kw=644 (a reasonable rate) and dust_limit=2500 to
ensure that the three smallest test HTLCs (1000, 2000, 2000 sats) are
properly trimmed, leaving only the 3000 and 4000 sat HTLCs on the
commitment transaction.

95/100 · StrongMessage clarity
✓ Specific, descriptive subject✓ Names a concrete action or component✓ Provides detailed explanatory context✓ Explains rationale or failure mode✓ Mentions testing or verification
Why it was queued
signing or wallet pathsecond-pass: security-sensitive path
AI analysis · Informational 15/100

This commit only adjusts the numbers used inside a single test case so that the test actually exercises the intended behavior. It does not change any production code, protocol rules, or wallet logic. There is no security issue here.