跳至主要內容
高級

Invoice Encoding 發票編碼

深入了解 BOLT 11 發票的編碼格式,包括 Bech32 編碼、欄位結構和簽名驗證。

12 分鐘

BOLT 11 發票結構

BOLT 11 定義了閃電網路發票的標準編碼格式。發票使用 Bech32 編碼, 包含支付所需的所有資訊:金額、目的地、支付哈希、過期時間等。

人類可讀: BOLT 11 發票以 "ln" 開頭,後接網路標識符(bc=主網、tb=測試網), 使其易於識別為閃電發票。

發票格式解析

BOLT 11 Invoice Structure

Example Invoice:
lnbc10u1pj9...omitted...cqzzsxqyz5vq

Breakdown:
• ln        : prefix (Lightning Network)
• bc        : network (bc=mainnet, tb=testnet, bcrt=regtest)
• 10u       : amount (10 micro-bitcoin = 1000 sats)
• 1         : separator
• pj9...    : timestamp + data fields (Bech32 encoded)
• cqzzsxqyz5vq : signature + recovery flag

Amount Units:
┌────────┬─────────────┬─────────────────────────────┐
│ Letter │ Multiplier  │ Conversion                  │
├────────┼─────────────┼─────────────────────────────┤
│ m      │ 0.001       │ milli-bitcoin (100,000 sats)│
│ u      │ 0.000001    │ micro-bitcoin (100 sats)    │
│ n      │ 0.000000001 │ nano-bitcoin (0.1 sats)     │
│ p      │ 1e-12       │ pico-bitcoin (0.0001 sats)  │
└────────┴─────────────┴─────────────────────────────┘

Examples:
• lnbc1m    = 0.001 BTC = 100,000 sats
• lnbc100u  = 0.0001 BTC = 10,000 sats
• lnbc1000n = 0.000001 BTC = 100 sats
• lnbc (no amount) = amount decided by payer

資料欄位(Tagged Fields)

BOLT 11 Tagged Fields

Field Structure:
┌──────────────────────────────────────────────────────────────┐
│ [type: 5 bits] [data_length: 10 bits] [data: variable]      │
└──────────────────────────────────────────────────────────────┘

Required Field:
• p (1) : payment_hash - 256-bit SHA256 hash, used for HTLC

Common Fields:
• d (13) : description - short text (UTF-8)
• h (23) : description_hash - SHA256 of long description
           (mutually exclusive with d)
• x (6)  : expiry - expiration time in seconds (default 3600)
• n (19) : payee_pubkey - receiver public key (33 bytes)
           can be recovered from signature
• c (24) : min_final_cltv_expiry_delta - minimum CLTV delta
           (default 18)

Routing Hints:
• r (3) : routing_info - hints for private channels
  Per hop (51 bytes):
  - pubkey: 33 bytes
  - short_channel_id: 8 bytes
  - fee_base_msat: 4 bytes
  - fee_proportional_millionths: 4 bytes
  - cltv_expiry_delta: 2 bytes

Feature Bits:
• 9 (5) : feature_bits - supported features
  e.g., payment_secret, basic_mpp

Payment Secret:
• s (16) : payment_secret - 256-bit random value
  Prevents probing and forward-hijacking
  Required for MPP

Bech32 編碼

Bech32 Encoding Details

Character Set (32 characters):
qpzry9x8gf2tvdw0s3jn54khce6mua7l

• Excludes confusing chars: 1, b, i, o
• All lowercase to reduce errors

Encoding Process:
1. Raw data (8-bit bytes)
   ↓
2. Convert to 5-bit groups
   ↓
3. Map to Bech32 characters
   ↓
4. Add checksum (6 characters)

Checksum Properties:
• Uses BCH code (Bose-Chaudhuri-Hocquenghem)
• Detects up to 4 character errors
• Guarantees detection of 2 substitution errors within 89 chars
• Provides error position hints

