Two fixes in bip-0360/ref-impl/common/tests/data/p2mr_pqc_construction.json, found while implementing BIP 360 against the published vectors.
First, the three-leaf vectors (p2mr_three_leaf_complex and p2mr_three_leaf_alternative) list intermediary.leafHashes with entries 0 and 2 swapped relative to the depth-first order of the script tree. The merkle root, scriptPubKey, address and control blocks in those same vectors all follow depth-first order, as do the equivalent trees in p2mr_construction.json. This looks like a leftover from the ordering problem that #2202 fixed for the control blocks.
Check against the spec formulas:
import json, hashlib
def tagged(tag, data):
t = hashlib.sha256(tag.encode()).digest()
return hashlib.sha256(t + t + data).digest()
d = json.load(open("p2mr_pqc_construction.json"))
tv = [t for t in d["test_vectors"] if t["id"] == "p2mr_three_leaf_complex"][0]
leaves = []
def walk(n):
if isinstance(n, list):
for x in n: walk(x)
else: leaves.append(n)
walk(tv["given"]["scriptTree"])
for i, leaf in enumerate(leaves):
s = bytes.fromhex(leaf["script"])
h = tagged("TapLeaf", bytes([leaf["leafVersion"]]) + bytes([len(s)]) + s).hex()
print(i, h == tv["intermediary"]["leafHashes"][i])
Before this change that prints "0 False / 1 True / 2 False", i.e. entries 0 and 2 hold each other's values. Same for p2mr_three_leaf_alternative.
Second, in p2mr_different_version_leaves the second leaf has "leafVersion": 250 (0xfa), but scriptPathControlBlocks[1] started with c1. The control byte carries the leaf version in its upper 7 bits with the low bit set, so it should be fb. The vector's leafHashes[1] and merkle root already correspond to the leaf hashed under 0xfa and the path bytes are correct, so only the first byte was wrong. As published, a spender using that control block would recompute the leaf hash under 0xc0 and fail the merkle check.
After both fixes every success vector in the file passes a full recomputation from the spec formulas: leaf hashes, merkle root, scriptPubKey, bech32m address, control blocks, and walking each control block path back to the root.