AI-generated analysisPublished automatically and not human-verified. Validated context appears in community notes below.
← Watch feed
Moderate 55 Bitcoin

Merge bitcoin/bitcoin#34697: descriptor: fix musig() duplicate key checks and doubled PSBT origin paths

Public commit record

What the developer wrote

Authored by merge-script

100/100 · Strong
Merge bitcoin/bitcoin#34697: descriptor: fix musig() duplicate key checks and doubled PSBT origin paths

b42f7fade0cd9a6fb3d69fcdff71436a99ba0005 descriptor: don't prepend key origins twice (Shuvam Pandey)
7b15e2cb442c0bfec76d7d4b9abdd31c7a538da8 descriptor: fix duplicate check for hardened keys (Shuvam Pandey)

Pull request description:

Fixes #34273.

Importing a descriptor that uses the same `musig()` participants twice in one
tapleaf, with different musig subderivations, fails with
`is not sane: contains duplicate public keys`. It only fails when one of the
participants is a private key on a hardened path. The all-xpub version of the
same descriptor imports fine. That's what gave it away.

The duplicate check (`KeyCompare`) resolves each key expression to a pubkey and
compares the results. It does this at index 0, and the old code used an empty
signing provider. With that empty provider, a `musig()` expression can't resolve
when one of its participants is on a hardened path, because deriving that
participant needs its private key, so the whole aggregate key comes back empty.
Two different musig expressions both came back empty, so the check treated them
as duplicates. The fix derives against the signing provider populated during
parsing, which holds the private keys, and only compares the expression strings
when neither side resolves. 151henry151 had suggested looking at the empty
signing provider on the issue.

scgbckbone found a second, separate bug in the same descriptors. When another
expression that reuses those participants is handled in the same expansion, its
participant origin in the PSBT is added twice, so `m/86h/1h/0h` becomes
`m/86h/1h/0h/86h/1h/0h` in both the input and output Taproot BIP32 derivation
maps. `OriginPubkeyProvider::GetPubKey()` now derives into a temporary provider,
merges it, and writes the corrected origin once, so a later expression can't
prepend the same origin again.

Tested:
```
./build/bin/test_bitcoin --run_test=descriptor_tests
./build/bin/test_bitcoin --run_test=miniscript_tests
./build/bin/test_bitcoin --run_test=bip328_tests
./build/bin/test_bitcoin --run_test=psbt_wallet_tests
./build/test/functional/test_runner.py wallet_musig.py --jobs=1
```

ACKs for top commit:
achow101:
ACK b42f7fade0cd9a6fb3d69fcdff71436a99ba0005
scgbckbone:
ACK b42f7fade0cd9a6fb3d69fcdff71436a99ba0005

Tree-SHA512: ab36caa6bc484fa1fc3289c79e9a3d713278d82f80de478e53e1bdbe645037e07776ac798eba085733abc139c11a9dbf0d3f49d3c0eee9632e4ddf33d2242f92
✓ Specific, 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
The short version

What changed, and why it matters

This Bitcoin Core patch fixes two bugs in how advanced wallet descriptors are parsed and turned into wallet data. First, the code could wrongly reject valid multi-signature setups as 'duplicate keys' when a private key on a hardened derivation path was involved, because it compared empty placeholder keys instead of the real ones. Second, when the same participant key appeared in multiple places in a descriptor, the wallet could double-prefix its BIP32 origin path in PSBT data (for example turning m/86h/1h/0h into m/86h/1h/0h/86h/1h/0h), which could confuse signing devices or wallet software. The patch corrects the duplicate-key comparison to use the real signing provider and prevents the origin path from being prepended more than once.

Recommended action

Review and merge if not already merged; run the added descriptor_tests, miniscript_tests, bip328_tests, psbt_wallet_tests and wallet_musig.py functional tests. Users relying on musig() descriptors with hardened derivation paths or reused participants should upgrade once released. No immediate emergency response is indicated because the bugs cause usability failures and incorrect metadata rather than direct fund loss, but incorrect PSBT origins could affect hardware-signer compatibility.

Security signals we found

01

Descriptor duplicate-key sanity check bypassed by false positive on hardened musig() participants

02

BIP32 origin path doubled in PSBT Taproot derivation maps when key expression reused

03

Fix uses real signing provider instead of dummy provider for key derivation during duplicate check

04

Fix isolates origin derivation in temporary provider and uses insert_or_assign to avoid duplicate origin prepending

05

New unit and functional tests cover hardened-key duplicate detection and single-origin behavior

Risk score

Why this scored 55/100

Our methodology →
Potential impact 18/30
Exploitability 10/25
Stealth signal 8/15
Affected reach 7/15
Confidence 8/10
Evidence quality 4/5
Human-validated context

Community notes

Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.

No validated notes yet.

The AI analysis stands alone for now. Submit a note if you can add evidence or important context.