Skip to content

offer: make the merkle tree signature public #3892

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged

Conversation

vincenzopalazzo
Copy link
Contributor

This is helpful for users who want to use the Merkle tree signature in their own code, for example, to verify the signature of bolt12 invoices or recreate it.

Very useful for people who are building command line tools for the bolt12 offers.

I am opening this, but I do not know if it is something that you want to do, but at the same time, IMHO, this is very useful to expose because it allows to use LDK in command line tools and in learning tools.

However, this is not strictly necessary because Bolt12Invoice::try_from already verifies the signature, but I would open this to know your point of view.

@ldk-reviews-bot
Copy link

ldk-reviews-bot commented Jun 26, 2025

👋 Thanks for assigning @TheBlueMatt as a reviewer!
I'll wait for their review and will help manage the review process.
Once they submit their review, I'll check if a second reviewer would be helpful.

@dunxen
Copy link
Contributor

dunxen commented Jun 26, 2025

I'm not personally opposed to this and it may be nice to expose it for the use cases you mention.
However, maybe the doc comments for these should be updated to indicate that these don't need to be used directly and they're really for internal use, but made public for use in applications like you specified. We should redirect them to the appropriate methods for production use.

I'm also not sure about any API guarantees for these methods. I don't think it's too much of a hassle to treat them the same way we treat any other public API.

Copy link

codecov bot commented Jun 26, 2025

Codecov Report

All modified and coverable lines are covered by tests ✅

Project coverage is 88.95%. Comparing base (1d507f2) to head (93cf409).
Report is 130 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #3892      +/-   ##
==========================================
- Coverage   89.00%   88.95%   -0.05%     
==========================================
  Files         166      168       +2     
  Lines      119990   122065    +2075     
  Branches   119990   122065    +2075     
==========================================
+ Hits       106798   108586    +1788     
- Misses      10770    11076     +306     
+ Partials     2422     2403      -19     
Flag Coverage Δ
fuzz ?
fuzzing 22.69% <0.00%> (?)
tests 88.78% <100.00%> (?)

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@ldk-reviews-bot
Copy link

👋 The first review has been submitted!

Do you think this PR is ready for a second reviewer? If so, click here to assign a second reviewer.

@ldk-reviews-bot
Copy link

🔔 1st Reminder

Hey @TheBlueMatt @valentinewallace! This PR has been waiting for your review.
Please take a look when you have a chance. If you're unable to review, please let us know so we can find another reviewer.

1 similar comment
@ldk-reviews-bot
Copy link

🔔 1st Reminder

Hey @TheBlueMatt @valentinewallace! This PR has been waiting for your review.
Please take a look when you have a chance. If you're unable to review, please let us know so we can find another reviewer.

@vincenzopalazzo
Copy link
Contributor Author

cc @jkczyz

@vincenzopalazzo vincenzopalazzo force-pushed the macros/markle-signature branch 2 times, most recently from dd046d5 to 29e5bd6 Compare July 8, 2025 20:46
@TheBlueMatt TheBlueMatt removed their request for review July 9, 2025 01:06
@TheBlueMatt
Copy link
Collaborator

Will take a look at this after @jkczyz's comments are addressed, assuming he thinks it needs a second reviewer at that point.

@vincenzopalazzo vincenzopalazzo force-pushed the macros/markle-signature branch from 0c7fe08 to 123e16f Compare July 9, 2025 10:19
@ldk-reviews-bot
Copy link

🔔 2nd Reminder

Hey @valentinewallace! This PR has been waiting for your review.
Please take a look when you have a chance. If you're unable to review, please let us know so we can find another reviewer.

@vincenzopalazzo vincenzopalazzo force-pushed the macros/markle-signature branch 2 times, most recently from 7429b6a to 1b958e9 Compare July 9, 2025 11:13
@vincenzopalazzo
Copy link
Contributor Author

vincenzopalazzo commented Jul 9, 2025

Ok, I pushed the change that @jkczyz requested, and now the PR is organised in two commits as follows:

  • bed3812 where expose the sign and verify method to verify manually an invoice signature, this is nice for people that are building command line tools and want to show how the signature verification is described inside the spec
    -e60b87c38c043114642eda5499864c3c6898aa64 expose the offer_id inside the Bolt12Invoice that allows to compare it with the Offer to make sure that the invoice is linked with the Bolt12 one. This is useful for a sanity check, but requires trusting that the decoding of ldk will always verify the signature of the invoice

Let me know if you are fine with the commit divided in this way, or you prefer e60b87c

@vincenzopalazzo vincenzopalazzo force-pushed the macros/markle-signature branch from 1b958e9 to 699f37f Compare July 9, 2025 11:23
@vincenzopalazzo vincenzopalazzo force-pushed the macros/markle-signature branch from 22ef851 to e60b87c Compare July 9, 2025 20:12
@vincenzopalazzo vincenzopalazzo force-pushed the macros/markle-signature branch 2 times, most recently from ec9b1c6 to 98d51cd Compare July 10, 2025 07:19
@vincenzopalazzo vincenzopalazzo requested a review from jkczyz July 10, 2025 11:06
Comment on lines 662 to 666
let offer_id = match &contents {
InvoiceContents::ForOffer { .. } => Some(OfferId::from_valid_bolt12_tlv_stream(&bytes)),
InvoiceContents::ForRefund { .. } => None,
};
Self { bytes, experimental_bytes, contents, tagged_hash, offer_id }
Copy link
Contributor Author

