lnwallet: emit actual MuSig2 partial sigs and nonces in test vectors
What changed, and why it matters
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.
No production action required. Reviewers may want to confirm the generated test vectors are now accepted by downstream implementations and that the PartialSig unwrap cannot fail silently in the test path.
Security signals we found
Fixes incorrect test vector data for Taproot/MuSig2 channel signatures
Improves cross-implementation test coverage (eclair, CLN, etc.)
No change to production signing, verification, or consensus paths
Evidence from the diff
The change is confined to lnwallet/taproot_test_vectors_test.go. The test vector generator now extracts local and remote MuSig2 partial signatures and nonces from CommitSigs.PartialSig instead of using CommitSig.ToSignatureBytes(), which for Taproot channels returns a minimal DER encoding of (0,0). The emitted JSON gains local_nonce and remote_nonce fields and remote_partial_sig now contains the actual 32-byte scalar. This improves the fidelity of interoperability test vectors but does not alter consensus, wallet, or network behavior.
Changed components
lnwallet/taproot_test_vectors_test.goInspect captured patch +18 / −3
diff --git a/lnwallet/taproot_test_vectors_test.go b/lnwallet/taproot_test_vectors_test.go
index a6894de..ecbb126 100644
--- a/lnwallet/taproot_test_vectors_test.go
+++ b/lnwallet/taproot_test_vectors_test.go
@@ -264,6 +264,8 @@ type TransactionTestCase struct {
FeePerKw int64 `json:"fee_per_kw"`
DustLimitSatoshis int64 `json:"dust_limit_satoshis,omitempty"`
Htlcs []HtlcInput `json:"htlcs"`
+ LocalNonce string `json:"local_nonce"`
+ RemoteNonce string `json:"remote_nonce"`
RemotePartialSig string `json:"remote_partial_sig"`
ExpectedCommitmentTxHex string `json:"expected_commitment_tx_hex"`
HtlcDescs []HtlcDesc `json:"htlc_descs"`
@@ -948,6 +950,12 @@ func (tc *taprootTestContext) generateTransactionVectors() []TransactionTestCase
localNewCommit, err := localChannel.SignNextCommitment(ctxb)
require.NoError(t, err)
+ // Capture the local nonce from the local commitment sig.
+ localPartialSig := localNewCommit.PartialSig.UnwrapOrFailV(t)
+ localNonceHex := hex.EncodeToString(
+ localPartialSig.Nonce[:],
+ )
+
err = remoteChannel.ReceiveNewCommitment(
localNewCommit.CommitSigs,
)
@@ -962,9 +970,14 @@ func (tc *taprootTestContext) generateTransactionVectors() []TransactionTestCase
remoteNewCommit, err := remoteChannel.SignNextCommitment(ctxb)
require.NoError(t, err)
- // Capture remote partial signature.
- remoteSigHex := hex.EncodeToString(
- remoteNewCommit.CommitSig.ToSignatureBytes(),
+ // Capture the remote partial signature and nonce from the
+ // musig2 partial sig (not CommitSig which is zero for
+ // taproot channels).
+ remotePartialSig := remoteNewCommit.PartialSig.UnwrapOrFailV(t)
+ sigBytes := remotePartialSig.Sig.Bytes()
+ remoteSigHex := hex.EncodeToString(sigBytes[:])
+ remoteNonceHex := hex.EncodeToString(
+ remotePartialSig.Nonce[:],
)
err = localChannel.ReceiveNewCommitment(
@@ -1064,6 +1077,8 @@ func (tc *taprootTestContext) generateTransactionVectors() []TransactionTestCase
RemoteBalanceMsat: uint64(testCase.remoteBalance),
FeePerKw: int64(testCase.feePerKw),
Htlcs: htlcInputs,
+ LocalNonce: localNonceHex,
+ RemoteNonce: remoteNonceHex,
RemotePartialSig: remoteSigHex,
ExpectedCommitmentTxHex: hex.EncodeToString(txBytes.Bytes()),
HtlcDescs: htlcDescs,
Why this scored 18/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.