BIP-375: correct labeled test vectors to include labeled-spend key in PSBT_OUT_SP_V0_INFO #2207

pull macgyver13 wants to merge 2 commits into bitcoin:master from macgyver13:bip375-labeled-spend changing 3 files +39 −27
  1. macgyver13 commented at 3:46 PM on July 7, 2026: contributor

    Includes two changes to align the labeled test vectors and validation reference with BIP-375:

    • Sort silent payment codes lexicographically then by output index before assigning k values.
    • PSBT_OUT_SP_V0_INFO should carry the labeled-spend public key, not the base-spend public key.

    Changed vectors:

    • can finalize: one P2WPKH input / two mixed outputs - labeled sp output and BIP 32 change
    • can finalize: one input / two sp outputs - output 0 has no label / output 1 uses label=0 convention for sp change
    • can finalize: three sp outputs (same scan key) - output 0 uses label=1, outputs 1 and 2 uses label=2 (same spend key)

    Test Runner Output

    Summary: 43 passed, 0 failed
    
  2. macgyver13 marked this as ready for review on Jul 7, 2026
  3. murchandamus commented at 11:00 PM on July 7, 2026: member

    cc BIP Owners for review: @andrewtoth, @achow101, @josibake

  4. murchandamus added the label Proposed BIP modification on Jul 7, 2026
  5. murchandamus added the label Pending acceptance on Jul 7, 2026
  6. fametrano commented at 5:10 PM on August 14, 2026: contributor

    Implementer's note. btclib has a BIP375 implementation and currently assigns k in output index order, so this PR would change what it derives. Working notes and the full measurement are in https://github.com/btclib-org/btclib/issues/768.

    Measured, in both directions, with bip-0375/test_runner.py on Python 3.12:

    tree result
    master 60f5b33b, unchanged 41 passed, 0 failed
    master, validate_output_scripts patched to assign k by ascending PSBT_OUT_SP_V0_INFO with output index as tie-break 40 passed, 1 failed: valid[8], "two sp outputs - output 0 uses label=3 / output 1 uses label=1"
    master's validator against this PR's vector file 40 passed, 1 failed: "three sp outputs (same scan key) - output 0 uses label=1, outputs 1 and 2 uses label=2"
    this PR at 8f7b632f, both halves 41 passed, 0 failed

    No invalid vector changes verdict under either rule. The two invalid vectors named after ordering do not discriminate between the rules: in invalid[20] the spend keys are already ascending, so index and lexicographic order coincide, and each of the two carries a k assignment no ascending rule produces (the two values swapped in one, three permuted in the other). So the discrepancy is confined to the labeled multi-output vectors, and this PR closes it.

    Two remarks, one per half of the PR.

    The PSBT_OUT_SP_V0_INFO half looks unambiguous — the field should carry the labeled spend key — and is independent of the ordering question.

    On the ordering half, a question about the rule rather than about which artefact is normative. What the rule has to buy appears to be inter-party determinism only: the Signer sets PSBT_OUT_SCRIPT and the Extractor recomputes it, so both must land on the same bytes. Nothing else seems to depend on it — a BIP352 receiver scans by deriving P_k for k = 0, 1, 2 … and matching against the transaction's outputs, so it never learns which output was assigned which k; and permuting k within a scan-key group still pays each recipient the same amount, since an output's script is derived from its own spend key. If that is right, any deterministic rule is equally correct and the choice is a matter of cost, where two things differ:

    • lexicographic order needs a canonical encoding of a "code" and a total order on it. The prose says "sort the codes", which could be the 66-byte PSBT_OUT_SP_V0_INFO, the bech32m address string, or the (scan, spend) pair; this PR picks the first, in code. Output indices need no such definition and are already in the psbt;
    • the property lexicographic order would buy — invariance under output reordering — looks unavailable here: L185 requires a Signer setting a missing PSBT_OUT_SCRIPT to clear the Inputs Modifiable and Outputs Modifiable flags, and a psbt carrying a script with PSBT_GLOBAL_TX_MODIFIABLE non-zero is invalid (invalid[4]). Outputs cannot be reordered once the scripts exist. The tie-break for identical codes is output index in any case.

    So index order looks like the cheaper rule, and it is what all three shipped artefacts did before this PR. That is an argument for amending the two sentences at L240-241 instead, and reducing this PR to its PSBT_OUT_SP_V0_INFO half.

    We have no stake beyond interoperability and will follow whichever way this is settled. If the lexicographic rule is kept, one edit would help: have the prose name the sort key — the serialized PSBT_OUT_SP_V0_INFO, ascending, ties by output index, which is what this PR implements. As written, "the codes" leaves the next implementer the same choice that produced this divergence.

    Unrelated and not touched here, noted while checking the above: L149 says "The PSBT_OUT_SP_V0_INFO should be serialized as a zero byte for the version, followed by the 33 bytes of the scan key and then 33 bytes for the spend key", which names the field, whose table entry at L124 is <33 byte scan key> <33 byte spend key> — 66 bytes, which is what the vectors carry and what the validator requires (invalid[1] reports "wrong length (65 bytes, expected 66)"). Read in its own section the sentence is about the substitute output script used for unique identification, where a version byte prefix contradicts nothing; that is how btclib implemented it. Since the sentence names the field rather than the substitution, one line of disambiguation would help. Glad to send it separately.

    Edited: the last paragraph originally called this an inconsistency about the field's length. In its section it is a question of wording, not a contradiction.

  7. jonatack commented at 9:45 PM on August 14, 2026: member

    @fametrano Thank you for the report. It is a little hard to understand, can you summarize more concisely in your own words, please?

  8. fametrano commented at 2:51 PM on September 7, 2026: contributor

    @jonatack in short: I support the labeled-spend-key half of this PR, it looks right regardless of the ordering question. The sort half is the alternative to #2256, which changes the text to the index order the current validator and vectors already follow; either direction removes the contradiction, and the owners' preference decides which of the two lands. The measurement in both directions is reproducible from the diff posted on #2256.

  9. fametrano referenced this in commit 71074e95e5 on Sep 9, 2026
  10. fametrano commented at 7:27 AM on September 9, 2026: contributor

    Partial nACK, to make my note above explicit: nACK the ordering half, ACK the PSBT_OUT_SP_V0_INFO half.

    ACK the labeled-spend-key fix. Carrying the labeled spend key is correct and is needed whichever ordering rule wins; this half should land.

    nACK the switch to lexicographic ordering. As measured above: the k assignment is invisible to a BIP352 receiver and serves only Signer/Extractor determinism, so any deterministic rule is equally correct and the choice is one of cost. Lexicographic's one advantage — invariance under output reordering — is unavailable here: L185 makes a Signer clear Outputs Modifiable when it sets a script, and invalid[4] rejects a script carried under a non-zero PSBT_GLOBAL_TX_MODIFIABLE, so outputs cannot be reordered once the scripts exist. What is left is cost, and there output index is cheaper: "sort the codes" still needs a canonical encoding and total order that this PR pins only in code, while output index needs no such definition, is already in the psbt, and is the tie-break the lexicographic rule itself already falls back to for identical codes. It is also what the reference validator and the vectors do today, with only the prose dissenting; #2256 aligns the prose with them.

    Could this be two PRs? The two fixes are independent and only the ordering one is contested. Splitting them lets the PSBT_OUT_SP_V0_INFO correction merge now and leaves the ordering direction to the BIP owners on its own. Glad to help either way.

  11. murchandamus requested review from achow101 on Sep 23, 2026
  12. fametrano referenced this in commit 7519f2a4cb on Sep 29, 2026
  13. macgyver13 force-pushed on Sep 29, 2026
  14. macgyver13 commented at 8:54 PM on September 29, 2026: contributor

    Rebased on master to resolve the conflict after #2286 "BIP375: validate PSBT_OUT_SP_V0_LABEL length".

  15. fametrano referenced this in commit 6bc603a073 on Oct 25, 2026
  16. murchandamus commented at 10:13 PM on November 3, 2026: member

    @andrewtoth: Does that look good to you?

  17. jonatack removed the label Proposed BIP modification on Nov 4, 2026
  18. jonatack removed the label Pending acceptance on Nov 4, 2026
  19. jonatack added the label BIP Update by Owner on Nov 4, 2026
  20. jonatack commented at 3:41 AM on November 4, 2026: member

    Updated the labels for the deputization of @macgyver13.

  21. in bip-0375.mediawiki:409 in 9514ecce26 outdated
     405 | @@ -406,6 +406,8 @@ Use the provided [[bip-0375/test_runner.py|test runner]] to validate each test v
     406 |  
     407 |  == Changelog ==
     408 |  
     409 | +* '''0.1.3''' (2026-09-29):
    


    jonatack commented at 3:39 PM on November 4, 2026:

    Please update also in the same commit the Version header on line 13.

  22. in bip-0375.mediawiki:241 in 9514ecce26


    jonatack commented at 3:52 PM on November 4, 2026:

    Would it be useful to describe the sort key in the BIP to avoid ambiguity? for instance

     Compute the PSBT_OUT_SCRIPT using the procedure in [https://github.com/bitcoin/bips/blob/master/bip-0352.mediawiki#creating-outputs BIP352] but substituting ''a·B<sub>scan</sub>'' with the PSBT_GLOBAL_SP_ECDH_SHARE for that scan key if available, or the sum of all PSBT_IN_SP_ECDH_SHAREs from eligible inputs for that scan key.
     If there are multiple silent payment codes with the same scan key, sort the codes lexicographically in ascending order to determine the ordering of the ''k'' value.
    +The sort key is the 66-byte serialized <tt>PSBT_OUT_SP_V0_INFO</tt> (33-byte scan key followed by 33-byte spend key).
     If there are multiple silent payment codes with both the same scan and spend keys, sort the subgroup by output index in ascending order.
     
     ===Transaction Extractor===
    

    or

     ====Computing the Output Scripts====
     
     Compute the PSBT_OUT_SCRIPT using the procedure in [https://github.com/bitcoin/bips/blob/master/bip-0352.mediawiki#creating-outputs BIP352] but substituting ''a·B<sub>scan</sub>'' with the PSBT_GLOBAL_SP_ECDH_SHARE for that scan key if available, or the sum of all PSBT_IN_SP_ECDH_SHAREs from eligible inputs for that scan key.
    -If there are multiple silent payment codes with the same scan key, sort the codes lexicographically in ascending order to determine the ordering of the ''k'' value.
    -If there are multiple silent payment codes with both the same scan and spend keys, sort the subgroup by output index in ascending order.
    +If there are multiple silent payment codes with the same scan key, assign the ''k'' values by sorting those codes in ascending order of their 66-byte serialized <tt>PSBT_OUT_SP_V0_INFO</tt> value (the concatenation of the 33-byte scan key and the 33-byte spend key). Break ties by ascending output index.
     
     ===Transaction Extractor===
    

    macgyver13 commented at 11:55 PM on November 4, 2026:

    I took a slightly different approach. Instead of restating the PSBT_OUT_SP_V0_INFO composition here, I clarified two terms in the per-output table (silent payment code and labeled spend key):

     | <tt><33 byte scan key> <33 byte spend key></tt>
    -| The scan and spend public keys from the silent payments address.
    +| The scan and spend public keys from the silent payments address, referred to in this document as a ''silent payment code''. For a labeled address, the spend key is the labeled spend key ''B<sub>m</sub>''.
    

    Does this resolve the ambiguity @jonatack and @fametrano?


    jonatack commented at 6:05 PM on November 5, 2026:

    A one-line addition naming the 66-byte sort key might still be helpful, not sure and it can be deferred.

  23. jonatack commented at 3:58 PM on November 4, 2026: member

    ACK

    I think I prefer aligning the reference to the existing prose (this PR) rather than rewriting the rule (#2256). It seems that Sparrow 2.5.5, SeedSigner, Caravan, and Coldcard followed the text, while btclib followed the vectors (simpler, using already-present output indices)?

  24. fametrano commented at 10:40 PM on November 4, 2026: contributor

    Yes, btclib, which I maintain, followed the vectors: it assigns k per scan key in output index order (code). I ran this PR's vectors at 9514ecc through btclib's tests, and only the new three-output case fails. With k assigned by spend key, then output index, that case passes too and every invalid vector is still refused. btclib will switch to that order. I'm closing #2256 in favour of this PR and withdraw my objection to its ordering change.

  25. BIP-375: update labeled test vectors
    Now PSBT_OUT_SP_V0_INFO provides labeled-spend public key not the base-spend
    public key.
    
    Modify test vector with labeled-spend key to the same recipient from:
    two sp outputs - output 0 uses label=3 / output 1 uses label=1
    to:
    three sp outputs (same scan key) - output 0 uses label=1, outputs 1 and 2 uses label=2 (same spend key)
    This vector excercises the BIP375 sorting outputs with same scan key properly.
    
    The next commit will fix the validation logic and address this failing test.
    
    bump ChangeLog to 0.1.3
    434a4d2659
  26. BIP-375: update validation to match sorting outputs with same scan key
    Fix output script validation for silent payment output ordering when multiple 
    outputs share the same scan key (labeled addresses of one recipient).
    d31236854b
  27. macgyver13 force-pushed on Nov 4, 2026
  28. jonatack merged this on Nov 5, 2026
  29. jonatack closed this on Nov 5, 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-11-14 09:10 UTC

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