Example Conversion:
Timestamp 1496314658
= 0x5932DC22 (32-bit)
= Split into 7 x 5-bit groups
= [0b01011, 0b00100, ...]
= Bech32 characters

簽名與驗證

Invoice Signature

Signed Message:
SHA256(SHA256(
  hrp (as UTF-8 bytes) ||
  data (as 5-bit values, excluding signature)
))
hrp = "lnbc" or "lntb" etc.

Signature Format (65 bytes):
┌──────────────────────────────────────────────────────────────┐
│ r: 32 bytes        - ECDSA signature r value                 │
│ s: 32 bytes        - ECDSA signature s value                 │
│ recovery: 1 byte   - public key recovery flag (0-3)          │
└──────────────────────────────────────────────────────────────┘

Public Key Recovery:
If invoice has no n (payee_pubkey) field:
1. Compute hash of signed message
2. Use recovery ID to recover pubkey from signature
3. Recovered pubkey is the receiver's node ID
• Benefit: saves 33 bytes

Verification Flow:
1. Decode Bech32
2. Verify checksum
3. Parse fields
4. Verify signature (or recover pubkey)
5. Check expiration time
6. Validate amount format

解碼範例

Invoice Decoding Example

Raw Invoice:
lnbc20m1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rq
wzqfqypqhp58yjmdan79s6qqdhdzgynm4zwqd5d7xmw5fk98klysy043l2ahr
sqsrzjqwryaup9lh50kkranzgcdnn2fgvx390wgj5jd07rwr3vxeje0glclldc
wwnqqqqqqqqqqqqqqqsqfq2zs8t3c

Decoded Result:
• Network: mainnet (bc)
• Amount: 20 mBTC = 2,000,000 sats
• Timestamp: 1496314658 (2017-06-01 12:57:38 UTC)
• payment_hash:
  0001020304050607080900010203040506070809000102030405060708
• description_hash:
  3925b6f67e2c340036ed12093dd44e0368df1b6ea26c53dbe4811f58fd5db8c1
• Expiry: 3600 seconds (default)
• Signature: valid
• Payee pubkey: (recovered from signature)

CLI Decoding:

# LND
lncli decodepayreq <invoice>

# Core Lightning
lightning-cli decode <invoice>

# Online Tool
https://lightningdecoder.com/

程式碼範例

JavaScript 解碼範例:

// 使用 bolt11 庫
import * as bolt11 from 'bolt11';

const invoice = 'lnbc10u1p...';

// 解碼
const decoded = bolt11.decode(invoice);

console.log({
  network: decoded.network,           // 'bc' | 'tb'
  satoshis: decoded.satoshis,         // 金額
  timestamp: decoded.timestamp,       // Unix 時間戳
  timeExpireDate: decoded.timeExpireDate,
  paymentHash: decoded.tags.find(t => t.tagName === 'payment_hash')?.data,
  description: decoded.tags.find(t => t.tagName === 'description')?.data,
  payeeNodeKey: decoded.payeeNodeKey, // 收款人公鑰
});

// 創建發票(需要私鑰)
const encoded = bolt11.encode({
  satoshis: 1000,
  description: 'Test payment',
  timestamp: Math.floor(Date.now() / 1000),
  tags: [
    { tagName: 'payment_hash', data: paymentHash },
    { tagName: 'expire_time', data: 3600 },
  ],
});

const signedInvoice = bolt11.sign(encoded, privateKey);

發票大小限制

沒有硬性限制,但 QR 碼有實際限制。 建議保持在約 1023 字元以下以確保 QR 可讀。

大小寫

Bech32 使用小寫,但解碼器應接受大寫或小寫。 混合大小寫是無效的。

BOLT 12 演進: BOLT 12 Offers 使用 TLV 編碼取代 Bech32, 支援可重複使用的支付請求和更好的隱私。

相關資源

下一步: 了解 LNURL 如何簡化支付流程。

已複製連結
已複製到剪貼簿