定制 nova-carnivore/bolt12-php 二次开发

按需修改功能、优化性能、对接业务系统,提供一站式技术支持

邮箱:yvsm@zunyunkeji.com | QQ:316430983 | 微信:yvsm316

nova-carnivore/bolt12-php

Composer 安装命令:

composer require nova-carnivore/bolt12-php

包简介

Modern PHP 8.3+ BOLT 12 Lightning Network offer/invoice encoder/decoder with BIP-340 Schnorr signatures

README 文档

README

PHP Version License CI PHPStan Level Latest Version

Modern PHP 8.3+ BOLT 12 Lightning Network offer/invoice encoder/decoder with BIP-340 Schnorr signatures. Full spec compliance, production-ready.

Features

  • Full BOLT 12 spec compliance — Offers, Invoice Requests, Invoices, Invoice Errors
  • 🔐 BIP-340 Schnorr signatures — Pure PHP implementation with Merkle tree construction
  • 🏗️ Modern PHP 8.3+ — Enums, readonly classes, named arguments, match expressions
  • 🔍 PHPStan level 9 — Maximum static analysis strictness
  • 🌐 All message types — Offer (lno), Invoice Request (lnr), Invoice (lni), Invoice Error
  • 🏷️ All TLV fields — chains, metadata, currency, amounts, paths, features, BIP-353, and more
  • 🔄 Round-trip safe — Encode → decode preserves all data
  • 📏 PSR-12 code style — Enforced with PHP-CS-Fixer
  • 🔒 Constant-time crypto — Uses GMP for big integer operations
  • 🔗 Blinded paths — Full support for multi-hop blinded payment paths

Installation

composer require nova-carnivore/bolt12-php

Requirements

  • PHP 8.3 or higher
  • ext-gmp (required for big integers and BIP-340 crypto)

Quick Start

Decode (Auto-detect Type)

use Nova\Bitcoin\Bolt12\Decoder;

$offer = Decoder::decode('lno1...');      // Returns Offer object
$invReq = Decoder::decode('lnr1...');     // Returns InvoiceRequest object
$invoice = Decoder::decode('lni1...');    // Returns Invoice object

Encode an Offer

use Nova\Bitcoin\Bolt12\Encoder;
use Nova\Bitcoin\Bolt12\Signer;

$encoded = Encoder::encodeOffer(
    issuerId: $myPublicKeyHex,
    description: 'Buy a coffee',
    amountMsat: gmp_init(100000),
    issuer: 'CoffeeShop',
);
// Returns: 'lno1...'

Encode an Invoice Request (auto-signed)

$invReq = Encoder::encodeInvoiceRequest(
    invreqMetadata: bin2hex(random_bytes(32)),
    payerId: $myPublicKeyHex,
    payerPrivateKey: $myPrivateKeyHex,
    offerDescription: 'Buy a coffee',
    offerIssuerId: $merchantPubkey,
    offerAmountMsat: gmp_init(100000),
);
// Returns: 'lnr1...' (signed with BIP-340 Schnorr)

Encode an Invoice (auto-signed)

use Nova\Bitcoin\Bolt12\BlindedPath;
use Nova\Bitcoin\Bolt12\BlindedPayInfo;
use Nova\Bitcoin\Bolt12\OnionMessageHop;

$invoice = Encoder::encodeInvoice(
    nodeId: $myNodePubkey,
    nodePrivateKey: $myNodePrivkey,
    createdAt: gmp_init(time()),
    paymentHash: hash('sha256', $preimage),
    amountMsat: gmp_init(100000),
    invoicePaths: [
        new BlindedPath($blindingKey, [
            new OnionMessageHop($nodeId, $encryptedData),
        ]),
    ],
    blindedPayInfo: [
        new BlindedPayInfo(
            feeBaseMsat: 1000,
            feeProportionalMillionths: 100,
            cltvExpiryDelta: 144,
            htlcMinimumMsat: gmp_init(1000),
            htlcMaximumMsat: gmp_init(1000000000),
        ),
    ],
);
// Returns: 'lni1...' (signed with BIP-340 Schnorr)

Verify Signatures

use Nova\Bitcoin\Bolt12\Signer;

$invReq = Decoder::decode('lnr1...');
$valid = Signer::verifyInvoiceRequest($invReq);  // Returns bool

$invoice = Decoder::decode('lni1...');
$valid = Signer::verifyInvoice($invoice);  // Returns bool

Invoice Errors

// Encode
$errorBytes = Encoder::encodeInvoiceError(
    error: 'Amount too low',
    erroneousField: gmp_init(82),  // invreq_amount
    suggestedValue: '0186a0',      // 100000 as tu64 hex
);

