Skip to content

Bind invoice hashes to encoded bytes#4752

Open
tnull wants to merge 1 commit into
lightningdevkit:mainfrom
tnull:2026-06-bolt11-original-signable-hash
Open

Bind invoice hashes to encoded bytes#4752
tnull wants to merge 1 commit into
lightningdevkit:mainfrom
tnull:2026-06-bolt11-original-signable-hash

Conversation

@tnull

@tnull tnull commented Jun 26, 2026

Copy link
Copy Markdown
Contributor

Previously, deserialized invoices recomputed their signature hash by re-encoding the parsed invoice. Non-canonical amount digits could then be dropped, letting distinct encodings share a hash.

Hash deserialized invoices from the HRP and unsigned data bytes accepted by the parser so the cached hash remains bound to the encoded invoice.

Reported by Project Loupe.

Co-Authored-By: HAL 9000

Previously, deserialized invoices recomputed their signature hash by
re-encoding the parsed invoice. Non-canonical amount digits could then
be dropped, letting distinct encodings share a hash.

Hash deserialized invoices from the HRP and unsigned data bytes accepted
by the parser so the cached hash remains bound to the encoded invoice.

Reported by Project Loupe.

Co-Authored-By: HAL 9000
@ldk-reviews-bot

ldk-reviews-bot commented Jun 26, 2026

Copy link
Copy Markdown

I've assigned @wpaulino 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.

@ldk-claude-review-bot

Copy link
Copy Markdown
Collaborator

No issues found.

The change is a correct and well-targeted security fix for invoice hash malleability:

  • RawHrp.raw_amount is a u64, so the old signable_hash() re-encoding canonicalized non-canonical amounts (e.g. 025m25m), letting distinct encodings share a hash. The new code binds the cached hash to the actual HRP and signatureless data bytes accepted by the parser.
  • Canonical invoices still verify, since the parser-derived HRP/data match what a signer hashed.
  • from_str is the only production deserialization path, and the sign path remains consistent.
  • The pub(crate) visibility bump on hash_from_parts is necessary for the cross-module call.

No bugs, security regressions, or logic errors found in the diff.

@ldk-reviews-bot ldk-reviews-bot requested a review from wpaulino June 26, 2026 10:21
@TheBlueMatt

Copy link
Copy Markdown
Collaborator

I'd rather we just update the SHOULD use the shortest representation possible, by using the largest multiplier or omitting the multiplier. in the spec to MUST and reject non-canonical encodings? Apparently no one does this cause we've never seen it fail before, so might as well just make the spec stricter.

@codecov

codecov Bot commented Jun 26, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 96.42857% with 1 line in your changes missing coverage. Please review.
✅ Project coverage is 86.95%. Comparing base (6965bc9) to head (e8341e4).
⚠️ Report is 3224 commits behind head on main.

Files with missing lines Patch % Lines
lightning-invoice/src/de.rs 96.29% 0 Missing and 1 partial ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #4752      +/-   ##
==========================================
+ Coverage   84.55%   86.95%   +2.40%     
==========================================
  Files         137      161      +24     
  Lines       77617   111658   +34041     
  Branches    77617   111658   +34041     
==========================================
+ Hits        65627    97097   +31470     
- Misses       9948    12054    +2106     
- Partials     2042     2507     +465     
Flag Coverage Δ
fuzzing-fake-hashes 8.43% <0.00%> (?)
fuzzing-real-hashes 32.40% <0.00%> (?)
tests 86.28% <96.42%> (?)

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

☔ View full report in Codecov by Harness.
📢 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.

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.

4 participants