bip-0375: assign k in output index order #2256

pull fametrano wants to merge 1 commits into bitcoin:master from fametrano:bip375-k-output-index-order changing 1 files +5 −3
  1. fametrano commented at 5:21 PM on August 14, 2026: contributor

    BIP375 states one rule for assigning k to the silent payment outputs of a transaction, and its test vectors and reference validator implement another. This amends the prose to the rule the shipped artefacts follow.

    The discrepancy

    bip-0375.mediawiki L240-241 asks for the codes sharing a scan key to be sorted lexicographically, with a tie-break by output index for codes sharing both keys. bip-0375/validator/validate_psbt.py does not sort: it tracks k per scan key while walking enumerate(psbt.o). The vectors were generated the same way.

    Measured with bip-0375/test_runner.py on Python 3.12, at 60f5b33b:

    tree result
    master, unchanged 41 passed, 0 failed
    master, validator patched to assign k by ascending PSBT_OUT_SP_V0_INFO, ties by output index 40 passed, 1 failed: valid[8], "two sp outputs - output 0 uses label=3 / output 1 uses label=1"

    That vector's two spend keys are in descending order, so a lexicographic sort gives k = 0 to output 1, and the scripts the file publishes are the ones index order derives. No invalid vector changes verdict under either rule; the two invalid vectors named after ordering do not discriminate, since in one the spend keys are already ascending and in the other all three codes are identical.

    Why index order rather than the reverse fix

    #2207 closes the same gap the other way, by correcting the vectors and the validator to the prose. Both work. This one is proposed because the rule is cheaper to state and to implement:

    • lexicographic order needs a canonical encoding of a "code" and a total order on it. "The codes" admits at least three readings — the 66-byte PSBT_OUT_SP_V0_INFO, the bech32m address string, or the (scan, spend) pair — and the BIP names none of them. Output indices are already in the psbt and already agreed by both parties;
    • the property a code-based order would buy, invariance under output reordering, is unavailable here: a Signer that sets any missing PSBT_OUT_SCRIPT must clear the Inputs Modifiable and Outputs Modifiable flags (L185), and a psbt carrying a script with PSBT_GLOBAL_TX_MODIFIABLE non-zero is invalid. The outputs cannot be reordered once the scripts exist;
    • what the rule has to buy appears to be inter-party determinism only. 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 correct and the choice is one of cost.

    If the owners prefer #2207's direction, this should be closed in its favour — the two are alternatives on the ordering question, and #2207's other half, the labeled spend key in PSBT_OUT_SP_V0_INFO, is independent of it and looks right either way.

    The second sentence

    Dropping it is not a loss: one counter per scan key covers codes sharing both keys with no tie-break. What it left unsaid is added in its place, because it is the part an implementer gets wrong — the counter counts the outputs of that scan key, not the output index, which the vector "three sp outputs (same scan key) / two regular outputs - k values assigned independently of output index" exercises.

    Checks

    scripts/link-format-chk.sh, scripts/buildtable.pl, scripts/diffcheck.sh and typos all pass locally. The version header and the changelog entry are the first thing to rebase if #2207 lands first.

    Found while implementing BIP375 in btclib, which follows the vectors: https://github.com/btclib-org/btclib/issues/768

  2. bip-0375: assign k in output index order
    The two sentences under "Computing the Output Scripts" ask for the codes
    sharing a scan key to be sorted lexicographically. The test vectors and
    bip-0375/validator/validate_psbt.py do not do that: the validator tracks
    k per scan key while walking the outputs in index order, and the vectors
    were generated the same way.
    
    Patching the validator to the prose fails the valid vector "two sp
    outputs - output 0 uses label=3 / output 1 uses label=1", whose two spend
    keys are in descending order; nothing else in the file changes verdict.
    
    Index order is also the cheaper rule to state. Lexicographic order needs
    a canonical encoding of a "code" -- the 66-byte PSBT_OUT_SP_V0_INFO, the
    bech32m address string, or the (scan, spend) pair are all readings of the
    present wording -- while output indices are already in the psbt. The
    invariance under output reordering that a code-based order would buy is
    unavailable here, because a Signer setting a missing PSBT_OUT_SCRIPT must
    clear the Inputs Modifiable and Outputs Modifiable flags, so the outputs
    cannot be reordered once the scripts exist.
    
    The second sentence, on codes sharing both keys, becomes redundant: one
    counter per scan key covers identical codes without a tie-break. What it
    did leave unsaid is added instead, since it is the part an implementer
    gets wrong: the counter counts the outputs of that scan key, not the
    output index, which the vector "three sp outputs (same scan key) / two
    regular outputs - k values assigned independently of output index"
    exercises.
    def1059ed9
  3. jonatack commented at 9:48 PM on August 14, 2026: member

    @fametrano Thank you for your proposal. Can you summarize the PR description more concisely in your own words, please.


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