Skip to content

Conversation

@rustyrussell
Copy link
Collaborator

Needs:

  1. Implementation.
  2. Test vectors
  3. Review

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
Copy link
Contributor

@jkczyz jkczyz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some minor comments from a first pass. Should have more feedback once we attempt to implement this.

* [`bip340sig`:`sig`]
1. type: 242 (`preimage`)
2. data:
* [`32*byte`:`premage`]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

s/premage/preimage


The non-signature elements of a payer proof are identical to the
`invoice` tlv_stream, with the exception that `invreq_metadata` cannot
be included. Various fields are omitted for privacy: numbers
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

s/are/may be


A writer of a payer_proof:
- MUST NOT include `invreq_metadata`.
- MUST include `invreq_payer_id`, `invoice_payment_hash`, `invoice_node_id`, `signature` and (if present) `invoice_features` from the invoice.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you include a rationale for requiring invoice_features?

- `omitted_tlvs` contains 0.
- `omitted_tlvs` contains signature TLV element number (240 through 1000 inclusive).
- `omitted_tlvs` contains the number of an included TLV field.
- `omitted_tlvs` contains more than one number larger than the largest included non-signature TLV element.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure I understand this restriction. Why can't more than one such TLV be omitted? The example contradicts this (41 and 42), IIUC.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oops, this was from an earlier draft, and should be removed!


Note that the signature TLV 250 is not included in the merkle tree.

`leaf_hashes` contains the nonce hashes for the present non-signature TLVS:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

s/TLVS/TLVs

1. type: 250 (`payer_signature`)
2. data:
* [`bip340sig`:`sig`]
* [`...*utf8`:`note`]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Presumably, this may be empty?

vincenzopalazzo added a commit to vincenzopalazzo/rust-lightning that referenced this pull request Jan 2, 2026
Implements the payer proof extension to BOLT 12 as specified in
lightning/bolts#1295. This allows proving
that a BOLT 12 invoice was paid by demonstrating possession of the
payment preimage, a valid invoice signature, and a payer signature.

Key additions:
- Extend merkle.rs with selective disclosure primitives for creating
  and reconstructing merkle trees with partial TLV disclosure
- Add payer_proof.rs with PayerProof, PayerProofBuilder, and
  UnsignedPayerProof types for building and verifying payer proofs
- Support bech32 encoding with "lnp" prefix

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Copy link
Contributor

@vincenzopalazzo vincenzopalazzo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for this spec! I am finishing to implement it in ldk and have some feedback from implementation experience:

  1. The nonce hash notation needs clarification (see inline comment)
  2. Test vectors would be extremely valuable for cross-implementation compatibility. Wondering if you already had some draft implementation where we can compare the tests vectors?

Happy to provide my implementation's test vectors once the ambiguities are resolved.

- For each non-signature TLV in the invoice in ascending-type order:
- If the field is to be included in the payer_proof:
- MUST copy it into the payer_proof.
- MUST append the nonce (H("LnNonce"||TLV0,type)) to `leaf_hashes`.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: is ambiguous. It could mean:

  • H(H("LnNonce"||TLV0) || H("LnNonce"||TLV0) || type) (tagged hash style), or
  • H("LnNonce" || TLV0 || type) (simple concatenation)

Comment on lines +1108 to +1114
Thus, `missing_hashes` contains the following hashes in left-to-right
order:

1. Merkle of H("LnLeaf",TLV0) and H("LnNonce"||TLV0,0)
2. Merkle of (Merkle of H("LnLeaf",TLV20) and H("LnNonce"||TLV0,20))
and (Merkle of H("LnLeaf",TLV30) and H("LnNonce"||TLV0,30))
3. Merkle of H("LnLeaf",TLV50) and H("LnNonce"||TLV0,50)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The example shows only 3 missing_hashes but TLV 60 is also omitted.

Looking at the tree, when the subtree (40, [50]) combines with [60] at level 2, shouldn't we need a 4th hash for 60?

Am I misunderstanding the tree structure, or is this example incomplete?

vincenzopalazzo added a commit to vincenzopalazzo/rust-lightning that referenced this pull request Jan 4, 2026
Implements the payer proof extension to BOLT 12 as specified in
lightning/bolts#1295. This allows proving
that a BOLT 12 invoice was paid by demonstrating possession of the
payment preimage, a valid invoice signature, and a payer signature.

Key additions:
- Extend merkle.rs with selective disclosure primitives for creating
  and reconstructing merkle trees with partial TLV disclosure
- Add payer_proof.rs with PayerProof, PayerProofBuilder, and
  UnsignedPayerProof types for building and verifying payer proofs
- Support bech32 encoding with "lnp" prefix
vincenzopalazzo added a commit to vincenzopalazzo/rust-lightning that referenced this pull request Jan 4, 2026
Implements the payer proof extension to BOLT 12 as specified in
lightning/bolts#1295. This allows proving
that a BOLT 12 invoice was paid by demonstrating possession of the
payment preimage, a valid invoice signature, and a payer signature.

Key additions:
- Extend merkle.rs with selective disclosure primitives for creating
  and reconstructing merkle trees with partial TLV disclosure
- Add payer_proof.rs with PayerProof, PayerProofBuilder, and
  UnsignedPayerProof types for building and verifying payer proofs
- Support bech32 encoding with "lnp" prefix
vincenzopalazzo added a commit to vincenzopalazzo/rust-lightning that referenced this pull request Jan 4, 2026
Implements the payer proof extension to BOLT 12 as specified in
lightning/bolts#1295. This allows proving
that a BOLT 12 invoice was paid by demonstrating possession of the
payment preimage, a valid invoice signature, and a payer signature.

Key additions:
- Extend merkle.rs with selective disclosure primitives for creating
  and reconstructing merkle trees with partial TLV disclosure
- Add payer_proof.rs with PayerProof, PayerProofBuilder, and
  UnsignedPayerProof types for building and verifying payer proofs
- Support bech32 encoding with "lnp" prefix
vincenzopalazzo added a commit to vincenzopalazzo/rust-lightning that referenced this pull request Jan 5, 2026
Implements the payer proof extension to BOLT 12 as specified in
lightning/bolts#1295. This allows proving
that a BOLT 12 invoice was paid by demonstrating possession of the
payment preimage, a valid invoice signature, and a payer signature.

Key additions:
- Extend merkle.rs with selective disclosure primitives for creating
  and reconstructing merkle trees with partial TLV disclosure
- Add payer_proof.rs with PayerProof, PayerProofBuilder, and
  UnsignedPayerProof types for building and verifying payer proofs
- Support bech32 encoding with "lnp" prefix
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants