bip360: depth-zero script trees should be anyone-can-spend #2198

pull conduition wants to merge 4 commits into bitcoin:master from conduition:360/depth-zero-ban changing 1 files +29 −12
  1. conduition commented at 3:30 PM on June 13, 2026: contributor

    This PR changes the validation rules of BIP360 to ~prevent users from spending~ add an auto-success path for script trees of depth zero - those with a single leaf script. By doing so, we discourage use of depth-zero script trees: anyone who uses them will lose their money to miners.

    This change is motivated by constructive critiques of P2MR which highlight the regressive use-cases that depth-zero script trees seem to incentivize.

    https://groups.google.com/g/bitcoindev/c/p8AVEmAtWdA

    Specifically, depth-zero script trees disincentivize the use of a PQ script. With depth-zero script trees in play, users may have incentive to omit a PQ leaf script from their P2MR address to save 32 bytes of witness data when spending with Schnorr. We also must consider the same incentive for multi-party transaction protocol authors, who may be incentivized to omit a cooperative leaf script to save 32 bytes off the witness of the non-cooperative script.

    After this change, P2MR's privacy profile is much more well aligned with that of P2TR: Every P2MR user must pay for at least two spending paths anyway, so it encourages everyone to make use of both of them if possible/applicable, whether for cooperative spending path or for a PQ leaf. We thus create ambiguity to on-chain observers: is this a cooperative spend of a multi-party protocol? or just a single-signer wallet with a sibling PQ leaf script?

    If depth-zero script trees are anyone-can-spend, this still leaves it open to future use in a later soft-fork. For example, if we someday have enough confidence to deploy isogenies, we can use taproot-style key tweaking with isogenies to hide a commitment to a script tree inside an isogeny-based pubkey, and put that pubkey in the P2MR "script" stack element, allowing a kind of key-spending with isogenies with a hidden script tree fallback. Other options abound.

    Thanks to @EthanHeilman for his suggestion to make this change reversible through an auto-success path. The first version of this PR implemented a straight-up ban on depth-zero script trees.

  2. bip360: disallow depth-zero script trees in P2MR
    This changes the validation rules of BIP360 to prevent users
    from spending script trees of depth zero - those with
    a single leaf script.
    
    This change is motivated by constructive critiques of P2MR which
    highlight the regressive use-cases which depth-zero script trees
    seem to incentivize.
    
    https://groups.google.com/g/bitcoindev/c/p8AVEmAtWdA
    
    This specifically includes disincentivizing the use of a PQ script.
    With depth-zero script trees in play, users may have incentive to
    omit a PQ leaf script from their P2MR address to save 32 bytes of
    witness data when spending with Schnorr.
    
    We also must consider the same incentive for multi-party transaction
    protocol authors, who may be incentivized to omit a cooperative
    leaf script to save 32 bytes off the witness of the non-cooperative script.
    
    After this change, P2MR's privacy profile is much more well aligned
    with that of P2TR: Every user must pay for at least two spending
    paths anyway, so it encourages everyone to make use of both of them
    if possible/applicable, whether for cooperative spending path or
    for a PQ leaf. We thus create ambiguity to on-chain observers:
    is this a cooperative spend of a multi-party protocol? or just a
    single-signer wallet with a sibling PQ leaf script?
    24e28ddc63
  3. conduition commented at 3:45 PM on June 13, 2026: contributor

    I have not edited the reference implementations, as they seem to live in third-party repositories.

  4. jonatack added the label Proposed BIP modification on Jun 13, 2026
  5. jonatack added the label Pending acceptance on Jun 13, 2026
  6. jonatack commented at 5:41 PM on June 13, 2026: member

    cc @cryptoquick @EthanHeilman @Isabelfoxenduke for feedback or sign-off

  7. EthanHeilman commented at 9:00 PM on June 13, 2026: contributor

    @jonatack I like how this incentivizes privacy and the cost of an additional 32-bytes seems worth it. The only drawback I think of is that the script tree has slightly different behavior between P2MR and P2TR. A script tree of depth 0 that works for P2TR would fail for P2MR. @conduition I do wonder if perhaps it might make sense to have a 0-depth leaf be an OP_SUCCESS rather than a fail. This way we can preserve 0-depth leaf trees as a soft fork mechanism and if someone does put funds into such a tree, they will be able to spend them (as will anyone else).

    I had a related idea. From my perspective the main privacy advantage of P2TR that the key spend doesn't use a script and by not using a script you prevent a source of wallet fingerprinting. One could replicate this behavior in P2MR by having the first leaf always be a single public key. If we have alg flagging for public keys, then a single public key would be interpreted as run CHECKSIG_VERIFY on this public key for the alg specified in the flag. This would then make P2MR identical in privacy to P2TR.

    All said, I have no strong objection to this change, but I need to catch up on the devlist discussion of this point.

  8. conduition commented at 1:04 AM on June 15, 2026: contributor

    perhaps it might make sense to have a 0-depth leaf be an OP_SUCCESS rather than a fail

    Brilliant idea. This leaves it much more open-ended so P2MR could potentially be reused for something else exciting in the future, e.g. isogeny key tweaking, something with lattices, etc. I'll see about making this change in the next few days

    One could replicate this behavior in P2MR by having the first leaf always be a single public key

    Could work for today, but then what do we do after Q-day? With Schnorr we can do multisig, threshold, etc, so having a single-pubkey as the default (mandated) spend path is reasonable, but not so with hash-based sigs where you'd need an explicit multisignature script, threshold script, etc.

  9. EthanHeilman commented at 2:07 AM on June 15, 2026: contributor

    Could work for today, but then what do we do after Q-day? With Schnorr we can do multisig, threshold, etc, so having a single-pubkey as the default (mandated) spend path is reasonable, but not so with hash-based sigs where you'd need an explicit multisignature script, threshold script, etc.

    You could do:

    • Single pubkey in leaf means CHECKSIG
    • Multiple pubkey in leaf means MULTISIG
    • Multiple pubkey and number in leaf means MULTISIG of N

    I'm not big fan of inferring the script based on number of public keys because you leak if something is a multisig or not. Better to do a script like you are proposing.

    We could enforce single pubkey with the expectation that we will figure out a way to do aggregation for any signature algorithm we add.

  10. depth zero trees should be anyone-can-spend 35ee070a9a
  11. conduition renamed this:
    bip360: disallow depth-zero script trees in P2MR
    bip360: depth-zero script trees should be anyone-can-spend
    on Jun 15, 2026
  12. conduition commented at 3:05 PM on June 15, 2026: contributor

    I applied Ethan's idea to make depth-zero script trees an anyone-can-spend path and updated the PR description/title. Note the auto-success path occurs after the P2MR commitment opening is validated (i.e. after validating $k_m = q$), so it cannot be gamed by a spender.

    I like how this incentivizes privacy and the cost of an additional 32-bytes seems worth it

    Small note on this: adding a minimum depth won't affect witness size for a majority of P2MR use-cases because almost everyone using P2MR will be doing so for quantum-security. I think the most common use-case this might affect would be addresses who want no standalone EC keys in their script tree at all, e.g. a pure PQC script, or an EC+PQC hybrid script. But for such use-cases, 32 bytes of extra witness data would be a relatively minor handicap due to the size of most PQ signatures.

  13. cryptoquick commented at 8:35 PM on June 18, 2026: contributor

    Good, thoughtful changes. Happy to also make sure they are supported in P2MRv2 and also reflected in Rust and Python test vectors.

  14. jonatack removed the label Pending acceptance on Jun 18, 2026
  15. fix unnecessary "to" typo
    Co-authored-by: Jon Atack <jon@atack.com>
    64b0b326e3
  16. in bip-0360.mediawiki:171 in 35ee070a9a
     167 | @@ -166,6 +168,8 @@ Importantly, we are proposing a script tree output, i.e. an output type that sup
     168 |  
     169 |  P2WSH, for instance, does not support tapscript and as such does not support the OP_SUCCESSx opcode update path that will be critical for the integration of post-quantum OP_CHECKSIG opcodes into Bitcoin.<ref><code>OP_SUCCESSx</code> is a mechanism to upgrade tapscript</ref>
     170 |  
     171 | +P2MR encourages script trees of depth 1 or more, to so that P2MR addresses contain at least two spending paths, even if one is not used. This is intended to incentivize the use of a post-quantum-secure leaf script once available, and to better align P2MR's privacy profile with P2TR.
    


    jonatack commented at 9:33 PM on June 18, 2026:

    Extraneous word? Or perhaps another expression was intended.

    P2MR encourages script trees of depth 1 or more, so that P2MR addresses contain at least two spending paths, even if one is not used. This is intended to incentivize the use of a post-quantum-secure leaf script once available, and to better align P2MR's privacy profile with P2TR.
    

    conduition commented at 9:35 PM on June 18, 2026:

    thanks!

  17. in bip-0360.mediawiki:252 in 64b0b326e3 outdated
     248 | @@ -234,13 +249,15 @@ A P2MR output is a native SegWit output (see [[bip-0141.mediawiki|BIP 141]]) wit
     249 |  **** If ''k<sub>j</sub> &ge; e<sub>j</sub>'': ''k<sub>j+1</sub> = hash<sub>TapBranch</sub>(e<sub>j</sub> || k<sub>j</sub>)''.
     250 |  ** Let ''r = k<sub>m</sub>''.
     251 |  ** If ''q &ne; r'', fail.
     252 | +** If ''m = 0'', succeed immediately.
    


    jonatack commented at 9:52 PM on June 18, 2026:

    Has m been defined before this line?

    (I do see a definition in line 296 below: "where m is the depth of the leaf script.")


    conduition commented at 9:53 PM on June 18, 2026:

    Yep, up at L242:

    The last stack element is called the control block ''c'', and must have length ''1 + 32 * m'', for a value of ''m'' that is an integer between 0 and 128, inclusive. Fail if it does not have such a length.


    conduition commented at 9:54 PM on June 18, 2026:

    I could make it more explicit:

    ** If ''len(c) = 1'', succeed immediately.
    

    jonatack commented at 9:55 PM on June 18, 2026:

    Thanks! I overlooked it.


    jonatack commented at 10:02 PM on June 18, 2026:

    I think the line containing the following would be clearer if it was a Let statement (or 2 Let statements for c and m on separate lines if m is kept). But it's only a nit.

    The last stack element is called the control block ''c'', and must have length ''1 + 32 * m'', for a value of ''m'' that is an integer between 0 and 128, inclusive.
    
  18. jonatack commented at 10:04 PM on June 18, 2026: member

    Add a changelog entry? (If you do, update also the Version header at the top.)

  19. update BIP360 changelog and version to 0.12.0 81ca40ee8e
  20. conduition commented at 12:09 AM on June 19, 2026: contributor

    oh thanks, forgot that. Now done.

  21. jonatack commented at 1:12 AM on June 19, 2026: member

    Thanks for adding the changelog (and updating the PR title/description).

  22. jonatack merged this on Jun 19, 2026
  23. jonatack closed this on Jun 19, 2026

  24. conduition deleted the branch on Jun 19, 2026

github-metadata-mirror

This is a metadata mirror of the GitHub repository bitcoin/bips. This site is not affiliated with GitHub. Content is generated from a GitHub metadata backup.
generated: 2026-07-08 15:10 UTC

This site is hosted by @0xB10C
More mirrored repositories can be found on mirror.b10c.me