// Decode
$invoiceError = Decoder::decodeInvoiceError($errorBytes);
echo $invoiceError->error;  // 'Amount too low'

Full Payment Flow Example

use Nova\Bitcoin\Bolt12\{Decoder, Encoder, Signer, BlindedPath, BlindedPayInfo, OnionMessageHop};

// 1. Merchant creates an offer
$offer = Encoder::encodeOffer(
    issuerId: $merchantPubkey,
    description: 'Buy a coffee',
    amountMsat: gmp_init(100000),
);
$decoded = Decoder::decode($offer);

// 2. Payer creates invoice request (mirrors offer fields)
$invReq = Encoder::encodeInvoiceRequest(
    invreqMetadata: bin2hex(random_bytes(32)),
    payerId: $payerPubkey,
    payerPrivateKey: $payerPrivkey,
    offerDescription: $decoded->description,
    offerIssuerId: $decoded->issuerId,
    offerAmountMsat: $decoded->amountMsat,
);

// 3. Merchant creates and signs invoice
$invoice = Encoder::encodeInvoice(
    nodeId: $merchantPubkey,
    nodePrivateKey: $merchantPrivkey,
    createdAt: gmp_init(time()),
    paymentHash: hash('sha256', $preimage),
    amountMsat: gmp_init(100000),
    invoicePaths: [$blindedPath],
    blindedPayInfo: [$payInfo],
);

// 4. Payer verifies invoice signature
$inv = Decoder::decode($invoice);
assert(Signer::verifyInvoice($inv));

API Reference

Decoder::decode(string $bolt12String): Offer|InvoiceRequest|Invoice

Decodes any BOLT 12 bech32 string (auto-detects type by prefix).

Decoder::decodeInvoiceError(array $bytes): InvoiceError

Decodes a BOLT 12 Invoice Error from raw TLV bytes.

Encoder::encodeOffer(...): string

Encodes a BOLT 12 Offer (lno1...). Not signed per spec.

Encoder::encodeInvoiceRequest(...): string

Encodes and signs a BOLT 12 Invoice Request (lnr1...).

Encoder::encodeInvoice(...): string

Encodes and signs a BOLT 12 Invoice (lni1...).

Encoder::encodeInvoiceError(...): array

Encodes a BOLT 12 Invoice Error as raw TLV bytes.

Signer::verifyInvoiceRequest(InvoiceRequest $invReq): bool

Verifies a BIP-340 Schnorr signature on an invoice request.

Signer::verifyInvoice(Invoice $invoice): bool

Verifies a BIP-340 Schnorr signature on an invoice.

Signer::getPublicKey(string $privateKeyHex): string

Derives a compressed public key from a private key.

Data Classes

Class Description
Offer Decoded offer with all fields as readonly properties
InvoiceRequest Decoded invoice request with signature
Invoice Decoded invoice with paths, payinfo, and signature
InvoiceError Decoded invoice error
BlindedPath Blinded path with hops
BlindedPayInfo Payment info for blinded paths
FallbackAddress On-chain fallback address
OnionMessageHop Single hop in a blinded path
Bip353Name BIP-353 name (user@domain)
TlvEntry Raw TLV type-value pair

BOLT 12 Spec Coverage

Message Types

Type Prefix Encode Decode Sign Verify
Offer lno ✅* ✅*
Invoice Request lnr
Invoice lni
Invoice Error N/A N/A

* Offers are optionally signed per spec

TLV Fields

Type Field Offer InvReq Invoice
0 invreq_metadata
2 offer_chains
4 offer_metadata
6 offer_currency
8 offer_amount
10 offer_description
12 offer_features
14 offer_absolute_expiry
16 offer_paths
18 offer_issuer
20 offer_quantity_max
22 offer_issuer_id
80 invreq_chain
82 invreq_amount
84 invreq_features
86 invreq_quantity
88 invreq_payer_id
89 invreq_payer_note
90 invreq_paths
91 invreq_bip_353_name
160 invoice_paths
162 invoice_blindedpay
164 invoice_created_at
166 invoice_relative_expiry
168 invoice_payment_hash
170 invoice_amount
172 invoice_fallbacks
174 invoice_features
176 invoice_node_id
240 signature ✅*

Encoding

  • Bech32 without checksum — per BOLT 12 spec
  • BigSize TLV type/length encoding
  • tu64 truncated unsigned 64-bit values
  • + concatenation support for long strings

Cryptography

  • BIP-340 Schnorr signatures (64-byte raw, not DER)
  • Tagged hashesSHA256(SHA256(tag) || SHA256(tag) || msg)
  • Merkle tree for multi-TLV signatures with nonce leaves
  • secp256k1 elliptic curve arithmetic

