MuSig2 power - #91
Conversation
7b0dd9f to
f842cae
Compare
2ecd3b6 to
0f809dd
Compare
c524af5 to
66705f3
Compare
|
Fresh rebase after bitcoin#31244 landed. |
|
Added bitcoin#33135 and the latest change to bitcoin#33008 (storing one hmac record per policy and fingerprint combination). |
|
The The fixup commits reflect changes made to the original branches. I'll up the commit history occasionally when one of its dependencies lands. |
|
bitcoin#29675 landed! Waiting for bitcoin#29136 to get a rebase so I can update the stack here. |
c1959d3 to
a42a034
Compare
|
Rebased! bitcoin#32821 and bitcoin#33135 also landed. Down from 67 commits to 44. I haven't had a chance to manually retest the whole flow though. |
a42a034 to
25e66d9
Compare
|
Rebased after bitcoin#32471 landed. Down to 37 commits. |
25e66d9 to
b7bb56e
Compare
b7bb56e to
14c7fce
Compare
14c7fce to
018d066
Compare
018d066 to
cf24e00
Compare
|
Added #110 which (very roughly) implements BIP388 policy support for displaying addresses. |
389caf4 to
9676dcc
Compare
|
Added #111 for signing support. |
684b910 to
6268484
Compare
…nd revamp mock # Conflicts: # test/functional/wallet_signer.py
# Conflicts: # test/functional/wallet_createwalletdescriptor.py
Add an optional Parse() input with extended private keys known to the caller, by their public form, used to fill in the extended public keys of the descriptor as if it contained the private keys. ParseState carries it through the parsers, including Miniscript keys and musig() participants. A key expression with an explicit origin that leads from a known key to its extended public key is replaced by that key and the full derivation path, matching a descriptor that contains the known key. A known extended public key without such an origin keeps its expression and only gains the private key. Known keys do not change the multipath descriptor output.
When importdescriptors is given a descriptor with extended public keys of the wallet's HD keys, or keys with an origin from them, fill in the private keys, so that such descriptors can be imported into wallets with private keys enabled.
262b3e5 to
c71602f
Compare
|
Refreshed the stack. bitcoin#36133 is the most useful to (conceptually) review, because once multipath support lands, I can spin off PRs for |
bitcoin#33112 tests walletdisplayaddress for an imported external-signer descriptor using the same xpub as a wallet exercised earlier in wallet_signer.py. bitcoin#36114 then revamps the shared external signer mock used by the test. With #127, the imported descriptor's known HD keys are filled immediately, so its first address is recognized as used and the wallet advances to the next index, which the mock intentionally maps to wrong_address for a separate error case. Let the test configure the address echoed by the mock so it remains independent of the derived index while preserving the mismatched-address coverage.
Use the multipath descriptor record kept by the wallet for external signer registration. This avoids reconstructing the original BIP 389 descriptor from its expanded receive and change descriptors.
c71602f to
f1a2249
Compare
Exercise descriptor registration and registered address display with a tr(musig(...)) wallet. The mock validates the opaque registration and the derived address, including rejection of an incorrect signer response.
Multi-round signing flows like MuSig2 take two passes: round 1 exchanges public nonces, round 2 produces partial signatures. A single FillPSBT(sign=true) call therefore can never complete a fresh MuSig2 spend -- the user has to feed the round-1 PSBT back into FillPSBT a second time. The 'send' RPC, the GUI's send-coins dialog, the GUI's PSBT-operations dialog, and the bumpfee path all suffer from this: each makes a single sign call and returns the round-1 PSBT to the user. Hoist the second-pass logic into CWallet::FillPSBT itself so every caller benefits without code duplication. After the first pass leaves the PSBT incomplete, do a structural check: every input that participates in a MuSig2 session must already have a complete set of pub nonces from every expected participant. If so, run the same pass again on a copy; on success adopt it, on failure preserve the round-1 result so the caller can ferry the PSBT out-of-band as before. Skipped for non-MuSig2 PSBTs (no participants entries) and for MuSig2 PSBTs where some cosigner's nonces are still missing, so we don't issue an unnecessary device-confirmation prompt. Note: PSBT_IN_MUSIG2_PARTICIPANT_PUBKEYS entries can't be paired to PSBT_IN_MUSIG2_PUB_NONCE entries by aggregate pubkey -- the former stores the pre-tweak aggregate while the latter stores the post-tweak one (after BIP32 derivations and the BIP86 taproot tweak). The structural check sidesteps that. Refactor the existing one-pass body into a fill_pass lambda so both rounds share it.
Drive registered MuSig2 signing through both nonce and partial-signature rounds, and cover structured external-signer failures. The mock delegates to real wallets to produce valid contributions so the result can be finalized and broadcast.
RunCommandParseJSON throws when the signer subprocess exits non-zero, for example after a device disconnect. Fold that exception into the same PSBTError::EXTERNAL_SIGNER_FAILED path used for a structured signer error, and cover both paths with the MuSig2 signer mock.
Treat a signer failure as soft when the local pass adds a MuSig2 pubnonce or partial signature. This preserves the matching secret nonce and lets a later walletprocesspsbt resume after the device returns. Keep failures hard when the local pass made no progress, avoiding silent no-op success.
Enumerate every connected signer for descriptor registration and signing, storing one opaque registration per fingerprint. Registered address display uses the first matching signer. Cover a two-device MuSig2 wallet that registers both devices and completes signing in one call.
f1a2249 to
e036107
Compare
Combines the following:
It then introduces:
registerdescriptorcommandThe MuSig2-specific commits integrate with
bitcoin-core/HWI#794.
The general workflow is:
tr(musig(...)/<0;1>/*)descriptor;bitcoin-cli -rpcwallet=<wallet> registerdescriptor "MuSig wallet";walletdisplayaddress;sendcall.Bitcoin Core performs both MuSig2 signing rounds in-process. It collects public
nonces, retries signing once the nonce set is complete, collects partial
signatures, aggregates the final Schnorr signature, and broadcasts.
Descriptor registration and registered signing are fanned out to all connected
external signers. This supports wallets whose MuSig2 participants live on
multiple hardware devices. Registrations can be inspected through
getwalletinfo.external_signer_registrations.If a signer fails after a local MuSig2 contribution was added, the returned
PSBT preserves that contribution so signing can be resumed later.
Tests:
The HWI end-to-end test also exercises this branch against the Ledger Bitcoin
app under Speculos: descriptor registration, address display, funding, both
MuSig2 signing rounds, broadcast, and confirmation.