Why does a MuSig2 partial signature pass local verification but get rejected by mempool — BIP341 double-tweak with python-bitcoinutils?
Why does a MuSig2 partial signature pass local verification but get rejected by mempool — BIP341 double-tweak with python-bitcoinutils?
Loading saved threads...
Aaron Zhang · External communityPost link
External question — Bitcoin Stack Exchange
Author: Aaron Zhang
Original post: https://bitcoin.stackexchange.com/questions/130657
License: CC BY-SA 4.0 — https://creativecommons.org/licenses/by-sa/4.0/
Adaptation: HTML converted to plain text; contact email addresses removed.
I implemented a MuSig2 cooperative close for a Taproot Lightning channel on testnet. Local signature verification passed, but the transaction was rejected by Bitcoin Core's mempool.
I first suspected the nonce aggregation was wrong, then thought it might be a sighash mismatch — printed the raw bytes on both sides, identical. Eventually I dumped the actual output key from the library versus what I had in my SessionContext. They were different. That's when I realized the issue was related to BIP86 tweaks.
Has anyone run into this?
Quote
Report
Aaron Zhang · External communityPost link
External answer — Bitcoin Stack Exchange
Author: Aaron Zhang
Original post: https://bitcoin.stackexchange.com/a/130658
License: CC BY-SA 4.0 — https://creativecommons.org/licenses/by-sa/4.0/
Adaptation: HTML converted to plain text; contact email addresses removed.
The problem is a double tweak.
python-bitcoinutils applies a BIP86 tweak internally when you call get_taproot_address(). If you have already applied a BIP86 tweak manually to the aggregate key, the on-chain output key has been tweaked twice.
Local schnorr_verify passes because it checks against the key you provide — it does not know what is actually on-chain. Bitcoin Core checks against the real output key, which has two tweaks applied. The signature built with only one tweak is invalid against that key.
The fix: SessionContext must carry both tweaks explicitly:
pythonsession_ctx = SessionContext(
aggnonce, pubkeys,
[tweak1, tweak2], # both tweaks required
[True, True],
msg
)
This is not a bug — the library handles BIP86 automatically for typical single-key use. In MuSig2, where you manage tweaks manually, the abstraction leaks.
Verified on testnet:
af6fdae8...9d1f
Quote
Report
Post Reply
Quoted from Forex.com.bd-Editorial External question — Bitcoin Stack Exchange Author: Aaron Zhang Source score (net votes, not local likes): 0 Original post: https://bitcoin.stackexchange.com/questions/130657 License: CC BY-SA 4.0 — https://creativecommons.org/licenses/by-sa/4.0/ Adaptation: HTML converted to plain text; contact email addresses removed. I implemented a MuSig2 cooperative close for a Taproot Lightning channel on testnet. Local signature verification passed, but the transaction was rejected by Bitcoin Core's mempool. I first suspected the nonce aggregation was wrong, then thought it might be a sighash mismatch — printed the raw bytes on both sides, identical. Eventually I dumped the actual output key from the library versus what I had in my SessionContext. They were different. That's when I realized the issue was related to BIP86 tweaks. Has anyone run into this?
Checking account access…