Security

  • BIP-340 Schnorr signatures use pure PHP with GMP for big integer arithmetic
  • All elliptic curve operations use constant-time modular arithmetic via GMP
  • The Merkle tree construction includes nonce leaves to prevent revealing adjacent fields
  • Private keys are only used in signing operations and never stored

Exception Handling

use Nova\Bitcoin\Bolt12\Exception\{
    Bolt12Exception,       // Base exception
    DecodeException,       // Malformed input
    EncodeException,       // Missing/invalid fields
    SignatureException,    // Signature issues
};

try {
    $offer = Decoder::decode($bolt12String);
} catch (DecodeException $e) {
    // Malformed string or TLV data
} catch (Bolt12Exception $e) {
    // Any BOLT 12 error
}

Development

# Install dependencies
composer install

# Run tests
vendor/bin/phpunit

# Static analysis
vendor/bin/phpstan analyse

# Code style check
vendor/bin/php-cs-fixer fix --dry-run --diff

# Fix code style
vendor/bin/php-cs-fixer fix

# Run all CI checks
composer ci

Architecture

src/
├── Decoder.php          # Main decoder (auto-detect type)
├── Encoder.php          # Main encoder (all message types)
├── Signer.php           # BIP-340 Schnorr + Merkle tree
├── Bech32.php           # Bech32 WITHOUT checksum (per BOLT 12)
├── TlvStream.php        # BigSize TLV encoding/decoding
├── TlvEntry.php         # TLV entry value object
├── Offer.php            # Offer value object (readonly)
├── InvoiceRequest.php   # Invoice request value object (readonly)
├── Invoice.php          # Invoice value object (readonly)
├── InvoiceError.php     # Invoice error value object (readonly)
├── BlindedPath.php      # Blinded path with encoding/decoding
├── BlindedPayInfo.php   # Blinded payment info
├── FallbackAddress.php  # On-chain fallback address
├── OnionMessageHop.php  # Blinded path hop
├── Bip353Name.php       # BIP-353 name resolution
├── Helpers.php          # Byte/hex/string utilities
└── Exception/
    ├── Bolt12Exception.php
    ├── DecodeException.php
    ├── EncodeException.php
    └── SignatureException.php

Key Differences from BOLT 11

Feature BOLT 11 BOLT 12
Encoding Bech32 with checksum Bech32 without checksum
Crypto ECDSA recovery BIP-340 Schnorr
Signatures Simple message hash Merkle tree construction
TLV encoding 5-bit continuation BigSize encoding
Message types 1 (invoice only) 4 (offer, invreq, invoice, error)
Privacy Direct node ID Blinded paths

License

MIT — see LICENSE.

nova-carnivore/bolt12-php 适用场景与选型建议

nova-carnivore/bolt12-php 是一款 基于 PHP 开发的 Composer 扩展包,目前已累计 0 次下载、GitHub Stars 达 0, 最近一次更新时间为 2026 年 02 月 15 日, 在 PHP 生态内属于活跃度较高的组件。

它主要适用于以下技术方向: 「invoice」 「bitcoin」 「offer」 「Lightning」 「lightning-network」 「schnorr」 等业务场景。在实际项目中,围绕这些方向常见需要落地的问题包括:接口对接、性能调优、并发安全、与既有框架(Laravel / ThinkPHP / Yii / Webman 等)的兼容适配,以及生产环境的日志埋点与稳定性保障。

我们在过去多个企业项目中使用过 nova-carnivore/bolt12-php 或与其功能相近的方案,如果你在选型或落地过程中遇到问题,例如 版本兼容、二次改造、私有化封装、与内部系统对接、生产 BUG 排查,欢迎联系我们协助评估。

围绕 nova-carnivore/bolt12-php 我们能提供哪些服务?
定制开发 / 二次开发

基于 nova-carnivore/bolt12-php 在你已有业务上做功能扩展、字段裁剪、UI 适配、与内部账号 / 权限 / 日志系统的深度对接。

BUG 修复 & 性能优化

线上偶发问题、内存泄漏、慢查询、并发异常等排查修复;针对高流量场景做缓存、队列、索引层面的调优。

项目外包 & 长期维护

承接完整的项目从需求 → 设计 → 开发 → 上线 → 长期运维;也可按月提供技术保姆服务。

yvsm@zunyunkeji.com QQ:316430983 微信:yvsm316 西安尊云信息科技 · 专注 PHP / Go / 分布式系统研发

统计信息

  • 总下载量: 0
  • 月度下载量: 0
  • 日度下载量: 0
  • 收藏数: 0
  • 点击次数: 36
  • 依赖项目数: 0
  • 推荐数: 0

GitHub 信息

  • Stars: 0
  • Watchers: 0
  • Forks: 0
  • 开发语言: PHP

其他信息

  • 授权协议: MIT
  • 更新时间: 2026-02-15