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 +38 −25
  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: 41 passed, 0 failed
    
  2. 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.2
    5225829fe3
  3. 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).
    8f7b632f67
  4. macgyver13 marked this as ready for review on Jul 7, 2026
  5. murchandamus commented at 11:00 PM on July 7, 2026: member

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

  6. murchandamus added the label Proposed BIP modification on Jul 7, 2026
  7. murchandamus added the label Pending acceptance on Jul 7, 2026
  8. 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.


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-08-20 04:10 UTC

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