Choose a reason for hiding this comment

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

@jkczyz do you think that we should add in OfferId a maybe_from_valid_bolt12_tlv_stream(&bytes) -> Option<OfferId> to include the refund case without duplicate the match here?

Copy link
Contributor

Choose a reason for hiding this comment

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

We'd need to take in the InvoiceContents then, too. Leaning towards not doing this for unsigned invoices after all. See next comment.

Comment on lines 662 to 666
let offer_id = match &contents {
InvoiceContents::ForOffer { .. } => Some(OfferId::from_valid_bolt12_tlv_stream(&bytes)),
InvoiceContents::ForRefund { .. } => None,
};
Self { bytes, experimental_bytes, contents, tagged_hash, offer_id }
Copy link
Contributor

Choose a reason for hiding this comment

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

We'd need to take in the InvoiceContents then, too. Leaning towards not doing this for unsigned invoices after all. See next comment.

@vincenzopalazzo vincenzopalazzo force-pushed the macros/markle-signature branch 3 times, most recently from 079db78 to 0e5217d Compare July 15, 2025 08:38
@vincenzopalazzo
Copy link
Contributor Author

Ok pushed the changes, not sure that I have got 100% this review, but let me know if there is something that is still pending #3892 (comment)

@vincenzopalazzo vincenzopalazzo requested a review from jkczyz July 15, 2025 08:39
@vincenzopalazzo vincenzopalazzo force-pushed the macros/markle-signature branch 2 times, most recently from 097c4a7 to 8df655b Compare July 15, 2025 08:56
@vincenzopalazzo
Copy link
Contributor Author

I noted that for some reason, I was not making public the tagged_hash inside the Bolt12Invoice which was the way to execute manual verification. I pushed the code in ea5685c and added a test to show a user how to use the API that we are now making public

@vincenzopalazzo vincenzopalazzo force-pushed the macros/markle-signature branch from 8df655b to 5ceaf4d Compare July 15, 2025 09:05
@vincenzopalazzo vincenzopalazzo force-pushed the macros/markle-signature branch 3 times, most recently from c5fe6a3 to f5fbd6c Compare July 16, 2025 09:55
@vincenzopalazzo vincenzopalazzo requested a review from jkczyz July 16, 2025 09:56
@vincenzopalazzo
Copy link
Contributor Author

vincenzopalazzo commented Jul 16, 2025

I had to rebase to make the CI happy because there was a problem fixed by some PR that is now merged.

So I think the only missing thing to resolve is the following one #3892 (comment)

Would love to have the API to hide the secp256k1, but I also understand that the code is simple enough that we do not need an API for skilled users. Let me know what you preferer

@vincenzopalazzo vincenzopalazzo force-pushed the macros/markle-signature branch from f5fbd6c to 87c74b1 Compare July 21, 2025 17:23
@vincenzopalazzo vincenzopalazzo requested a review from jkczyz July 21, 2025 17:25
vincenzopalazzo and others added 2 commits July 23, 2025 19:42
This is helpfull for the users that want to use the merkle tree
signature in their own code, for example to verify the
signature of bolt12 invoices or recreate it.

Very useful for people that are building command line tools
for the bolt12 offers.

Signed-off-by: Vincenzo Palazzo <[email protected]>
- Add an Option<OfferId> field to Bolt12Invoice to
  track the originating offer.
- Compute the offer_id for invoices created from
  offers by extracting the offer TLV records and
  hashing them with the correct tag.
- Expose a public offer_id() accessor on invoice.
- Add tests to ensure the offer_id in the invoice
  matches the originating Offer, and that refund
  invoices have no offer_id.
- All existing and new tests pass. This enables
  linking invoices to their originating offers
  in a robust and spec-compliant way.

Co-authored-by: graphite-app[bot] <96075541+graphite-app[bot]@users.noreply.github.com>
Signed-off-by: Vincenzo Palazzo <[email protected]>
@vincenzopalazzo vincenzopalazzo force-pushed the macros/markle-signature branch from 87c74b1 to 93cf409 Compare July 23, 2025 17:43
@vincenzopalazzo vincenzopalazzo requested a review from jkczyz July 23, 2025 17:44
Copy link
Collaborator

@TheBlueMatt TheBlueMatt left a comment

Choose a reason for hiding this comment

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

Sure

@@ -642,7 +651,8 @@ impl TryFrom<ParsedMessage<FullInvoiceTlvStream>> for StaticInvoice {
let pubkey = contents.signing_pubkey;
merkle::verify_signature(&signature, &tagged_hash, pubkey)?;

Ok(StaticInvoice { bytes, contents, signature })
let offer_id = OfferId::from_valid_bolt12_tlv_stream(&bytes);
Copy link
Collaborator

Choose a reason for hiding this comment

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

This is a chunk more hashing on load. Its probably not crazy given we already do a signature validation, but if we assume most folks won't use it, does it make more sense to expose a calculate_offer_id method that does it live instead?

@TheBlueMatt TheBlueMatt merged commit 479c5c7 into lightningdevkit:main Jul 24, 2025
27 checks passed
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.

6 participants