Merge pull request #10974 from SomberNight/202609_nostr_psbt_xpub
What changed, and why it matters
This commit only adds a long code comment explaining a design choice in Electrum's PSBT-over-Nostr plugin. It does not change any program behavior. The comment documents that the plugin derives each cosigner's Nostr secret key from their Bitcoin extended public key (xpub), which means every cosigner can also compute every other cosigner's secret key. The developers explicitly call this an accepted tradeoff because the only shared cryptographic material among cosigners is the xpubs, and the Nostr keys are only used to exchange proposed transaction drafts (PSBTs). No vulnerability is introduced or fixed by this change.
No action required. Reviewers may want to evaluate whether the documented tradeoff is acceptable for their threat model, but the commit itself is purely informational.
Security signals we found
Documentation-only change
Explicit design tradeoff disclosure: cosigners can derive each other's Nostr secret keys from shared xpubs
No functional code change
Evidence from the diff
The diff adds an 11-line comment block in electrum/plugins/psbt_nostr/psbt_nostr.py before the existing loop that derives a Nostr key from each keystore’s xpub. The comment explains why the xpub is used as the basis for the nsec: non-interactive discoverability of npubs among cosigners, compatibility with hardware signers that cannot export arbitrary private keys but can perform ECDH, and the low sensitivity of keys that only sign/encrypt PSBT proposal messages. It explicitly notes the drawback (all cosigners know each other’s nsec) and the assumption that outsiders do not know the multisig xpubs. No executable code is modified.
Changed components
electrum/plugins/psbt_nostr/psbt_nostr.pyInspect captured patch +13 / −0
### electrum/plugins/psbt_nostr/psbt_nostr.py
@@ -105,6 +105,19 @@ def __init__(self, wallet: 'Multisig_Wallet', db_storage: dict):
self.nostr_pubkey = None
for keystore in wallet.get_keystores():
+ # design question: how do we select our nsec/npub for communicating with our cosigners?
+ # - We want a scheme where every cosigner can *non-interactively* figure out
+ # each other's *npub*. The only cryptographic material we have shared amongst the cosigners
+ # is the set of xpubs (~output script descriptors).
+ # - Cosigners might be using hardware signers that do not allow arbitrary access to the
+ # private keys corresponding to their xpub, and they need to be able to do ECDH
+ # with their nostr key to encrypt/decrypt nostr DMs.
+ # - The keys are not *that* sensitive: they only allow sending proposed PSBTs to cosigners.
+ # Hence we construct the nostr secret key for each cosigner based on their xpub.
+ # - drawback: each cosigner knows not only the *npub* but also the *nsec* for each other.
+ # This is an accepted tradeoff. One cosigner "impersonating" another is accepted.
+ # - assumption: people other than the multisig participants are unlikely to know the xpubs
+ # participating in the multisig.
# note: there should be domain separation between testnet/mainnet.
# Currently there is, due to the xpub str encoding it in its header.
xpub = keystore.get_master_public_key() # type: strWhy this scored 15/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.