BOLT #11 Ambiguity: p Field Skipping vs. Mandatory Payment Hash
I’ve noticed a potential ambiguity in BOLT 11 regarding the p field:
- The spec states that a writer MUST include exactly one p field.
- However, under the “Tagged Fields” → “Requirements” section, it also says a reader MUST skip: “… unknown fields, OR an f field with unknown version, OR p, h, s or n fields that do not have data_lengths of 52, 52, 52 or 53, respectively.”
This can be misread to mean that if a p field doesn’t match the required length (e.g. zero length), the invoice parser should skip it rather than fail.
However, skipping a zero-length p field effectively means “no payment hash field is present,” which conflicts with the writer's requirement that p is mandatory. We know from the spec that the invoice must have a valid p field to be payable.
Why is this confusing?
A literal reading of “MUST skip over p fields that do not have data_length of 52” could be interpreted as:
“If data_length is not 52 for p, just skip it. Move on.”
But skipping a mandatory field is the same as omitting it. This leads to the question:
Is an invoice valid if we skip the p field because its data_length is 0 or invalid?
Why am I asking this now?
While running some Differential Fuzz Tests between LND and NLightning, we found out that for the decoding of the following invoice, LND fails and NLightning succeeds:
lnbc1pxtpcnsdz5cw9huz3z7wctpfpnptxcsdz5w9chzcw9huz3z7wc309t5cw9huz3z7wc3tpfpxpcnsdz5w9chzu3z7qqqqqqqqqqqqqqqqqqqqqqqquq44p9
A live demo for NLightning's Decoder can be found here
Potential Fix / Clarification
It might help to clarify in BOLT 11 that while you can skip unknown field types, you must fail if a mandatory known field (like p) doesn’t meet its specified data length. Perhaps something like:
“A reader MUST fail the invoice if a mandatory field (p, h, s, n) is present with an incorrect length, rather than skipping it.”
This would remove any possible interpretation that a zero-length p field can be skipped and the invoice somehow remain valid.
Can you please open a PR that fixes this? I don't think anyone else will do it based on this issue alone.
I had some issues while testing against the provided vectors, specifically on the signatures of the invoices. I'm using NBitcoin as the underlying Bitcoin library and it has a setting that defaults to producing signatures using Low R. After a few hours of going through the code (NLightning and NBitcoin) I realized all the test vectors (including BOLT3) do not enforce Low R on the signatures, which caused me a lot of headaches. I'll add this information to the same PR, if that's ok.
Fixed by #1243