[RFC] contrib: add libbolt12 standalone decode/verify library#9056
Draft
vincenzopalazzo wants to merge 1 commit intoElementsProject:masterfrom
Draft
[RFC] contrib: add libbolt12 standalone decode/verify library#9056vincenzopalazzo wants to merge 1 commit intoElementsProject:masterfrom
vincenzopalazzo wants to merge 1 commit intoElementsProject:masterfrom
Conversation
51c340d to
63bf809
Compare
Add a standalone C library (libbolt12) that wraps CLN's existing bolt12 implementation behind a clean public API with no CLN-internal types exposed (no tal, no TLV structs). The library provides: - Decode BOLT12 offers (lno1...) and invoices (lni1...) - Access all offer/invoice properties via accessor functions - Verify invoice BIP-340 schnorr signatures - Verify proof of payment (preimage vs payment_hash) - Compare offer_id and signing pubkeys between offer and invoice - All-in-one bolt12_verify_offer_payment() convenience function The motivation is enabling external C programs (e.g. mining pool payout verification tools) to decode and verify BOLT12 offers/invoices without depending on Rust or running a full CLN node. The library links against libcommon.a and libccan.a, with a fat archive option (libbolt12-fat.a) for external consumers. libbolt12 deliberately avoids common_setup() because common_setup() mutates process-global state (locale, env, progname) and calls errx(1) on init failures -- both unacceptable for a reusable library. Instead, bolt12_init() does the minimum: secp256k1_context_create() plus a tmpctx. bolt12_cleanup() reverses this. Includes a test suite (contrib/libbolt12/run-bolt12.c) using real-world test vectors from Phoenix and CLN-generated offers/invoices, exercising the happy path and all documented error branches. Changelog-Added: contrib: new libbolt12 library exposing BOLT12 decode and verification as a standalone C API. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
63bf809 to
1464a54
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
RFC: Add a standalone C library (
libbolt12) that wraps CLN's existing bolt12 implementation behind a clean public API — notal, no CLN internal types exposed.Motivation
External C programs (e.g. mining pool payout verification tools) need to decode and verify BOLT12 offers/invoices without depending on Rust or running a full CLN node. Currently the only options are:
offersmodule (requires Rust toolchain)lightning-cli decodeas a subprocess (requires running CLN)This library provides a fourth option: link against
libbolt12.aand call clean C functions.What it provides
API surface
Decode/Free:
bolt12_offer_decode()/bolt12_offer_free()bolt12_invoice_decode()/bolt12_invoice_free()Offer accessors:
bolt12_offer_id(),bolt12_offer_description(),bolt12_offer_issuer()bolt12_offer_amount(),bolt12_offer_currency()bolt12_offer_effective_signing_pubkey(),bolt12_offer_num_paths()bolt12_offer_absolute_expiry(),bolt12_offer_quantity_max(),bolt12_offer_chains()Invoice accessors:
bolt12_invoice_payment_hash(),bolt12_invoice_amount(),bolt12_invoice_description()bolt12_invoice_signing_pubkey(),bolt12_invoice_offer_id()bolt12_invoice_created_at(),bolt12_invoice_expiry(),bolt12_invoice_signature()bolt12_invoice_payer_note(),bolt12_invoice_quantity(),bolt12_invoice_num_paths()Verification:
bolt12_verify_invoice_signature()— BIP-340 schnorr over merkle rootbolt12_verify_proof_of_payment()— SHA256(preimage) == payment_hashbolt12_compare_offer_id()/bolt12_compare_signing_pubkeys()bolt12_verify_offer_payment()— all-in-one convenienceImplementation
~1400 lines total. The implementation is a thin wrapper (~660 lines in
bolt12_api.c) around CLN's existingoffer_decode(),invoice_decode(),bolt12_check_signature(),merkle_tlv()etc. No CLN code was modified — only a one-lineincludeadded to the top-level Makefile.Opaque types (
bolt12_offer_t,bolt12_invoice_t) hide the internaltaltree. Public API uses only standard C types (uint8_t[32],uint64_t,char *).Build
Test results
Questions for reviewers
contrib/the right home for this, or should it live elsewhere?bolt12_offer_encode()etc.)?Test plan
make check-libbolt12passes (19/19 tests)🤖 Generated with Claude Code