The vectors file contradicts the prose it is checksummed by
44.md defines the 6-byte extended length prefix as valid, and the vectors file it pins still lists that length as an invalid encrypt length. Both are current, so an implementer following the prose fails their own conformance suite.
The prose
44.md:90-91 — "If length is less than 65536: prefix is 2 bytes (u16) […] If length is 65536 or greater: prefix is 6 bytes (2 zero bytes + u32)"
44.md:168 — "extended_prefix_threshold is 65536"
44.md:206-209 — pad emits concat([0, 0], write_u32_be(unpadded_len)) at or above the threshold
44.md:86 — "Minimum is 1 byte, maximum is 4,294,967,295 bytes"
The vectors file
44.md:303 publishes:
269ed0f69e4c192512cc779e78c555090cebc7c785b609e338a62afc3ce25040 nip44.vectors.json
A file matching that checksum contains:
"invalid": { "encrypt_msg_lengths": [0, 65536, 100000, 10000000] }
65536 and 100000 are valid encrypt lengths under the prose above. They sit in the invalid list.
Why this is awkward to work around
The checksum has not moved, so there is no regenerated file to fetch — re-vendoring reproduces the same contradiction. An implementer either edits a pinned artifact, which defeats the pin, or carries a local exception.
The inline table is a usable substitute, and it is correct
44.md:331-352 supplies the extended-prefix cases separately, noting the payloads are too large to inline in JSON. I implemented the decrypt side against that table and reproduced all three published payload_sha256 values byte-for-byte, including the 65535 u16 case as a control:
| plaintext_len |
prefix |
payload_sha256 |
reproduced |
| 65535 |
u16 |
6d8c2810d1e870fbaa1f0a0937126cca837a15f9260e27060c331d70a3c0bc84 |
yes |
| 65536 |
extended |
b7b4edb36ba92e267d322d56d9aebc22e7fa96ff52e3c12adc07f07a43cbc616 |
yes |
| 65537 |
extended |
eeb7c7c5373894ea2c1547cfd3ccb15d5a0b2d619da852e5c79df792dcc9e435 |
yes |
So the table is trustworthy. The JSON is the piece left behind.
Suggestion
Regenerate nip44.vectors.json so invalid.encrypt_msg_lengths drops 65536 and 100000, fold the three boundary cases in beside valid.encrypt_decrypt_long_msg, which already uses checksums rather than inline payloads, and update the published sha256. Failing that, a sentence in 44.md saying the vectors file predates the extended prefix would save the next implementer the detour.
Happy to open a PR for the regenerated file if that helps.
The vectors file contradicts the prose it is checksummed by
44.mddefines the 6-byte extended length prefix as valid, and the vectors file it pins still lists that length as an invalid encrypt length. Both are current, so an implementer following the prose fails their own conformance suite.The prose
44.md:90-91— "If length is less than 65536: prefix is 2 bytes (u16) […] If length is 65536 or greater: prefix is 6 bytes (2 zero bytes +u32)"44.md:168— "extended_prefix_thresholdis 65536"44.md:206-209—pademitsconcat([0, 0], write_u32_be(unpadded_len))at or above the threshold44.md:86— "Minimum is 1 byte, maximum is 4,294,967,295 bytes"The vectors file
44.md:303publishes:A file matching that checksum contains:
65536 and 100000 are valid encrypt lengths under the prose above. They sit in the invalid list.
Why this is awkward to work around
The checksum has not moved, so there is no regenerated file to fetch — re-vendoring reproduces the same contradiction. An implementer either edits a pinned artifact, which defeats the pin, or carries a local exception.
The inline table is a usable substitute, and it is correct
44.md:331-352supplies the extended-prefix cases separately, noting the payloads are too large to inline in JSON. I implemented the decrypt side against that table and reproduced all three publishedpayload_sha256values byte-for-byte, including the 65535 u16 case as a control:6d8c2810d1e870fbaa1f0a0937126cca837a15f9260e27060c331d70a3c0bc84b7b4edb36ba92e267d322d56d9aebc22e7fa96ff52e3c12adc07f07a43cbc616eeb7c7c5373894ea2c1547cfd3ccb15d5a0b2d619da852e5c79df792dcc9e435So the table is trustworthy. The JSON is the piece left behind.
Suggestion
Regenerate
nip44.vectors.jsonsoinvalid.encrypt_msg_lengthsdrops 65536 and 100000, fold the three boundary cases in besidevalid.encrypt_decrypt_long_msg, which already uses checksums rather than inline payloads, and update the published sha256. Failing that, a sentence in44.mdsaying the vectors file predates the extended prefix would save the next implementer the detour.Happy to open a PR for the regenerated file if that helps.