mirror of
https://github.com/vitorpamplona/amethyst.git
synced 2026-08-09 08:04:45 +00:00
feat(bolt12): verify compressed payer proofs via merkle reconstruction
Real BOLT12 wallets emit selective-disclosure payer proofs: `invreq_metadata` is always withheld and other invoice fields may be elided for privacy, with `proof_omitted_tlvs` / `proof_missing_hashes` / `proof_leaf_hashes` carrying enough to rebuild the invoice signature's merkle root. The verifier previously reported these as unsupported (cryptoVerified = false), so a zap paid through a real wallet never counted locally. Implement the lightning/bolts#1346 reader: - Bolt12Merkle.reconstructRoot rebuilds the invoice root from the disclosed LnLeaf hashes + supplied nonce leaves (proof_leaf_hashes) + omitted-field markers + missing subtree hashes (consumed post-order DFS, smallest-to-largest). Add emitMissingHashes as the writer dual, unify both on one tree builder. - Fix two latent interop bugs the vectors exposed: the nonce leaf hashes the record's type bytes (not the full encoded TLV), and the payer proof signs under fieldname `proof_signature` (not `signature`). - Bolt12PayerProof gains marker/leaf/missing accessors and the invoice-field range predicate; the verifier reconstructs on every proof (type 0 is always the implied first omitted leaf) and drops the Unsupported result. - Add Bolt12ProofBuilder to mint spec-compliant proofs (tests + future interop), and rewire Bolt12ProofFixture onto it. Validated byte-for-byte against the draft's own conformance suite (bolt12/payer-proof-test.json): all 5 valid vectors verify, all 23 invalid are rejected, and the writer reproduces every vector's compression fields exactly. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01SpgpWLKzgD7vS9Fs4CXTR3
This commit is contained in:
@@ -123,10 +123,12 @@ but is **not** wired into the pay path — we'd add the gate ourselves.
|
||||
A wallet may settle the offer and return no proof → payment succeeds but we
|
||||
can't publish a zap. Phase 1 is unaffected; Phase 2 must degrade gracefully
|
||||
("paid, but no zap receipt available").
|
||||
3. **Our verifier can't check compressed proofs yet** (see
|
||||
`quartz/plans/2026-07-23-bolt12-zap-interop-vectors.md`). Real wallet proofs are
|
||||
compressed, so a zap we send may show locally as unverified. Publishing is fine;
|
||||
local counting waits on the merkle-reconstruction work.
|
||||
3. ~~**Our verifier can't check compressed proofs yet.**~~ **Resolved.** The
|
||||
compressed-proof merkle reconstruction shipped and is validated byte-for-byte
|
||||
against the lightning/bolts#1346 conformance vectors (see
|
||||
`quartz/plans/2026-07-23-bolt12-zap-interop-vectors.md`). Real wallet
|
||||
(selective-disclosure) proofs now reconstruct and verify, so a bound zap counts
|
||||
locally as `cryptoVerified = true`.
|
||||
4. **Maturity.** Both nwc#2 and NIP-2421 are unmerged; few/no wallets implement
|
||||
`pay` today. Gate hard on capability (Phase 3) and keep the intent fallback.
|
||||
|
||||
@@ -191,7 +193,7 @@ BOLT12 rail even if it supports `pay`. Both fail safe toward lightning.
|
||||
|
||||
Known limitations (follow-ons, not blockers):
|
||||
|
||||
- **Compressed proofs aren't locally counted.** A zap we send with a compressed
|
||||
proof is published and valid, but our own `updateZapTotal` won't count it until
|
||||
the merkle-reconstruction lands (see the interop-vectors plan). Other clients with
|
||||
full BOLT12 support can count it.
|
||||
- ~~**Compressed proofs aren't locally counted.**~~ **Resolved.** Compressed
|
||||
(selective-disclosure) proofs now reconstruct and verify, so `updateZapTotal`
|
||||
counts a bound zap locally. Validated against the lightning/bolts#1346
|
||||
conformance vectors — see `quartz/plans/2026-07-23-bolt12-zap-interop-vectors.md`.
|
||||
|
||||
+1
-1
@@ -81,7 +81,7 @@ object Bolt12ZapActions {
|
||||
val proof = Bolt12PayerProof.parse(raw) ?: return null
|
||||
return runCatching {
|
||||
buildMap {
|
||||
put("has_all_required_fields", proof.hasAllRequiredFields())
|
||||
put("has_all_required_fields", proof.hasAllCryptoFields())
|
||||
put("compressed", proof.isCompressed())
|
||||
proof.invreqPayerNote()?.let { put("invreq_payer_note", it) }
|
||||
proof.invreqPayerId()?.let { put("invreq_payer_id", Hex.encode(it)) }
|
||||
|
||||
@@ -1,67 +1,44 @@
|
||||
# BOLT12 zap proof verification — interop test vectors (follow-up)
|
||||
|
||||
Status: **blocked on upstream.** The NIP-XX BOLT12-zap layer (`quartz/…/nipXXBolt12Zaps/`)
|
||||
verifies fully-disclosed payer proofs and reports compressed ones as
|
||||
`Bolt12ProofResult.Unsupported` (surfaced as `cryptoVerified = false`). Two pieces
|
||||
of work are gated on the BOLT12 payer-proof spec ([lightning/bolts#1346]) merging
|
||||
with published test vectors.
|
||||
Status: **done** (both work items shipped), with one standing upstream caveat.
|
||||
`Bolt12ProofVerifier` now reconstructs and fully verifies **compressed** BOLT12
|
||||
payer proofs — the selective-disclosure case real wallets emit — so they count as
|
||||
`cryptoVerified = true` (subject to the usual offer-binding rule). Verified
|
||||
byte-for-byte against the draft's own conformance vectors.
|
||||
|
||||
## Why it's gated
|
||||
## What shipped
|
||||
|
||||
Today the crypto path (`Bolt12ProofVerifier` + `Bolt12Merkle`) is validated only by
|
||||
**self-consistent round-trips** (our own encoder ↔ our own verifier, see
|
||||
`Bolt12ProofFixture` + `Bolt12MerkleTest` + `Bolt12ZapValidatorTest`). That proves
|
||||
internal correctness, not agreement with CLN/LDK. Several constants are our best
|
||||
reading of the still-draft spec and MUST be reconciled against real vectors before
|
||||
we trust wallet-produced proofs:
|
||||
- **Vector-driven interop test.** `bolt12/payer-proof-test.json` from
|
||||
[lightning/bolts#1346] is vendored into `quartz/src/commonTest/resources/bolt12/`
|
||||
and driven by `Bolt12PayerProofVectorTest`: all 5 `valid_vectors` verify, all 23
|
||||
`invalid_vectors` are rejected, and the writer (`Bolt12ProofBuilder`) reproduces
|
||||
each valid vector's `proof_omitted_tlvs` / `proof_missing_hashes` /
|
||||
`proof_leaf_hashes` exactly. The vectors disproved two of our earlier guesses,
|
||||
now fixed:
|
||||
- the **nonce leaf** hashes the record's *type* bytes, not the full encoded TLV
|
||||
(`Bolt12Merkle.nonceLeafHash`);
|
||||
- the **proof signature** field name is `proof_signature`, not `signature`
|
||||
(`Bolt12ProofVerifier.PROOF_SIG_FIELD`).
|
||||
|
||||
- TLV type numbers (`Bolt12PayerProof` companion): 240/241, 1001–1005, 22, 80–91,
|
||||
160–176.
|
||||
- Signature digest tags (`Bolt12ProofVerifier`): `"lightning" + messagename + fieldname`
|
||||
— `INVOICE_MESSAGE`/`PROOF_MESSAGE`/`SIGNATURE_FIELD`. The proof-signature field
|
||||
name especially is a guess.
|
||||
- Merkle leaf/branch tag strings + odd-node promotion (`Bolt12Merkle`) — believed to
|
||||
match LDK, not checked byte-for-byte.
|
||||
- 33-byte compressed `point` → BIP-340 x-only handling / even-y convention for
|
||||
`invoice_node_id` and `invreq_payer_id`.
|
||||
- **Compressed-proof merkle reconstruction.** `Bolt12Merkle.reconstructRoot`
|
||||
rebuilds the invoice root from the disclosed `LnLeaf` hashes + `proof_leaf_hashes`
|
||||
(nonce leaves) + `proof_omitted_tlvs` markers + `proof_missing_hashes` (consumed
|
||||
post-order DFS smallest-to-largest). `invreq_metadata` (type 0) is always the
|
||||
implied first omitted leaf. The `isCompressed()` short-circuit is gone; every
|
||||
proof now goes through reconstruction.
|
||||
|
||||
## Work item 1 — vector-driven interop test
|
||||
## Standing caveat (upstream)
|
||||
|
||||
When `bolt12/payer-proof-test.json` exists in #1346:
|
||||
#1346 is still an unmerged draft. The TLV type numbers, signature digest tag
|
||||
strings, leaf/branch tags, and the invoice/proof field ranges track the current
|
||||
PR head (`vincenzopalazzo/bolts@1be97b2`) and MUST be re-checked if the spec
|
||||
changes before it merges. The vector test is the tripwire: refresh the resource
|
||||
from the merged BOLT and it will flag any drift.
|
||||
|
||||
1. Vendor the vectors into `quartz/src/commonTest/resources/` (or inline the hex).
|
||||
2. Add `Bolt12PayerProofVectorTest`: for each `valid` proof assert
|
||||
`Bolt12ProofVerifier.verify(...) is Valid`; for each `invalid` proof assert the
|
||||
specific rejection reason.
|
||||
3. Fix any constant above that the vectors disprove. If a fix is needed, the
|
||||
round-trip tests will still pass (they move with our encoder) — the vector test
|
||||
is the real gate.
|
||||
## Not covered here
|
||||
|
||||
## Work item 2 — compressed-proof merkle reconstruction
|
||||
|
||||
Real wallet proofs omit non-required invoice TLVs (blinded paths, etc.), which still
|
||||
contributed to the invoice signature's merkle root — so `Bolt12ProofVerifier.verify`
|
||||
currently returns `Unsupported` for them. Implement the reconstruction in
|
||||
`Bolt12Merkle`, rebuilding the invoice root from:
|
||||
|
||||
- disclosed invoice TLVs → compute their `LnLeaf` hashes locally;
|
||||
- `proof_leaf_hashes` (1004) → the `LnNonce` leaves for disclosed fields (can't be
|
||||
computed locally — the nonce tag embeds the possibly-omitted first TLV);
|
||||
- `proof_omitted_tlvs` (1002) → markers for where omitted fields sit in
|
||||
TLV-ascending order;
|
||||
- `proof_missing_hashes` (1003) → sibling subtree hashes for omitted branches,
|
||||
consumed post-order DFS smallest-to-largest.
|
||||
|
||||
Then verify the invoice signature against the reconstructed root and drop the
|
||||
`isCompressed()` short-circuit. Gate acceptance behind Work item 1's vectors — a
|
||||
reconstruction that only round-trips against our own encoder proves nothing about
|
||||
real-wallet interop.
|
||||
|
||||
## Not gated on this
|
||||
|
||||
Runtime validation is fully offline (no network) and everything else in the feature
|
||||
— events, accounting, display, the fully-disclosed crypto path — is done. This
|
||||
document only covers making compressed real-wallet proofs count as
|
||||
`cryptoVerified = true`.
|
||||
Offer↔recipient-identity binding is still out of scope — a verified proof only
|
||||
proves payment to the *embedded* offer, not that the offer belongs to the
|
||||
p-tagged recipient (see `Bolt12ZapValidator.isInvoiceBoundToOffer`).
|
||||
|
||||
[lightning/bolts#1346]: https://github.com/lightning/bolts/pull/1346
|
||||
|
||||
+161
-9
@@ -32,19 +32,22 @@ import com.vitorpamplona.quartz.utils.sha256.sha256
|
||||
* - Tagged hash: `H(tag, msg) = SHA256(SHA256(tag) || SHA256(tag) || msg)`.
|
||||
* - For each signable TLV record (types outside the 240..1000 signature range),
|
||||
* two leaves are produced, in TLV-ascending order:
|
||||
* 1. `H("LnLeaf", tlv)`
|
||||
* 2. `H("LnNonce" || first-tlv, tlv)` where `first-tlv` is the encoded bytes
|
||||
* of the numerically-first signable record.
|
||||
* 1. `H("LnLeaf", tlv)` — over the record's full `type || length || value`.
|
||||
* 2. `H("LnNonce" || first-tlv, type)` — over just the record's `type` field
|
||||
* (its BigSize bytes), where `first-tlv` is the encoded bytes of the
|
||||
* numerically-first signable record. (This is the subtle bit the BOLT
|
||||
* spec's worked example pins down: the nonce leaf hashes the *type*, not
|
||||
* the whole record.)
|
||||
* - Inner nodes: `H("LnBranch", lesser || greater)` (children sorted by their
|
||||
* 32-byte value). Odd nodes are promoted unchanged to the next level.
|
||||
* - The signature message digest is `H("lightning" || messagename || fieldname,
|
||||
* merkle_root)`, verified with BIP-340 against the signing key.
|
||||
*
|
||||
* NOTE: this computes the root over a **fully-disclosed** record set. Compressed
|
||||
* payer proofs (which omit some invoice TLVs and supply `proof_missing_hashes` /
|
||||
* `proof_leaf_hashes` to reconstruct the tree) are not reconstructed here; the
|
||||
* verifier reports those as unverifiable pending validation against the
|
||||
* lightning/bolts#1346 test vectors.
|
||||
* [rootHash] computes the root over a **fully-disclosed** record set.
|
||||
* [reconstructRoot] rebuilds it from a selectively-disclosed payer proof
|
||||
* (lightning/bolts#1346), pulling omitted subtrees from `proof_missing_hashes`.
|
||||
* Both are exercised byte-for-byte against the spec's `payer-proof-test.json`
|
||||
* vectors.
|
||||
*/
|
||||
object Bolt12Merkle {
|
||||
private val LN_NONCE = "LnNonce".encodeToByteArray()
|
||||
@@ -82,7 +85,7 @@ object Bolt12Merkle {
|
||||
var nodes = ArrayList<ByteArray>(signableRecords.size * 2)
|
||||
for (record in signableRecords) {
|
||||
nodes.add(taggedHashPrecomputed(LN_LEAF_TAG_HASH, record.encoded))
|
||||
nodes.add(taggedHashPrecomputed(nonceTagHash, record.encoded))
|
||||
nodes.add(taggedHashPrecomputed(nonceTagHash, BigSize.encode(record.type)))
|
||||
}
|
||||
|
||||
while (nodes.size > 1) {
|
||||
@@ -102,6 +105,155 @@ object Bolt12Merkle {
|
||||
return nodes[0]
|
||||
}
|
||||
|
||||
/**
|
||||
* The `H("LnLeaf", tlv)` leaf hash of a single record (over its full encoded
|
||||
* `type || length || value`).
|
||||
*/
|
||||
fun leafHash(encodedRecord: ByteArray): ByteArray = taggedHashPrecomputed(LN_LEAF_TAG_HASH, encodedRecord)
|
||||
|
||||
/**
|
||||
* The `H("LnNonce" || first-tlv, type)` nonce leaf hash for a record of the
|
||||
* given [type], where [firstTlvEncoded] is the encoded numerically-first
|
||||
* signable record of the message.
|
||||
*/
|
||||
fun nonceLeafHash(
|
||||
firstTlvEncoded: ByteArray,
|
||||
type: Long,
|
||||
): ByteArray = taggedHash(LN_NONCE + firstTlvEncoded, BigSize.encode(type))
|
||||
|
||||
/**
|
||||
* The per-field merkle node — `branch(H("LnLeaf", tlv), nonceLeafHash)` — the
|
||||
* hash that sits directly above a single TLV's leaf pair. A compressed proof
|
||||
* supplies [nonceLeafHash] (from `proof_leaf_hashes`) because it depends on
|
||||
* `first-tlv`, which the proof may have omitted.
|
||||
*/
|
||||
fun fieldNode(
|
||||
encodedRecord: ByteArray,
|
||||
nonceLeafHash: ByteArray,
|
||||
): ByteArray = branch(leafHash(encodedRecord), nonceLeafHash)
|
||||
|
||||
/**
|
||||
* A node of the reconstruction/emission tree. A leaf carries a per-field node
|
||||
* hash ([leafHash], null only for a reader's omitted position) and whether it
|
||||
* was omitted; an inner node carries [left]/[right].
|
||||
*/
|
||||
private class TreeNode private constructor(
|
||||
val left: TreeNode?,
|
||||
val right: TreeNode?,
|
||||
val leafHash: ByteArray?,
|
||||
val omitted: Boolean,
|
||||
) {
|
||||
val isLeaf: Boolean get() = left == null
|
||||
|
||||
companion object {
|
||||
fun leaf(
|
||||
hash: ByteArray?,
|
||||
omitted: Boolean,
|
||||
) = TreeNode(null, null, hash, omitted)
|
||||
|
||||
fun fork(
|
||||
left: TreeNode,
|
||||
right: TreeNode,
|
||||
) = TreeNode(left, right, null, false)
|
||||
}
|
||||
}
|
||||
|
||||
/** Rebuilds the pair-adjacent / promote-odd tree shape [rootHash] flattens. */
|
||||
private fun buildTree(leaves: List<TreeNode>): TreeNode {
|
||||
var level = leaves
|
||||
while (level.size > 1) {
|
||||
val next = ArrayList<TreeNode>((level.size + 1) / 2)
|
||||
var i = 0
|
||||
while (i < level.size) {
|
||||
if (i + 1 < level.size) {
|
||||
next.add(TreeNode.fork(level[i], level[i + 1]))
|
||||
i += 2
|
||||
} else {
|
||||
next.add(level[i])
|
||||
i += 1
|
||||
}
|
||||
}
|
||||
level = next
|
||||
}
|
||||
return level[0]
|
||||
}
|
||||
|
||||
/**
|
||||
* Reconstructs the merkle root of a selectively-disclosed BOLT12 message
|
||||
* (lightning/bolts#1346). [leafNodeHashes] holds one entry per non-signature
|
||||
* leaf of the **original** message in ascending-type order: the per-field node
|
||||
* hash ([fieldNode]) for a disclosed field, or `null` for an omitted one. When
|
||||
* exactly one child of an inner node is entirely omitted, its hash is pulled
|
||||
* from [missingHashes] in the post-order depth-first (smallest-to-largest)
|
||||
* order the writer emitted them.
|
||||
*
|
||||
* Returns `null` if the tree cannot be closed with exactly the supplied
|
||||
* missing hashes (too few, too many, or an entirely-omitted root) — i.e. an
|
||||
* unverifiable proof.
|
||||
*/
|
||||
fun reconstructRoot(
|
||||
leafNodeHashes: List<ByteArray?>,
|
||||
missingHashes: List<ByteArray>,
|
||||
): ByteArray? {
|
||||
if (leafNodeHashes.isEmpty()) return null
|
||||
val tree = buildTree(leafNodeHashes.map { TreeNode.leaf(it, omitted = it == null) })
|
||||
var idx = 0
|
||||
var failed = false
|
||||
|
||||
fun eval(node: TreeNode): ByteArray? {
|
||||
if (failed) return null
|
||||
if (node.isLeaf) return node.leafHash
|
||||
val a = eval(node.left!!)
|
||||
val b = eval(node.right!!)
|
||||
return when {
|
||||
failed -> null
|
||||
a == null && b == null -> null
|
||||
a != null && b != null -> branch(a, b)
|
||||
else -> {
|
||||
if (idx >= missingHashes.size) {
|
||||
failed = true
|
||||
null
|
||||
} else {
|
||||
branch(a ?: b!!, missingHashes[idx++])
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val root = eval(tree)
|
||||
return if (failed || root == null || idx != missingHashes.size) null else root
|
||||
}
|
||||
|
||||
/**
|
||||
* The writer dual of [reconstructRoot]: given every non-signature leaf's
|
||||
* per-field node hash ([leafNodeHashes]) and whether each was omitted
|
||||
* ([leafOmitted]), emits the `proof_missing_hashes` — the hash of each subtree
|
||||
* that is the lone entirely-omitted child of an inner node — in post-order
|
||||
* depth-first (smallest-to-largest) order. Used to mint payer proofs (tests +
|
||||
* interop harness), never on the hot verification path.
|
||||
*/
|
||||
fun emitMissingHashes(
|
||||
leafNodeHashes: List<ByteArray>,
|
||||
leafOmitted: List<Boolean>,
|
||||
): List<ByteArray> {
|
||||
require(leafNodeHashes.size == leafOmitted.size) { "leaf hash / omitted-flag size mismatch" }
|
||||
if (leafNodeHashes.isEmpty()) return emptyList()
|
||||
val tree = buildTree(leafNodeHashes.indices.map { TreeNode.leaf(leafNodeHashes[it], leafOmitted[it]) })
|
||||
val missing = ArrayList<ByteArray>()
|
||||
|
||||
// Returns the subtree hash and whether it is entirely omitted.
|
||||
fun emit(node: TreeNode): Pair<ByteArray, Boolean> {
|
||||
if (node.isLeaf) return node.leafHash!! to node.omitted
|
||||
val (a, aOmitted) = emit(node.left!!)
|
||||
val (b, bOmitted) = emit(node.right!!)
|
||||
if (aOmitted != bOmitted) missing.add(if (aOmitted) a else b)
|
||||
return branch(a, b) to (aOmitted && bOmitted)
|
||||
}
|
||||
|
||||
emit(tree)
|
||||
return missing
|
||||
}
|
||||
|
||||
private fun branch(
|
||||
a: ByteArray,
|
||||
b: ByteArray,
|
||||
|
||||
+61
-18
@@ -24,9 +24,11 @@ package com.vitorpamplona.quartz.nipXXBolt12Zaps.bolt12
|
||||
* A parsed BOLT12 payer proof (`lnp1...`), per lightning/bolts#1346.
|
||||
*
|
||||
* A payer proof copies the relevant offer / invoice-request / invoice TLV fields,
|
||||
* plus the invoice's `signature`, and adds the payer's own `proof_signature`,
|
||||
* the `proof_preimage`, and (for compressed proofs) the merkle-reconstruction
|
||||
* fields `proof_missing_hashes` / `proof_leaf_hashes` / `proof_omitted_tlvs`.
|
||||
* plus the invoice's `signature`, and adds the payer's own `proof_signature`, the
|
||||
* `proof_preimage`, and the merkle-reconstruction fields `proof_missing_hashes` /
|
||||
* `proof_leaf_hashes` / `proof_omitted_tlvs` that let [Bolt12ProofVerifier] rebuild
|
||||
* the invoice root even though `invreq_metadata` (and optionally other fields) are
|
||||
* withheld for privacy.
|
||||
*
|
||||
* The type numbers below are the ones proposed in lightning/bolts#1346 and MUST
|
||||
* be reconciled against the final merged BOLT if they change.
|
||||
@@ -61,32 +63,59 @@ class Bolt12PayerProof(
|
||||
fun proofLeafHashes(): ByteArray? = tlv.value(TYPE_PROOF_LEAF_HASHES)
|
||||
|
||||
/**
|
||||
* True when the proof omits some of the original invoice's TLV fields and
|
||||
* relies on `proof_missing_hashes` to reconstruct the merkle tree. Such
|
||||
* proofs need the compressed-tree reconstruction to verify the invoice
|
||||
* signature (not yet implemented — see [Bolt12ProofVerifier]).
|
||||
* The `proof_omitted_tlvs` marker numbers (BigSize-decoded), empty when the
|
||||
* field is absent. Returns null if the bytes don't decode as a BigSize list —
|
||||
* a malformed proof the verifier must reject.
|
||||
*/
|
||||
fun isCompressed(): Boolean {
|
||||
if (tlv.has(TYPE_PROOF_OMITTED_TLVS)) return true
|
||||
val missing = proofMissingHashes()
|
||||
return missing != null && missing.isNotEmpty()
|
||||
fun omittedTlvMarkers(): List<Long>? {
|
||||
val bytes = proofOmittedTlvs() ?: return emptyList()
|
||||
return try {
|
||||
val reader = TlvReader(bytes)
|
||||
buildList { while (reader.remaining() > 0) add(reader.readBigSize()) }
|
||||
} catch (_: Exception) {
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
/** The signable invoice records (types < 240) — used to recompute the invoice merkle root when fully disclosed. */
|
||||
fun invoiceSignableRecords(): List<TlvRecord> = tlv.records.filter { it.type < TlvRecord.SIGNATURE_TYPE_MIN }
|
||||
/** `proof_leaf_hashes` split into 32-byte hashes, or null if not a whole multiple of 32. */
|
||||
fun leafHashList(): List<ByteArray>? = split32(proofLeafHashes())
|
||||
|
||||
/** `proof_missing_hashes` split into 32-byte hashes, or null if not a whole multiple of 32. */
|
||||
fun missingHashList(): List<ByteArray>? = split32(proofMissingHashes())
|
||||
|
||||
/**
|
||||
* The disclosed invoice (offer / invoice-request / invoice) records — the
|
||||
* fields whose types fall in the invoice ranges 1..239 and
|
||||
* 1_000_000_000..3_999_999_999 (lightning/bolts#1346), excluding the signature
|
||||
* elements and the proof-specific fields (240..999_999_999).
|
||||
*/
|
||||
fun invoiceIncludedRecords(): List<TlvRecord> = tlv.records.filter { isInvoiceField(it.type) }
|
||||
|
||||
/**
|
||||
* True when the proof omits some of the original invoice's TLV fields (i.e.
|
||||
* carries `proof_omitted_tlvs` markers). Every proof reconstructs the invoice
|
||||
* root through the merkle machinery — `invreq_metadata` (type 0) is always
|
||||
* omitted — but this flags the extra selective disclosure for display.
|
||||
*/
|
||||
fun isCompressed(): Boolean = omittedTlvMarkers()?.isNotEmpty() == true
|
||||
|
||||
/** The signable proof records (everything but the 240..1000 signature elements) — used for the payer proof signature. */
|
||||
fun proofSignableRecords(): List<TlvRecord> = tlv.records.filter { !it.isSignatureElement() }
|
||||
|
||||
/** True when every field NIP-XX validation requires is present. */
|
||||
fun hasAllRequiredFields(): Boolean =
|
||||
/**
|
||||
* True when every field the BOLT12 crypto verification requires is present and
|
||||
* well-sized (lightning/bolts#1346 reader rules). `invreq_payer_note` is *not*
|
||||
* required here — the NIP-XX zap binding checks it separately in the validator.
|
||||
*/
|
||||
fun hasAllCryptoFields(): Boolean =
|
||||
invreqPayerId() != null &&
|
||||
invreqPayerNote() != null &&
|
||||
invoicePaymentHash() != null &&
|
||||
invoicePaymentHash()?.size == 32 &&
|
||||
invoiceNodeId() != null &&
|
||||
invoiceSignature()?.size == 64 &&
|
||||
proofSignature()?.size == 64 &&
|
||||
proofPreimage()?.size == 32
|
||||
proofPreimage()?.size == 32 &&
|
||||
tlv.has(TYPE_PROOF_MISSING_HASHES) &&
|
||||
tlv.has(TYPE_PROOF_LEAF_HASHES)
|
||||
|
||||
companion object {
|
||||
// Offer / invoice-request fields copied into the proof.
|
||||
@@ -122,6 +151,20 @@ class Bolt12PayerProof(
|
||||
const val TYPE_PROOF_LEAF_HASHES = 1004L
|
||||
const val TYPE_PROOF_NOTE = 1005L
|
||||
|
||||
/**
|
||||
* The invoice TLV type ranges that participate in the invoice merkle tree,
|
||||
* per lightning/bolts#1346: 1..239 (offer/invreq/invoice) and
|
||||
* 1_000_000_000..3_999_999_999 (high/unknown invoice fields). Excludes the
|
||||
* signature range 240..1000 and the proof-specific fields 1001..999_999_999.
|
||||
*/
|
||||
fun isInvoiceField(type: Long): Boolean = type in 1L..239L || type in 1_000_000_000L..3_999_999_999L
|
||||
|
||||
private fun split32(bytes: ByteArray?): List<ByteArray>? {
|
||||
if (bytes == null) return null
|
||||
if (bytes.size % 32 != 0) return null
|
||||
return (0 until bytes.size / 32).map { bytes.copyOfRange(it * 32, it * 32 + 32) }
|
||||
}
|
||||
|
||||
fun parse(canonicalProof: String): Bolt12PayerProof? {
|
||||
val bytes = Bolt12Bech32.decodeToBytesOrNull(canonicalProof, Bolt12Bech32.PAYER_PROOF_HRP) ?: return null
|
||||
val tlv = TlvStream.readOrNull(bytes) ?: return null
|
||||
|
||||
+155
@@ -0,0 +1,155 @@
|
||||
/*
|
||||
* Copyright (c) 2025 Vitor Pamplona
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to use,
|
||||
* copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
|
||||
* Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
|
||||
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
package com.vitorpamplona.quartz.nipXXBolt12Zaps.bolt12
|
||||
|
||||
/**
|
||||
* Mints a canonical BOLT12 `lnp1...` payer proof from a full invoice, per
|
||||
* lightning/bolts#1346 — the writer dual of [Bolt12ProofVerifier]. Production never
|
||||
* *creates* payer proofs (a paying wallet does); this exists for the self-consistent
|
||||
* test fixtures and the interop harness, and to prove the reader against
|
||||
* writer-produced streams. It reproduces the spec `payer-proof-test.json` vectors'
|
||||
* `proof_omitted_tlvs` / `proof_missing_hashes` / `proof_leaf_hashes` byte-for-byte.
|
||||
*/
|
||||
object Bolt12ProofBuilder {
|
||||
/**
|
||||
* One non-signature invoice TLV. [include] flags whether it is disclosed in the
|
||||
* proof; `invreq_metadata` (type 0) is always omitted regardless (it is the
|
||||
* hashing nonce and must never be revealed).
|
||||
*/
|
||||
class InvoiceField(
|
||||
val type: Long,
|
||||
val value: ByteArray,
|
||||
val include: Boolean,
|
||||
)
|
||||
|
||||
/**
|
||||
* @param invoiceFields ALL non-signature invoice TLVs in ascending type order,
|
||||
* including `invreq_metadata` (type 0).
|
||||
* @param preimage the `proof_preimage`; the caller ensures the invoice's
|
||||
* `invoice_payment_hash` (type 168) is its SHA-256 (or deliberately corrupt).
|
||||
* @param signInvoiceDigest signs the 32-byte invoice merkle digest (node key).
|
||||
* @param signProofDigest signs the 32-byte proof merkle digest (payer key).
|
||||
*/
|
||||
fun build(
|
||||
invoiceFields: List<InvoiceField>,
|
||||
preimage: ByteArray,
|
||||
proofNote: String? = null,
|
||||
signInvoiceDigest: (ByteArray) -> ByteArray,
|
||||
signProofDigest: (ByteArray) -> ByteArray,
|
||||
): String {
|
||||
val firstTlv = TlvRecord(invoiceFields.first().type, invoiceFields.first().value).encoded
|
||||
|
||||
// Invoice signature (240) over the full invoice merkle root.
|
||||
val invoiceRecords = invoiceFields.map { TlvRecord(it.type, it.value) }
|
||||
val invoiceRoot = Bolt12Merkle.rootHash(invoiceRecords)
|
||||
val invoiceSig = signInvoiceDigest(Bolt12Merkle.signatureDigest("invoice", INVOICE_SIG_FIELD, invoiceRoot))
|
||||
|
||||
// Disclosed invoice fields (type 0 is always withheld).
|
||||
val disclosed = invoiceFields.filter { it.include && it.type != 0L }
|
||||
val leafHashes = disclosed.map { Bolt12Merkle.nonceLeafHash(firstTlv, it.type) }
|
||||
val markers = renumberOmitted(invoiceFields)
|
||||
|
||||
val leafNodeHashes =
|
||||
invoiceFields.map { Bolt12Merkle.fieldNode(TlvRecord(it.type, it.value).encoded, Bolt12Merkle.nonceLeafHash(firstTlv, it.type)) }
|
||||
val leafOmitted = invoiceFields.map { !(it.include && it.type != 0L) }
|
||||
val missingHashes = Bolt12Merkle.emitMissingHashes(leafNodeHashes, leafOmitted)
|
||||
|
||||
// Records the proof signature (241) commits to: everything but the 240..1000
|
||||
// signature elements — disclosed invoice fields plus the proof-specific fields.
|
||||
val proofSignable =
|
||||
buildList {
|
||||
disclosed.forEach { add(TlvRecord(it.type, it.value)) }
|
||||
add(TlvRecord(Bolt12PayerProof.TYPE_PROOF_PREIMAGE, preimage))
|
||||
if (markers.isNotEmpty()) add(TlvRecord(Bolt12PayerProof.TYPE_PROOF_OMITTED_TLVS, encodeMarkers(markers)))
|
||||
add(TlvRecord(Bolt12PayerProof.TYPE_PROOF_MISSING_HASHES, concat(missingHashes)))
|
||||
add(TlvRecord(Bolt12PayerProof.TYPE_PROOF_LEAF_HASHES, concat(leafHashes)))
|
||||
if (proofNote != null) add(TlvRecord(Bolt12PayerProof.TYPE_PROOF_NOTE, proofNote.encodeToByteArray()))
|
||||
}.sortedBy { it.type }
|
||||
val proofRoot = Bolt12Merkle.rootHash(proofSignable)
|
||||
val proofSig = signProofDigest(Bolt12Merkle.signatureDigest("payer_proof", PROOF_SIG_FIELD, proofRoot))
|
||||
|
||||
val all =
|
||||
(
|
||||
proofSignable +
|
||||
TlvRecord(Bolt12PayerProof.TYPE_SIGNATURE, invoiceSig) +
|
||||
TlvRecord(Bolt12PayerProof.TYPE_PROOF_SIGNATURE, proofSig)
|
||||
).sortedBy { it.type }
|
||||
return Bolt12Bech32.encode(Bolt12Bech32.PAYER_PROOF_HRP, TlvStream(all).encode())
|
||||
}
|
||||
|
||||
/**
|
||||
* Minimal renumbering of omitted fields into `proof_omitted_tlvs` markers
|
||||
* (lightning/bolts#1346): `invreq_metadata` (type 0) is implied and never
|
||||
* emitted; every other omitted field takes the previous included type + 1, or
|
||||
* the next value after the previous marker (starting at 1), with the
|
||||
* 1_000_000_000 jump once the low range (≤239) is exhausted.
|
||||
*/
|
||||
private fun renumberOmitted(invoiceFields: List<InvoiceField>): List<Long> {
|
||||
val markers = ArrayList<Long>()
|
||||
var prevIncludedType: Long? = null
|
||||
for (f in invoiceFields) {
|
||||
if (f.include && f.type != 0L) {
|
||||
prevIncludedType = f.type
|
||||
continue
|
||||
}
|
||||
if (f.type == 0L) {
|
||||
prevIncludedType = null
|
||||
continue
|
||||
}
|
||||
markers.add(
|
||||
when {
|
||||
prevIncludedType != null -> prevIncludedType + 1
|
||||
markers.isEmpty() -> 1L
|
||||
markers.last() == 239L -> 1_000_000_000L
|
||||
else -> markers.last() + 1
|
||||
},
|
||||
)
|
||||
prevIncludedType = null
|
||||
}
|
||||
return markers
|
||||
}
|
||||
|
||||
private fun encodeMarkers(markers: List<Long>): ByteArray {
|
||||
var size = 0
|
||||
for (m in markers) size += BigSize.encodedSize(m)
|
||||
val out = ByteArray(size)
|
||||
var offset = 0
|
||||
for (m in markers) {
|
||||
val enc = BigSize.encode(m)
|
||||
enc.copyInto(out, offset)
|
||||
offset += enc.size
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
private fun concat(hashes: List<ByteArray>): ByteArray {
|
||||
val out = ByteArray(hashes.size * 32)
|
||||
var offset = 0
|
||||
for (h in hashes) {
|
||||
h.copyInto(out, offset)
|
||||
offset += 32
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
private const val INVOICE_SIG_FIELD = "signature"
|
||||
private const val PROOF_SIG_FIELD = "proof_signature"
|
||||
}
|
||||
+7
-11
@@ -52,22 +52,18 @@ sealed interface Bolt12ProofResult {
|
||||
val reason: Reason,
|
||||
) : Bolt12ProofResult
|
||||
|
||||
/**
|
||||
* The proof could not be verified with the currently-implemented checks (e.g.
|
||||
* a compressed proof needing the not-yet-validated merkle reconstruction).
|
||||
* Whether to surface it as unverified or drop it is the caller's policy.
|
||||
*/
|
||||
@Immutable
|
||||
data class Unsupported(
|
||||
val reason: Reason,
|
||||
) : Bolt12ProofResult
|
||||
|
||||
enum class Reason {
|
||||
MISSING_REQUIRED_FIELDS,
|
||||
PREIMAGE_MISMATCH,
|
||||
|
||||
/**
|
||||
* The selective-disclosure fields (`proof_omitted_tlvs` /
|
||||
* `proof_missing_hashes` / `proof_leaf_hashes`) are malformed or don't
|
||||
* describe a closable merkle tree, so the invoice root can't be rebuilt.
|
||||
*/
|
||||
RECONSTRUCTION_FAILED,
|
||||
INVOICE_SIGNATURE_INVALID,
|
||||
PROOF_SIGNATURE_INVALID,
|
||||
MALFORMED_KEY,
|
||||
COMPRESSED_PROOF_UNSUPPORTED,
|
||||
}
|
||||
}
|
||||
|
||||
+93
-26
@@ -23,59 +23,56 @@ package com.vitorpamplona.quartz.nipXXBolt12Zaps.verify
|
||||
import com.vitorpamplona.quartz.nip01Core.crypto.Nip01Crypto
|
||||
import com.vitorpamplona.quartz.nipXXBolt12Zaps.bolt12.Bolt12Merkle
|
||||
import com.vitorpamplona.quartz.nipXXBolt12Zaps.bolt12.Bolt12PayerProof
|
||||
import com.vitorpamplona.quartz.nipXXBolt12Zaps.bolt12.TlvRecord
|
||||
import com.vitorpamplona.quartz.utils.sha256.sha256
|
||||
|
||||
/**
|
||||
* Cryptographic verification of a BOLT12 `lnp` payer proof, per lightning/bolts#1346:
|
||||
*
|
||||
* 1. `SHA256(proof_preimage) == invoice_payment_hash` — proves the payment settled.
|
||||
* 2. The invoice `signature` (240) is valid over the invoice merkle root, signed
|
||||
* by `invoice_node_id`.
|
||||
* 3. The `proof_signature` (241) is valid over the proof merkle root, signed by
|
||||
* `invreq_payer_id`.
|
||||
* 2. The invoice `signature` (240) is valid over the **reconstructed** invoice
|
||||
* merkle root, signed by `invoice_node_id`. The proof discloses only some of
|
||||
* the invoice's TLV fields (`invreq_metadata` is always withheld); the omitted
|
||||
* branches are rebuilt from `proof_missing_hashes` / `proof_leaf_hashes` /
|
||||
* `proof_omitted_tlvs` via [Bolt12Merkle.reconstructRoot].
|
||||
* 3. The `proof_signature` (241) is valid over the proof's own (fully-disclosed)
|
||||
* merkle root, signed by `invreq_payer_id`.
|
||||
*
|
||||
* The merkle machinery ([Bolt12Merkle]) and the BIP-340 checks ([Nip01Crypto.verify])
|
||||
* are exercised end-to-end by the round-trip tests. **Interop caveat:** the exact
|
||||
* signature field names and, especially, the compressed-proof merkle
|
||||
* reconstruction (`proof_missing_hashes` / `proof_leaf_hashes` / `proof_omitted_tlvs`)
|
||||
* have not been checked against lightning/bolts#1346's `payer-proof-test.json`
|
||||
* vectors — that spec is still an unmerged draft. Until then, this verifier only
|
||||
* fully validates signatures for **fully-disclosed** proofs and reports
|
||||
* compressed proofs as [Bolt12ProofResult.Unsupported]. Callers decide whether an
|
||||
* unsupported crypto check may still be surfaced (labeled unverified) or dropped.
|
||||
* The full reader path — reconstruction and both BIP-340 checks — is exercised
|
||||
* byte-for-byte against the spec's `payer-proof-test.json` vectors
|
||||
* ([Bolt12PayerProofVectorTest]). The BOLT signature message/field names below
|
||||
* still track the unmerged draft and must be reconciled if it changes on merge.
|
||||
*/
|
||||
class Bolt12ProofVerifier {
|
||||
fun verify(proof: Bolt12PayerProof): Bolt12ProofResult {
|
||||
if (!proof.hasAllRequiredFields()) {
|
||||
if (!proof.hasAllCryptoFields()) {
|
||||
return Bolt12ProofResult.Invalid(Bolt12ProofResult.Reason.MISSING_REQUIRED_FIELDS)
|
||||
}
|
||||
|
||||
val preimage = proof.proofPreimage() ?: return Bolt12ProofResult.Invalid(Bolt12ProofResult.Reason.MISSING_REQUIRED_FIELDS)
|
||||
val paymentHash = proof.invoicePaymentHash() ?: return Bolt12ProofResult.Invalid(Bolt12ProofResult.Reason.MISSING_REQUIRED_FIELDS)
|
||||
val preimage = proof.proofPreimage()!!
|
||||
val paymentHash = proof.invoicePaymentHash()!!
|
||||
|
||||
// 1. Settlement proof: the preimage must hash to the invoice payment hash.
|
||||
if (!sha256(preimage).contentEquals(paymentHash)) {
|
||||
return Bolt12ProofResult.Invalid(Bolt12ProofResult.Reason.PREIMAGE_MISMATCH)
|
||||
}
|
||||
|
||||
// 2/3. Signature checks require reconstructing the invoice merkle root; for a
|
||||
// compressed proof that needs the (unverified) missing-hash reconstruction.
|
||||
if (proof.isCompressed()) {
|
||||
return Bolt12ProofResult.Unsupported(Bolt12ProofResult.Reason.COMPRESSED_PROOF_UNSUPPORTED)
|
||||
}
|
||||
|
||||
// 2. Invoice signature over the reconstructed invoice merkle root.
|
||||
val invoiceRoot =
|
||||
reconstructInvoiceRoot(proof)
|
||||
?: return Bolt12ProofResult.Invalid(Bolt12ProofResult.Reason.RECONSTRUCTION_FAILED)
|
||||
val invoiceSig = proof.invoiceSignature()!!
|
||||
val nodeId = xOnly(proof.invoiceNodeId()!!) ?: return Bolt12ProofResult.Invalid(Bolt12ProofResult.Reason.MALFORMED_KEY)
|
||||
val invoiceRoot = Bolt12Merkle.rootHash(proof.invoiceSignableRecords())
|
||||
val invoiceDigest = Bolt12Merkle.signatureDigest(INVOICE_MESSAGE, SIGNATURE_FIELD, invoiceRoot)
|
||||
val invoiceDigest = Bolt12Merkle.signatureDigest(INVOICE_MESSAGE, INVOICE_SIG_FIELD, invoiceRoot)
|
||||
if (!Nip01Crypto.verify(invoiceSig, invoiceDigest, nodeId)) {
|
||||
return Bolt12ProofResult.Invalid(Bolt12ProofResult.Reason.INVOICE_SIGNATURE_INVALID)
|
||||
}
|
||||
|
||||
// 3. Payer proof signature over the proof's own (disclosed) records.
|
||||
val proofSig = proof.proofSignature()!!
|
||||
val payerId = xOnly(proof.invreqPayerId()!!) ?: return Bolt12ProofResult.Invalid(Bolt12ProofResult.Reason.MALFORMED_KEY)
|
||||
val proofRoot = Bolt12Merkle.rootHash(proof.proofSignableRecords())
|
||||
val proofDigest = Bolt12Merkle.signatureDigest(PROOF_MESSAGE, SIGNATURE_FIELD, proofRoot)
|
||||
val proofDigest = Bolt12Merkle.signatureDigest(PROOF_MESSAGE, PROOF_SIG_FIELD, proofRoot)
|
||||
if (!Nip01Crypto.verify(proofSig, proofDigest, payerId)) {
|
||||
return Bolt12ProofResult.Invalid(Bolt12ProofResult.Reason.PROOF_SIGNATURE_INVALID)
|
||||
}
|
||||
@@ -83,6 +80,71 @@ class Bolt12ProofVerifier {
|
||||
return Bolt12ProofResult.Valid(paymentHash = paymentHash, invoiceAmountMillisats = proof.invoiceAmount())
|
||||
}
|
||||
|
||||
/**
|
||||
* Rebuilds the invoice merkle root from a selectively-disclosed proof. Returns
|
||||
* null when the proof's compression fields are malformed or don't describe a
|
||||
* closable tree — an unverifiable proof the caller must not count.
|
||||
*/
|
||||
private fun reconstructInvoiceRoot(proof: Bolt12PayerProof): ByteArray? {
|
||||
val markers = proof.omittedTlvMarkers() ?: return null
|
||||
val leafHashes = proof.leafHashList() ?: return null
|
||||
val missingHashes = proof.missingHashList() ?: return null
|
||||
|
||||
val included = proof.invoiceIncludedRecords().sortedBy { it.type }
|
||||
if (leafHashes.size != included.size) return null
|
||||
if (!markersValid(markers, included)) return null
|
||||
|
||||
// Ordered non-signature leaves of the original invoice: the implied
|
||||
// `invreq_metadata` (type 0) plus every omitted marker plus every disclosed
|
||||
// field, merged in ascending numeric order. Disclosed fields carry their
|
||||
// per-field node hash; omitted positions are null (filled from missing hashes).
|
||||
val positions = ArrayList<Pair<Long, TlvRecord?>>(included.size + markers.size + 1)
|
||||
positions.add(0L to null) // type 0 (invreq_metadata) is always omitted
|
||||
for (m in markers) positions.add(m to null)
|
||||
for (r in included) positions.add(r.type to r)
|
||||
positions.sortBy { it.first }
|
||||
|
||||
var leafIdx = 0
|
||||
val leafNodeHashes =
|
||||
positions.map { (_, record) ->
|
||||
if (record == null) {
|
||||
null
|
||||
} else {
|
||||
Bolt12Merkle.fieldNode(record.encoded, leafHashes[leafIdx++])
|
||||
}
|
||||
}
|
||||
|
||||
return Bolt12Merkle.reconstructRoot(leafNodeHashes, missingHashes)
|
||||
}
|
||||
|
||||
/**
|
||||
* The lightning/bolts#1346 reader rules for `proof_omitted_tlvs`: strictly
|
||||
* ascending, non-zero, within the invoice ranges, never the number of a
|
||||
* disclosed field, and each a valid *minimal renumbering* successor — one more
|
||||
* than a disclosed field, one more than the previous marker (or 0 for the
|
||||
* first), or the 1_000_000_000 jump after 239.
|
||||
*/
|
||||
private fun markersValid(
|
||||
markers: List<Long>,
|
||||
included: List<TlvRecord>,
|
||||
): Boolean {
|
||||
val includedTypes = included.mapTo(HashSet()) { it.type }
|
||||
var prev = 0L
|
||||
for ((i, m) in markers.withIndex()) {
|
||||
if (i > 0 && m <= markers[i - 1]) return false // strict ascending, no duplicates
|
||||
if (m == 0L) return false
|
||||
if (!Bolt12PayerProof.isInvoiceField(m)) return false
|
||||
if (m in includedTypes) return false
|
||||
val validSuccessor =
|
||||
(m - 1) in includedTypes ||
|
||||
m == prev + 1 ||
|
||||
(m == 1_000_000_000L && prev == 239L)
|
||||
if (!validSuccessor) return false
|
||||
prev = m
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
/**
|
||||
* A BOLT12 `point` is a 33-byte compressed secp256k1 key; BIP-340 uses the
|
||||
* 32-byte x-only form. Drop the parity prefix. (Already-x-only 32-byte input
|
||||
@@ -100,6 +162,11 @@ class Bolt12ProofVerifier {
|
||||
// These strings track lightning/bolts#1346 and must be reconciled on merge.
|
||||
const val INVOICE_MESSAGE = "invoice"
|
||||
const val PROOF_MESSAGE = "payer_proof"
|
||||
const val SIGNATURE_FIELD = "signature"
|
||||
|
||||
/** The invoice's own signature field is named `signature`. */
|
||||
const val INVOICE_SIG_FIELD = "signature"
|
||||
|
||||
/** The payer proof's signature field is named `proof_signature`. */
|
||||
const val PROOF_SIG_FIELD = "proof_signature"
|
||||
}
|
||||
}
|
||||
|
||||
+7
-4
@@ -36,10 +36,12 @@ sealed interface Bolt12ZapValidation {
|
||||
* @property paymentHashHex the proof's `invoice_payment_hash`, hex-encoded —
|
||||
* the key clients MUST deduplicate on before summing.
|
||||
* @property proofCryptoVerified true when the BOLT12 payer-proof signatures
|
||||
* were fully verified; false when the proof is structurally valid and bound
|
||||
* but its signatures could not yet be checked (a compressed proof — see
|
||||
* [Bolt12ProofVerifier]). Callers decide whether to count or merely display
|
||||
* the latter, and MUST label it as unverified.
|
||||
* verified **and** the settled invoice is provably the embedded offer's (the
|
||||
* offer publishes an `offer_issuer_id`, uses no blinded paths, and the
|
||||
* invoice node key equals it). False when the signatures verify but the offer
|
||||
* hides its destination (blinded paths / no issuer id), so paying *this* offer
|
||||
* isn't proven — see [Bolt12ProofVerifier]. Callers decide whether to count or
|
||||
* merely display the latter, and MUST label it as unverified.
|
||||
*/
|
||||
@Immutable
|
||||
data class Valid(
|
||||
@@ -94,6 +96,7 @@ sealed interface Bolt12ZapValidation {
|
||||
OFFER_PROOF_MISMATCH,
|
||||
PROOF_MISSING_REQUIRED_FIELDS,
|
||||
PROOF_PREIMAGE_MISMATCH,
|
||||
PROOF_RECONSTRUCTION_FAILED,
|
||||
PROOF_INVOICE_SIGNATURE_INVALID,
|
||||
PROOF_SIGNATURE_INVALID,
|
||||
PROOF_MALFORMED_KEY,
|
||||
|
||||
+1
-3
@@ -138,7 +138,6 @@ class Bolt12ZapValidator(
|
||||
val cryptoOk =
|
||||
when (cryptoResult) {
|
||||
is Bolt12ProofResult.Valid -> true
|
||||
is Bolt12ProofResult.Unsupported -> false
|
||||
is Bolt12ProofResult.Invalid -> return invalid(mapProofReason(cryptoResult.reason))
|
||||
}
|
||||
|
||||
@@ -225,11 +224,10 @@ class Bolt12ZapValidator(
|
||||
when (reason) {
|
||||
Bolt12ProofResult.Reason.MISSING_REQUIRED_FIELDS -> Reason.PROOF_MISSING_REQUIRED_FIELDS
|
||||
Bolt12ProofResult.Reason.PREIMAGE_MISMATCH -> Reason.PROOF_PREIMAGE_MISMATCH
|
||||
Bolt12ProofResult.Reason.RECONSTRUCTION_FAILED -> Reason.PROOF_RECONSTRUCTION_FAILED
|
||||
Bolt12ProofResult.Reason.INVOICE_SIGNATURE_INVALID -> Reason.PROOF_INVOICE_SIGNATURE_INVALID
|
||||
Bolt12ProofResult.Reason.PROOF_SIGNATURE_INVALID -> Reason.PROOF_SIGNATURE_INVALID
|
||||
Bolt12ProofResult.Reason.MALFORMED_KEY -> Reason.PROOF_MALFORMED_KEY
|
||||
// A compressed proof never reaches here (it returns Unsupported, not Invalid).
|
||||
Bolt12ProofResult.Reason.COMPRESSED_PROOF_UNSUPPORTED -> Reason.PROOF_MISSING_REQUIRED_FIELDS
|
||||
}
|
||||
|
||||
private fun invalid(reason: Reason) = Bolt12ZapValidation.Invalid(reason)
|
||||
|
||||
+2
-2
@@ -36,8 +36,8 @@ import kotlin.test.assertTrue
|
||||
* Proves the send-side assembly ([Bolt12ZapBuilder.buildProfileIntent] →
|
||||
* [Bolt12ZapBuilder.payerNote] → [Bolt12ZapBuilder.buildZap]) — the exact path
|
||||
* `Account.sendBolt12Zap` drives — produces a kind:9736 the validator accepts. Uses
|
||||
* a self-consistent fixture proof bound to the built intent (not a wallet interop
|
||||
* vector), so it exercises structure + binding, not the compressed-merkle gap.
|
||||
* a self-consistent fixture proof bound to the built intent; byte-exact wallet
|
||||
* interop is covered separately by [Bolt12PayerProofVectorTest].
|
||||
*/
|
||||
class Bolt12ZapBuilderTest {
|
||||
private val validator = Bolt12ZapValidator()
|
||||
|
||||
+130
@@ -0,0 +1,130 @@
|
||||
/*
|
||||
* Copyright (c) 2025 Vitor Pamplona
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to use,
|
||||
* copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
|
||||
* Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
|
||||
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
package com.vitorpamplona.quartz.nipXXBolt12Zaps.verify
|
||||
|
||||
import com.vitorpamplona.quartz.TestResourceLoader
|
||||
import com.vitorpamplona.quartz.nipXXBolt12Zaps.bolt12.Bolt12PayerProof
|
||||
import com.vitorpamplona.quartz.nipXXBolt12Zaps.bolt12.Bolt12ProofBuilder
|
||||
import com.vitorpamplona.quartz.utils.Hex
|
||||
import kotlinx.serialization.json.Json
|
||||
import kotlinx.serialization.json.jsonArray
|
||||
import kotlinx.serialization.json.jsonObject
|
||||
import kotlinx.serialization.json.jsonPrimitive
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertEquals
|
||||
import kotlin.test.assertIs
|
||||
import kotlin.test.assertTrue
|
||||
import kotlin.test.fail
|
||||
|
||||
/**
|
||||
* Byte-exact interop against the lightning/bolts#1346 conformance suite
|
||||
* (`bolt12/payer-proof-test.json`), the draft's own CLN/LDK-generated vectors.
|
||||
*
|
||||
* - Every `valid_vectors` entry must fully verify ([Bolt12ProofVerifier] returns
|
||||
* [Bolt12ProofResult.Valid]) — this exercises the compressed-proof merkle
|
||||
* reconstruction and both BIP-340 signature checks against real proofs.
|
||||
* - Every `invalid_vectors` entry must be rejected (never [Bolt12ProofResult.Valid]).
|
||||
* - The writer ([Bolt12ProofBuilder]) reproduces each valid vector's
|
||||
* `proof_omitted_tlvs` / `proof_missing_hashes` / `proof_leaf_hashes` exactly.
|
||||
*/
|
||||
class Bolt12PayerProofVectorTest {
|
||||
private val vectors by lazy {
|
||||
Json.parseToJsonElement(TestResourceLoader().loadString("bolt12/payer-proof-test.json")).jsonObject
|
||||
}
|
||||
|
||||
private val verifier = Bolt12ProofVerifier()
|
||||
|
||||
@Test
|
||||
fun everyValidVectorVerifies() {
|
||||
val valid = vectors["valid_vectors"]!!.jsonArray
|
||||
assertTrue(valid.size >= 5, "expected the full valid vector set")
|
||||
for (vector in valid) {
|
||||
val obj = vector.jsonObject
|
||||
val name = obj["name"]!!.jsonPrimitive.content
|
||||
val bech32 = obj["result"]!!.jsonObject["bech32"]!!.jsonPrimitive.content
|
||||
val proof = Bolt12PayerProof.parse(bech32) ?: fail("valid vector '$name' failed to parse")
|
||||
val result = verifier.verify(proof)
|
||||
assertIs<Bolt12ProofResult.Valid>(result, "valid vector '$name' did not verify: $result")
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun everyInvalidVectorIsRejected() {
|
||||
val invalid = vectors["invalid_vectors"]!!.jsonArray
|
||||
assertTrue(invalid.size >= 20, "expected the full invalid vector set")
|
||||
for (vector in invalid) {
|
||||
val obj = vector.jsonObject
|
||||
val reason = obj["reason"]?.jsonPrimitive?.content ?: "?"
|
||||
val bech32 = obj["bech32"]!!.jsonPrimitive.content
|
||||
val proof = Bolt12PayerProof.parse(bech32)
|
||||
// Rejection is either an unparseable stream or any non-Valid crypto result.
|
||||
val verified = proof?.let { verifier.verify(it) }
|
||||
assertTrue(
|
||||
verified !is Bolt12ProofResult.Valid,
|
||||
"invalid vector '$reason' was accepted",
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun writerReproducesEveryValidVectorCompressionFields() {
|
||||
val valid = vectors["valid_vectors"]!!.jsonArray
|
||||
for (vector in valid) {
|
||||
val obj = vector.jsonObject
|
||||
val name = obj["name"]!!.jsonPrimitive.content
|
||||
val working = obj["working"]!!.jsonObject
|
||||
|
||||
val invoiceFields =
|
||||
obj["input"]!!
|
||||
.jsonObject["invoice_fields"]!!
|
||||
.jsonArray
|
||||
.map { it.jsonObject }
|
||||
.filter { it["type"]!!.jsonPrimitive.content.toLong() !in 240L..1000L }
|
||||
.map {
|
||||
Bolt12ProofBuilder.InvoiceField(
|
||||
type = it["type"]!!.jsonPrimitive.content.toLong(),
|
||||
value = Hex.decode(it["hex"]!!.jsonPrimitive.content),
|
||||
include = it["included"]!!.jsonPrimitive.content.toBoolean(),
|
||||
)
|
||||
}
|
||||
|
||||
// Deterministic compression fields don't depend on the signatures, so
|
||||
// dummy signers suffice; we read the minted proof back and compare.
|
||||
val minted =
|
||||
Bolt12ProofBuilder.build(
|
||||
invoiceFields = invoiceFields,
|
||||
preimage = Hex.decode(obj["input"]!!.jsonObject["preimage"]!!.jsonPrimitive.content),
|
||||
signInvoiceDigest = { ByteArray(64) },
|
||||
signProofDigest = { ByteArray(64) },
|
||||
)
|
||||
val proof = Bolt12PayerProof.parse(minted) ?: fail("writer output for '$name' failed to parse")
|
||||
|
||||
val expectedMarkers = working["proof_omitted_tlvs"]!!.jsonArray.map { it.jsonPrimitive.content.toLong() }
|
||||
assertEquals(expectedMarkers, proof.omittedTlvMarkers(), "proof_omitted_tlvs mismatch for '$name'")
|
||||
|
||||
val expectedMissing = working["proof_missing_hashes"]!!.jsonArray.map { it.jsonPrimitive.content }
|
||||
assertEquals(expectedMissing, proof.missingHashList()!!.map { Hex.encode(it) }, "proof_missing_hashes mismatch for '$name'")
|
||||
|
||||
val expectedLeaves = working["proof_leaf_hashes"]!!.jsonArray.map { it.jsonPrimitive.content }
|
||||
assertEquals(expectedLeaves, proof.leafHashList()!!.map { Hex.encode(it) }, "proof_leaf_hashes mismatch for '$name'")
|
||||
}
|
||||
}
|
||||
}
|
||||
+27
-43
@@ -23,19 +23,20 @@ package com.vitorpamplona.quartz.nipXXBolt12Zaps.verify
|
||||
import com.vitorpamplona.quartz.nip01Core.crypto.KeyPair
|
||||
import com.vitorpamplona.quartz.nip01Core.crypto.Nip01Crypto
|
||||
import com.vitorpamplona.quartz.nipXXBolt12Zaps.bolt12.Bolt12Bech32
|
||||
import com.vitorpamplona.quartz.nipXXBolt12Zaps.bolt12.Bolt12Merkle
|
||||
import com.vitorpamplona.quartz.nipXXBolt12Zaps.bolt12.Bolt12Offer
|
||||
import com.vitorpamplona.quartz.nipXXBolt12Zaps.bolt12.Bolt12PayerProof
|
||||
import com.vitorpamplona.quartz.nipXXBolt12Zaps.bolt12.Bolt12ProofBuilder
|
||||
import com.vitorpamplona.quartz.nipXXBolt12Zaps.bolt12.Bolt12Values
|
||||
import com.vitorpamplona.quartz.nipXXBolt12Zaps.bolt12.TlvRecord
|
||||
import com.vitorpamplona.quartz.nipXXBolt12Zaps.bolt12.TlvStream
|
||||
import com.vitorpamplona.quartz.utils.sha256.sha256
|
||||
|
||||
/**
|
||||
* Builds matched BOLT12 offers and payer proofs for tests, self-signing them with
|
||||
* Quartz's own secp256k1 so the whole merkle + BIP-340 path is exercised. This is
|
||||
* a self-consistent construction, not a CLN/LDK interop vector — see
|
||||
* [Bolt12ProofVerifier].
|
||||
* Builds matched BOLT12 offers and payer proofs for tests, minting spec-compliant
|
||||
* (lightning/bolts#1346) proofs through [Bolt12ProofBuilder] and self-signing them
|
||||
* with Quartz's own secp256k1 so the whole reconstruction + merkle + BIP-340 path
|
||||
* is exercised. This is a self-consistent construction; byte-exact CLN/LDK interop
|
||||
* is covered separately by [Bolt12PayerProofVectorTest].
|
||||
*/
|
||||
object Bolt12ProofFixture {
|
||||
/** A 33-byte compressed point (even parity) wrapping an x-only key. */
|
||||
@@ -73,48 +74,31 @@ object Bolt12ProofFixture {
|
||||
// the preimage check (SHA256(preimage) != invoice_payment_hash) is what rejects it.
|
||||
val paymentHash = sha256(preimage).also { if (corruptPaymentHash) it[0] = (it[0] + 1).toByte() }
|
||||
|
||||
// The invoice's signed records (types < 240), in ascending order.
|
||||
val invoiceRecords =
|
||||
// The full invoice's non-signature TLVs, ascending. invreq_metadata (type 0)
|
||||
// is always present and always withheld; invreq_amount (82) is the field the
|
||||
// `compressed` flag selectively omits.
|
||||
val invoiceFields =
|
||||
listOf(
|
||||
TlvRecord(Bolt12PayerProof.TYPE_OFFER_ISSUER_ID, nodePoint),
|
||||
TlvRecord(Bolt12PayerProof.TYPE_INVREQ_AMOUNT, Bolt12Values.tu64ToBytes(amountMillisats)),
|
||||
TlvRecord(Bolt12PayerProof.TYPE_INVREQ_PAYER_ID, payerPoint),
|
||||
TlvRecord(Bolt12PayerProof.TYPE_INVREQ_PAYER_NOTE, payerNote.encodeToByteArray()),
|
||||
TlvRecord(Bolt12PayerProof.TYPE_INVOICE_PAYMENT_HASH, paymentHash),
|
||||
TlvRecord(Bolt12PayerProof.TYPE_INVOICE_AMOUNT, Bolt12Values.tu64ToBytes(amountMillisats)),
|
||||
TlvRecord(Bolt12PayerProof.TYPE_INVOICE_NODE_ID, nodePoint),
|
||||
Bolt12ProofBuilder.InvoiceField(TYPE_INVREQ_METADATA, ByteArray(16), include = false),
|
||||
Bolt12ProofBuilder.InvoiceField(Bolt12PayerProof.TYPE_OFFER_ISSUER_ID, nodePoint, include = true),
|
||||
Bolt12ProofBuilder.InvoiceField(Bolt12PayerProof.TYPE_INVREQ_AMOUNT, Bolt12Values.tu64ToBytes(amountMillisats), include = !compressed),
|
||||
Bolt12ProofBuilder.InvoiceField(Bolt12PayerProof.TYPE_INVREQ_PAYER_ID, payerPoint, include = true),
|
||||
Bolt12ProofBuilder.InvoiceField(Bolt12PayerProof.TYPE_INVREQ_PAYER_NOTE, payerNote.encodeToByteArray(), include = true),
|
||||
Bolt12ProofBuilder.InvoiceField(Bolt12PayerProof.TYPE_INVOICE_PAYMENT_HASH, paymentHash, include = true),
|
||||
Bolt12ProofBuilder.InvoiceField(Bolt12PayerProof.TYPE_INVOICE_AMOUNT, Bolt12Values.tu64ToBytes(amountMillisats), include = true),
|
||||
Bolt12ProofBuilder.InvoiceField(Bolt12PayerProof.TYPE_INVOICE_NODE_ID, nodePoint, include = true),
|
||||
)
|
||||
val invoiceRoot = Bolt12Merkle.rootHash(invoiceRecords)
|
||||
|
||||
val invoiceSigningKey = if (breakInvoiceSignature) payerLightningKey else nodeKey
|
||||
val invoiceSig =
|
||||
Nip01Crypto.sign(
|
||||
Bolt12Merkle.signatureDigest(Bolt12ProofVerifier.INVOICE_MESSAGE, Bolt12ProofVerifier.SIGNATURE_FIELD, invoiceRoot),
|
||||
invoiceSigningKey.privKey!!,
|
||||
)
|
||||
|
||||
val preimageRecord = TlvRecord(Bolt12PayerProof.TYPE_PROOF_PREIMAGE, preimage)
|
||||
|
||||
// The payer proof signs everything but the 240..1000 signature elements.
|
||||
val proofSignable = invoiceRecords + preimageRecord
|
||||
val proofRoot = Bolt12Merkle.rootHash(proofSignable)
|
||||
val proofSigningKey = if (breakProofSignature) nodeKey else payerLightningKey
|
||||
val proofSig =
|
||||
Nip01Crypto.sign(
|
||||
Bolt12Merkle.signatureDigest(Bolt12ProofVerifier.PROOF_MESSAGE, Bolt12ProofVerifier.SIGNATURE_FIELD, proofRoot),
|
||||
proofSigningKey.privKey!!,
|
||||
)
|
||||
|
||||
val records =
|
||||
buildList {
|
||||
addAll(invoiceRecords)
|
||||
add(TlvRecord(Bolt12PayerProof.TYPE_SIGNATURE, invoiceSig))
|
||||
add(TlvRecord(Bolt12PayerProof.TYPE_PROOF_SIGNATURE, proofSig))
|
||||
add(preimageRecord)
|
||||
if (compressed) {
|
||||
// A non-empty proof_missing_hashes marks the proof as compressed.
|
||||
add(TlvRecord(Bolt12PayerProof.TYPE_PROOF_MISSING_HASHES, ByteArray(32) { 9 }))
|
||||
}
|
||||
}
|
||||
return Bolt12Bech32.encode(Bolt12Bech32.PAYER_PROOF_HRP, TlvStream(records).encode())
|
||||
return Bolt12ProofBuilder.build(
|
||||
invoiceFields = invoiceFields,
|
||||
preimage = preimage,
|
||||
signInvoiceDigest = { digest -> Nip01Crypto.sign(digest, invoiceSigningKey.privKey!!) },
|
||||
signProofDigest = { digest -> Nip01Crypto.sign(digest, proofSigningKey.privKey!!) },
|
||||
)
|
||||
}
|
||||
|
||||
private const val TYPE_INVREQ_METADATA = 0L
|
||||
}
|
||||
|
||||
+5
-2
@@ -76,8 +76,11 @@ class Bolt12ZapValidatorTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
fun acceptsButFlagsACompressedProofAsUnverified() =
|
||||
fun verifiesACompressedProofThroughMerkleReconstruction() =
|
||||
runTest {
|
||||
// The proof withholds `invreq_amount`, forcing the verifier to rebuild the
|
||||
// invoice merkle root from `proof_missing_hashes` before checking the
|
||||
// invoice signature. Bound to a directly-addressed offer, it is fully verified.
|
||||
val signer = NostrSignerInternal(KeyPair())
|
||||
val nodeKey = KeyPair()
|
||||
val preimage = ByteArray(32) { (it + 1).toByte() }
|
||||
@@ -88,7 +91,7 @@ class Bolt12ZapValidatorTest {
|
||||
|
||||
val result = validator.validate(signedZap(signer, intent, proof))
|
||||
assertIs<Bolt12ZapValidation.Valid>(result)
|
||||
assertTrue(!result.proofCryptoVerified, "a compressed proof is bound but not yet crypto-verified")
|
||||
assertTrue(result.proofCryptoVerified, "a compressed proof bound to the offer must verify")
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -0,0 +1,969 @@
|
||||
{
|
||||
"payer_secret": "4242424242424242424242424242424242424242424242424242424242424242",
|
||||
"keys": {
|
||||
"offer_issuer_id": {
|
||||
"secret": "4646464646464646464646464646464646464646464646464646464646464646",
|
||||
"pubkey": "024bc2a31265153f07e70e0bab08724e6b85e217f8cd628ceb62974247bb493382"
|
||||
},
|
||||
"invreq_payer_id": {
|
||||
"secret": "4242424242424242424242424242424242424242424242424242424242424242",
|
||||
"pubkey": "0324653eac434488002cc06bbfb7f10fe18991e35f9fe4302dbea6d2353dc0ab1c"
|
||||
},
|
||||
"first_node_id": {
|
||||
"secret": "4343434343434343434343434343434343434343434343434343434343434343",
|
||||
"pubkey": "027f31ebc5462c1fdce1b737ecff52d37d75dea43ce11c74d25aa297165faa2007"
|
||||
},
|
||||
"first_path_key": {
|
||||
"secret": "4444444444444444444444444444444444444444444444444444444444444444",
|
||||
"pubkey": "032c0b7cf95324a07d05398b240174dc0c2be444d96b159aa6c7f7b1e668680991"
|
||||
},
|
||||
"blinded_node_id": {
|
||||
"secret": "4545454545454545454545454545454545454545454545454545454545454545",
|
||||
"pubkey": "02edabbd16b41c8371b92ef2f04c1185b4f03b6dcd52ba9b78d9d7c89c8f221145"
|
||||
},
|
||||
"invoice_node_id": {
|
||||
"secret": "4646464646464646464646464646464646464646464646464646464646464646",
|
||||
"pubkey": "024bc2a31265153f07e70e0bab08724e6b85e217f8cd628ceb62974247bb493382"
|
||||
}
|
||||
},
|
||||
"valid_vectors": [
|
||||
{
|
||||
"name": "full_disclosure",
|
||||
"input": {
|
||||
"invoice": "lni1qqgqqqqqqqqqqqqqqqqqqqqqqqqqq93pqf9u9gcjv52n7pl8pc96kzrjfe4ctcshlrxk9r8tv2t5y3amfyecy5szq059sggry3jnatzrgjyqqtxqdwlm0ug0uxyerc6lnljrqtd75mfr20wq4vw2qasz0uc7h32x9s0aecdhxlk075kn046aafpuuyw8f5j652t3vha2yqrsxtqt0nu4xf9q05znnzeyq96dcrptu3zdj6c4n2nv0aa3ue5xszv3qypwm2aaz66peqm3hyh09uzvzxzmfupmdhx49w5m0rva0jyu3u3pz3gqzqqqqqqqqqqqqqqqqqqqqqqqqqq2y8qqqqqqzqqqqqpqqqcqqqqqqqqqqqzqqqqqqqqqqqq9qqq2gpr82fuc32pqwtxkappzcsrlkmgfs6g0zyct0hkhashh7hsaxz7e65slq9fkx7f65qsrazhq6zqqqqqqqqqqqqqqqqqqqzczzqjtc233yeg48ur7wrst4vy8ynntsh3p07xdv2xwkc5hgfrmkjfnstcyp7aextn2n4d5mzx2phwfe70cejyqaaq78my4wndgna3ymwyc4vlf60kke258g33nhp23vldqpygemxp54ecl0vr0qfejm3xpm6atq4mlavkstcqszss",
|
||||
"invoice_hex": "0010000000000000000000000000000000001621024bc2a31265153f07e70e0bab08724e6b85e217f8cd628ceb62974247bb493382520203e858210324653eac434488002cc06bbfb7f10fe18991e35f9fe4302dbea6d2353dc0ab1ca076027f31ebc5462c1fdce1b737ecff52d37d75dea43ce11c74d25aa297165faa2007032c0b7cf95324a07d05398b240174dc0c2be444d96b159aa6c7f7b1e6686809910102edabbd16b41c8371b92ef2f04c1185b4f03b6dcd52ba9b78d9d7c89c8f221145001000000000000000000000000000000000a21c00000001000000020003000000000000000400000000000000050000a40467527988a82072cd6e8422c407fb6d098690f1130b7ded7ec2f7f5e1d30bd9d521f015363793aa0203e8ae0d08000000000000000000000000b021024bc2a31265153f07e70e0bab08724e6b85e217f8cd628ceb62974247bb493382f040fbb932e6a9d5b4d88ca0ddc9cf9f8cc880ef41e3ec9574da89f624db898ab3e9d3ed6caa8744633b855167da009119d9834ae71f7b06f02732dc4c1debab0577feb2d05e010142",
|
||||
"preimage": "0101010101010101010101010101010101010101010101010101010101010101",
|
||||
"invoice_fields": [
|
||||
{
|
||||
"type": 0,
|
||||
"len": 16,
|
||||
"hex": "00000000000000000000000000000000",
|
||||
"included": false
|
||||
},
|
||||
{
|
||||
"type": 22,
|
||||
"len": 33,
|
||||
"hex": "024bc2a31265153f07e70e0bab08724e6b85e217f8cd628ceb62974247bb493382",
|
||||
"included": true
|
||||
},
|
||||
{
|
||||
"type": 82,
|
||||
"len": 2,
|
||||
"hex": "03e8",
|
||||
"included": true
|
||||
},
|
||||
{
|
||||
"type": 88,
|
||||
"len": 33,
|
||||
"hex": "0324653eac434488002cc06bbfb7f10fe18991e35f9fe4302dbea6d2353dc0ab1c",
|
||||
"included": true
|
||||
},
|
||||
{
|
||||
"type": 160,
|
||||
"len": 118,
|
||||
"hex": "027f31ebc5462c1fdce1b737ecff52d37d75dea43ce11c74d25aa297165faa2007032c0b7cf95324a07d05398b240174dc0c2be444d96b159aa6c7f7b1e6686809910102edabbd16b41c8371b92ef2f04c1185b4f03b6dcd52ba9b78d9d7c89c8f221145001000000000000000000000000000000000",
|
||||
"included": true
|
||||
},
|
||||
{
|
||||
"type": 162,
|
||||
"len": 28,
|
||||
"hex": "00000001000000020003000000000000000400000000000000050000",
|
||||
"included": true
|
||||
},
|
||||
{
|
||||
"type": 164,
|
||||
"len": 4,
|
||||
"hex": "67527988",
|
||||
"included": true
|
||||
},
|
||||
{
|
||||
"type": 168,
|
||||
"len": 32,
|
||||
"hex": "72cd6e8422c407fb6d098690f1130b7ded7ec2f7f5e1d30bd9d521f015363793",
|
||||
"included": true
|
||||
},
|
||||
{
|
||||
"type": 170,
|
||||
"len": 2,
|
||||
"hex": "03e8",
|
||||
"included": true
|
||||
},
|
||||
{
|
||||
"type": 174,
|
||||
"len": 13,
|
||||
"hex": "08000000000000000000000000",
|
||||
"included": true
|
||||
},
|
||||
{
|
||||
"type": 176,
|
||||
"len": 33,
|
||||
"hex": "024bc2a31265153f07e70e0bab08724e6b85e217f8cd628ceb62974247bb493382",
|
||||
"included": true
|
||||
},
|
||||
{
|
||||
"type": 240,
|
||||
"len": 64,
|
||||
"hex": "fbb932e6a9d5b4d88ca0ddc9cf9f8cc880ef41e3ec9574da89f624db898ab3e9d3ed6caa8744633b855167da009119d9834ae71f7b06f02732dc4c1debab0577",
|
||||
"included": false
|
||||
},
|
||||
{
|
||||
"type": 3000000001,
|
||||
"len": 1,
|
||||
"hex": "42",
|
||||
"included": true
|
||||
}
|
||||
]
|
||||
},
|
||||
"working": {
|
||||
"invoice_merkle_root": "cb9e0c81bb39fc244f9f523c748ab4de0e09f1a5fef74359c2e1f7cc7cdc7447",
|
||||
"invoice_sighash": "538aab18f82285032db132cecf7275ba2cbb462ef1f4d151588f836d0ce47aae",
|
||||
"invoice_signature": "fbb932e6a9d5b4d88ca0ddc9cf9f8cc880ef41e3ec9574da89f624db898ab3e9d3ed6caa8744633b855167da009119d9834ae71f7b06f02732dc4c1debab0577",
|
||||
"proof_merkle_root": "d461a2dd3099e2c43ccef4c3c8d36f720948fe21712ea94dceccb4bddb0c9e5e",
|
||||
"proof_leaf_hashes": [
|
||||
"8c9057ed88f3c5a6b6441dcac3b5e4cefb3615904d7362b86e78427fb695f461",
|
||||
"8dc54a97453dee6f207fa5216a30f1567442712ca98852bc789b73885029283c",
|
||||
"f2deaf5f30be3ced89fc7c24d422819bf06af0e48a31423bbd0e2634f3c3de67",
|
||||
"f54f80c94a87383f2a8ef7c3e461c62b67a51da5bccf6cd96a7dbab29bea51fa",
|
||||
"7849b8b856e1d2a63d9ce7dc1a78e05cbb2def1f5d7709c48e8707e0a59fe51e",
|
||||
"19e7e4eee6bf56c6c589fe50035490c1a7c91b753cb8007c4b52838a6772f997",
|
||||
"f0191c35000247554b8d0a196898a794bf3de89982571178d931affb654f0c1a",
|
||||
"dc0b8de03f1a0b0531bff146982d7d613ef6e1ef8d3bdd9590971fc18d835ffb",
|
||||
"c14cfffaa314261bcbb2ed4ca24d5717bb608d8a6cc9910790bc1d49af7858ab",
|
||||
"7e92b77b9e3843650f6cd7ee94b6753ea9df3533710b04dee686ad376515a5cb",
|
||||
"abaab91b367e30fea7026daf9f2590bb7e9cc31db8221f4013c67289e38f22c8"
|
||||
],
|
||||
"proof_omitted_tlvs": [],
|
||||
"proof_missing_hashes": [
|
||||
"0b510ba4c6884d603159ced2f0ca21e772424b59e52a2191bbfbcf07377805a1"
|
||||
]
|
||||
},
|
||||
"result": {
|
||||
"payer_sig": "4961333409f453b5518fcbc662936fcb46e6c1db8d963c44b67d5677f0ffce3ac5c42293d1bc1298b0d67320a772e20a06c069dfa7079df9207b675357735dd7",
|
||||
"proof_fields": [
|
||||
{
|
||||
"type": 22,
|
||||
"len": 33,
|
||||
"hex": "024bc2a31265153f07e70e0bab08724e6b85e217f8cd628ceb62974247bb493382"
|
||||
},
|
||||
{
|
||||
"type": 82,
|
||||
"len": 2,
|
||||
"hex": "03e8"
|
||||
},
|
||||
{
|
||||
"type": 88,
|
||||
"len": 33,
|
||||
"hex": "0324653eac434488002cc06bbfb7f10fe18991e35f9fe4302dbea6d2353dc0ab1c"
|
||||
},
|
||||
{
|
||||
"type": 160,
|
||||
"len": 118,
|
||||
"hex": "027f31ebc5462c1fdce1b737ecff52d37d75dea43ce11c74d25aa297165faa2007032c0b7cf95324a07d05398b240174dc0c2be444d96b159aa6c7f7b1e6686809910102edabbd16b41c8371b92ef2f04c1185b4f03b6dcd52ba9b78d9d7c89c8f221145001000000000000000000000000000000000"
|
||||
},
|
||||
{
|
||||
"type": 162,
|
||||
"len": 28,
|
||||
"hex": "00000001000000020003000000000000000400000000000000050000"
|
||||
},
|
||||
{
|
||||
"type": 164,
|
||||
"len": 4,
|
||||
"hex": "67527988"
|
||||
},
|
||||
{
|
||||
"type": 168,
|
||||
"len": 32,
|
||||
"hex": "72cd6e8422c407fb6d098690f1130b7ded7ec2f7f5e1d30bd9d521f015363793"
|
||||
},
|
||||
{
|
||||
"type": 170,
|
||||
"len": 2,
|
||||
"hex": "03e8"
|
||||
},
|
||||
{
|
||||
"type": 174,
|
||||
"len": 13,
|
||||
"hex": "08000000000000000000000000"
|
||||
},
|
||||
{
|
||||
"type": 176,
|
||||
"len": 33,
|
||||
"hex": "024bc2a31265153f07e70e0bab08724e6b85e217f8cd628ceb62974247bb493382"
|
||||
},
|
||||
{
|
||||
"type": 240,
|
||||
"len": 64,
|
||||
"hex": "fbb932e6a9d5b4d88ca0ddc9cf9f8cc880ef41e3ec9574da89f624db898ab3e9d3ed6caa8744633b855167da009119d9834ae71f7b06f02732dc4c1debab0577"
|
||||
},
|
||||
{
|
||||
"type": 241,
|
||||
"len": 64,
|
||||
"hex": "4961333409f453b5518fcbc662936fcb46e6c1db8d963c44b67d5677f0ffce3ac5c42293d1bc1298b0d67320a772e20a06c069dfa7079df9207b675357735dd7"
|
||||
},
|
||||
{
|
||||
"type": 1001,
|
||||
"len": 32,
|
||||
"hex": "0101010101010101010101010101010101010101010101010101010101010101"
|
||||
},
|
||||
{
|
||||
"type": 1003,
|
||||
"len": 32,
|
||||
"hex": "0b510ba4c6884d603159ced2f0ca21e772424b59e52a2191bbfbcf07377805a1"
|
||||
},
|
||||
{
|
||||
"type": 1004,
|
||||
"len": 352,
|
||||
"hex": "8c9057ed88f3c5a6b6441dcac3b5e4cefb3615904d7362b86e78427fb695f4618dc54a97453dee6f207fa5216a30f1567442712ca98852bc789b73885029283cf2deaf5f30be3ced89fc7c24d422819bf06af0e48a31423bbd0e2634f3c3de67f54f80c94a87383f2a8ef7c3e461c62b67a51da5bccf6cd96a7dbab29bea51fa7849b8b856e1d2a63d9ce7dc1a78e05cbb2def1f5d7709c48e8707e0a59fe51e19e7e4eee6bf56c6c589fe50035490c1a7c91b753cb8007c4b52838a6772f997f0191c35000247554b8d0a196898a794bf3de89982571178d931affb654f0c1adc0b8de03f1a0b0531bff146982d7d613ef6e1ef8d3bdd9590971fc18d835ffbc14cfffaa314261bcbb2ed4ca24d5717bb608d8a6cc9910790bc1d49af7858ab7e92b77b9e3843650f6cd7ee94b6753ea9df3533710b04dee686ad376515a5cbabaab91b367e30fea7026daf9f2590bb7e9cc31db8221f4013c67289e38f22c8"
|
||||
},
|
||||
{
|
||||
"type": 3000000001,
|
||||
"len": 1,
|
||||
"hex": "42"
|
||||
}
|
||||
],
|
||||
"bech32": "lnp1zcssyj7z5vfx29flqlnsuzatppeyu6u9ugtl3ntz3n4k996zg7a5jvuz2gpq86zcyypjgef743p5fzqq9nqxh0ah7y87rzv3ud0eleps9kl2d5348hq2k89qwcp87v0tc4rzc87uuxmn0m8l2tfh6aw75s7wz8r56fd299ckt74zqpcr9s9he72nyjs86pfe3vjqzaxups47g3xedv2e4fk877c7v6rgpxgszqhd4w73ddqusdcmjthj7pxprpd57qakmn2jh2dh3kwhezwg7gs3g5qpqqqqqqqqqqqqqqqqqqqqqqqqqq9zrsqqqqqpqqqqqqsqqvqqqqqqqqqqqpqqqqqqqqqqqqzsqq9yq3n4y7vg4qs89ntwss3vgplmd5ycdy83zv9hmmt7ctmltcwnp0va2g0sz5mr0ya2qgp73tsdpqqqqqqqqqqqqqqqqqqqpvppqf9u9gcjv52n7pl8pc96kzrjfe4ctcshlrxk9r8tv2t5y3amfyec9uzqlwun9e4f6k6d3r9qmhyul8uvezqw7s0raj2hfk5f7cjdhzv2k05a8mtv42r5gcems4gk0ksqjyvanq62uu0hkphsyuedcnqaaw4s2al3gpykzve5p8698d233l9uvc5ndl95dekpmwxev0zyke74valsll8r43wyy2far0qjnzcdvueq5aewyzsxcp5alfc8nhujq7m82dthxhwhl5p7jgqpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpq87s86eqpdgshfxx3pxkqv2eemf0pj3puaeyyj6eu54zrydml08swdmcqksl6qlvl5qkprys2lkc3u7956myg8w2cw67fnhmxc2eqntnv2uxu7zz07mftarp3hz549698hhx7grl55sk5v832e6yyufv4xy990rcndecs5pf9q709h40tuctu08d3878cfx5y2qehur27rjg5v2z8w7suf3570pauel4f7qvjj588qlj4rhhc0jxr33tv7j3mfdueakdj6nah2efh6j3lfuynw9c2msa9f3annnacxncupwtkt00rawhwzwy36rs0c99nlj3ux08unhwd06kcmzcnljsqd2fpsd8eydh209cqp7yk55r3fnh97vh7qv3cdgqqfr42judpgvk3x98jjlnm6yesft3z7xexxhlke20psddczuduql35zc9xxllz35c947kz0hku8hc6w7ajkgfw87p3kp4l77pfnll4gc5ycduhvhdfj3y64chhdsgmznvexgs0y9ur4y677zc4dlf9dmmncuyxeg0dnt7a99kw5l2nhe4xdcskpx7u6r26dm9zkjuh2a2hydnvl3sl6nsymd0nujepwm7nnp3mwpzraqp83nj383c7gkgl6edqhspq9pq"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "minimal_disclosure",
|
||||
"input": {
|
||||
"invoice": "lni1qqgqqqqqqqqqqqqqqqqqqqqqqqqqq93pqf9u9gcjv52n7pl8pc96kzrjfe4ctcshlrxk9r8tv2t5y3amfyecy5szq059sggry3jnatzrgjyqqtxqdwlm0ug0uxyerc6lnljrqtd75mfr20wq4vw2qasz0uc7h32x9s0aecdhxlk075kn046aafpuuyw8f5j652t3vha2yqrsxtqt0nu4xf9q05znnzeyq96dcrptu3zdj6c4n2nv0aa3ue5xszv3qypwm2aaz66peqm3hyh09uzvzxzmfupmdhx49w5m0rva0jyu3u3pz3gqzqqqqqqqqqqqqqqqqqqqqqqqqqq2y8qqqqqqzqqqqqpqqqcqqqqqqqqqqqzqqqqqqqqqqqq9qqq2gpr82fuc32pqwtxkappzcsrlkmgfs6g0zyct0hkhashh7hsaxz7e65slq9fkx7f65qsrazczzqjtc233yeg48ur7wrst4vy8ynntsh3p07xdv2xwkc5hgfrmkjfnstcyqz3nyfzk3d42umkj2gqjh4l7zpevq04aefl6gnu4kql3e5ymu29s4q7fcvsst9uvmqx6q6yhje3vsraqple9pnxuf5vtwz0l68r6uvvs",
|
||||
"invoice_hex": "0010000000000000000000000000000000001621024bc2a31265153f07e70e0bab08724e6b85e217f8cd628ceb62974247bb493382520203e858210324653eac434488002cc06bbfb7f10fe18991e35f9fe4302dbea6d2353dc0ab1ca076027f31ebc5462c1fdce1b737ecff52d37d75dea43ce11c74d25aa297165faa2007032c0b7cf95324a07d05398b240174dc0c2be444d96b159aa6c7f7b1e6686809910102edabbd16b41c8371b92ef2f04c1185b4f03b6dcd52ba9b78d9d7c89c8f221145001000000000000000000000000000000000a21c00000001000000020003000000000000000400000000000000050000a40467527988a82072cd6e8422c407fb6d098690f1130b7ded7ec2f7f5e1d30bd9d521f015363793aa0203e8b021024bc2a31265153f07e70e0bab08724e6b85e217f8cd628ceb62974247bb493382f0400a33224568b6aae6ed252012bd7fe1072c03ebdca7fa44f95b03f1cd09be28b0a83c9c32105978cd80da068979662c80fa00ff250ccdc4d18b709ffd1c7ae319",
|
||||
"preimage": "0101010101010101010101010101010101010101010101010101010101010101",
|
||||
"invoice_fields": [
|
||||
{
|
||||
"type": 0,
|
||||
"len": 16,
|
||||
"hex": "00000000000000000000000000000000",
|
||||
"included": false
|
||||
},
|
||||
{
|
||||
"type": 22,
|
||||
"len": 33,
|
||||
"hex": "024bc2a31265153f07e70e0bab08724e6b85e217f8cd628ceb62974247bb493382",
|
||||
"included": false
|
||||
},
|
||||
{
|
||||
"type": 82,
|
||||
"len": 2,
|
||||
"hex": "03e8",
|
||||
"included": false
|
||||
},
|
||||
{
|
||||
"type": 88,
|
||||
"len": 33,
|
||||
"hex": "0324653eac434488002cc06bbfb7f10fe18991e35f9fe4302dbea6d2353dc0ab1c",
|
||||
"included": true
|
||||
},
|
||||
{
|
||||
"type": 160,
|
||||
"len": 118,
|
||||
"hex": "027f31ebc5462c1fdce1b737ecff52d37d75dea43ce11c74d25aa297165faa2007032c0b7cf95324a07d05398b240174dc0c2be444d96b159aa6c7f7b1e6686809910102edabbd16b41c8371b92ef2f04c1185b4f03b6dcd52ba9b78d9d7c89c8f221145001000000000000000000000000000000000",
|
||||
"included": false
|
||||
},
|
||||
{
|
||||
"type": 162,
|
||||
"len": 28,
|
||||
"hex": "00000001000000020003000000000000000400000000000000050000",
|
||||
"included": false
|
||||
},
|
||||
{
|
||||
"type": 164,
|
||||
"len": 4,
|
||||
"hex": "67527988",
|
||||
"included": false
|
||||
},
|
||||
{
|
||||
"type": 168,
|
||||
"len": 32,
|
||||
"hex": "72cd6e8422c407fb6d098690f1130b7ded7ec2f7f5e1d30bd9d521f015363793",
|
||||
"included": true
|
||||
},
|
||||
{
|
||||
"type": 170,
|
||||
"len": 2,
|
||||
"hex": "03e8",
|
||||
"included": false
|
||||
},
|
||||
{
|
||||
"type": 176,
|
||||
"len": 33,
|
||||
"hex": "024bc2a31265153f07e70e0bab08724e6b85e217f8cd628ceb62974247bb493382",
|
||||
"included": true
|
||||
},
|
||||
{
|
||||
"type": 240,
|
||||
"len": 64,
|
||||
"hex": "0a33224568b6aae6ed252012bd7fe1072c03ebdca7fa44f95b03f1cd09be28b0a83c9c32105978cd80da068979662c80fa00ff250ccdc4d18b709ffd1c7ae319",
|
||||
"included": false
|
||||
}
|
||||
]
|
||||
},
|
||||
"working": {
|
||||
"invoice_merkle_root": "0501ea6d4ad9fe7fce7edd5e3795987bd409d66c5709c2a17f9c0dfb839e3d8e",
|
||||
"invoice_sighash": "41ce7b274b0e73e60dd6abf4fa51ccae892b161adc24d4099f620b12c59a03e5",
|
||||
"invoice_signature": "0a33224568b6aae6ed252012bd7fe1072c03ebdca7fa44f95b03f1cd09be28b0a83c9c32105978cd80da068979662c80fa00ff250ccdc4d18b709ffd1c7ae319",
|
||||
"proof_merkle_root": "ccc704b73e8190c71bf2ac3661d631c8c5ac502b78641708c8e61c0a1c8ebb72",
|
||||
"proof_leaf_hashes": [
|
||||
"f2deaf5f30be3ced89fc7c24d422819bf06af0e48a31423bbd0e2634f3c3de67",
|
||||
"f0191c35000247554b8d0a196898a794bf3de89982571178d931affb654f0c1a",
|
||||
"7e92b77b9e3843650f6cd7ee94b6753ea9df3533710b04dee686ad376515a5cb"
|
||||
],
|
||||
"proof_omitted_tlvs": [
|
||||
1,
|
||||
2,
|
||||
89,
|
||||
90,
|
||||
91,
|
||||
169
|
||||
],
|
||||
"proof_missing_hashes": [
|
||||
"bf8cb2b1d6fa9bcdcab501b59f82c65c506b7f43514737f7197f1fcfeaebad41",
|
||||
"b9406f4ce526a6a0d4e0b3a63ed89a832e31cb9939dfe1a7b5dd7232d32c02ab",
|
||||
"cd9c44b53b31700c9ed0e3330ce425f7f18fac2fc1d566a34468439274f0e316",
|
||||
"9f9830f2c3070cfbad13fde30ee36cd7143591164ed12040a9cd595c96840ac9",
|
||||
"998ab7fa9c743fb9dbdb0d8d46fbe3ad333400bd07f328dcdb6008790bc9d2db"
|
||||
]
|
||||
},
|
||||
"result": {
|
||||
"payer_sig": "cebc25d40a2d927b5ebcab8400f542fbb7a8f462e8dd802bb13e050b9bf293b7457c19b46a476740f97c9d6ec141f23434c5d4fa253a1d2eb8896ebad99455cc",
|
||||
"proof_fields": [
|
||||
{
|
||||
"type": 88,
|
||||
"len": 33,
|
||||
"hex": "0324653eac434488002cc06bbfb7f10fe18991e35f9fe4302dbea6d2353dc0ab1c"
|
||||
},
|
||||
{
|
||||
"type": 168,
|
||||
"len": 32,
|
||||
"hex": "72cd6e8422c407fb6d098690f1130b7ded7ec2f7f5e1d30bd9d521f015363793"
|
||||
},
|
||||
{
|
||||
"type": 176,
|
||||
"len": 33,
|
||||
"hex": "024bc2a31265153f07e70e0bab08724e6b85e217f8cd628ceb62974247bb493382"
|
||||
},
|
||||
{
|
||||
"type": 240,
|
||||
"len": 64,
|
||||
"hex": "0a33224568b6aae6ed252012bd7fe1072c03ebdca7fa44f95b03f1cd09be28b0a83c9c32105978cd80da068979662c80fa00ff250ccdc4d18b709ffd1c7ae319"
|
||||
},
|
||||
{
|
||||
"type": 241,
|
||||
"len": 64,
|
||||
"hex": "cebc25d40a2d927b5ebcab8400f542fbb7a8f462e8dd802bb13e050b9bf293b7457c19b46a476740f97c9d6ec141f23434c5d4fa253a1d2eb8896ebad99455cc"
|
||||
},
|
||||
{
|
||||
"type": 1001,
|
||||
"len": 32,
|
||||
"hex": "0101010101010101010101010101010101010101010101010101010101010101"
|
||||
},
|
||||
{
|
||||
"type": 1002,
|
||||
"len": 6,
|
||||
"hex": "0102595a5ba9"
|
||||
},
|
||||
{
|
||||
"type": 1003,
|
||||
"len": 160,
|
||||
"hex": "bf8cb2b1d6fa9bcdcab501b59f82c65c506b7f43514737f7197f1fcfeaebad41b9406f4ce526a6a0d4e0b3a63ed89a832e31cb9939dfe1a7b5dd7232d32c02abcd9c44b53b31700c9ed0e3330ce425f7f18fac2fc1d566a34468439274f0e3169f9830f2c3070cfbad13fde30ee36cd7143591164ed12040a9cd595c96840ac9998ab7fa9c743fb9dbdb0d8d46fbe3ad333400bd07f328dcdb6008790bc9d2db"
|
||||
},
|
||||
{
|
||||
"type": 1004,
|
||||
"len": 96,
|
||||
"hex": "f2deaf5f30be3ced89fc7c24d422819bf06af0e48a31423bbd0e2634f3c3de67f0191c35000247554b8d0a196898a794bf3de89982571178d931affb654f0c1a7e92b77b9e3843650f6cd7ee94b6753ea9df3533710b04dee686ad376515a5cb"
|
||||
}
|
||||
],
|
||||
"bech32": "lnp1tqssxfr986kyx3ygqqkvq6alklcslcvfj834l8lyxqkmafkjx57up2cu4qs89ntwss3vgplmd5ycdy83zv9hmmt7ctmltcwnp0va2g0sz5mr0yasyypyhs4rzfj320c8uu8qh2cgwf8xhp0zzluv6c5vad3fwsj8hdyn8qhsgq9rxgj9dzm24ehdy5sp90tluyrjcqltmjnl538etvplrngfhc5tp2punsepqktcekqd5p5f09nzeq86qrlj2rxdcngckuyll5w84cce79qva0p96s9zmynmt672hpqq74p0hdag733w3hvq9wcnupgtn0ef8d690svmg6j8vaq0jlyadmq5ru35xnzaf7398gwjawyfd6adn9z4en7s86fqqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyql6ql2qcqsyk26tw5l6qlt5zlcev436mafhnw2k5qmt8uzcew9q6mlgdg5wdlhr9l3lnl2awk5rw2qdaxw2f4x5r2wpvax8mvf4qewx89ejwwluxnmthtjxtfjcq4tekwyfdfmx9cqe8ksuveseep97lccltp0c82kdg6ydppeya8suvtflxps7tpswr8m45flmccwudkdw9p4jytya5fqgz5u6k2uj6zq4jve32ml48r587uahkcd34r0hcadxv6qp0g87v5dekmqppushjwjm07s8mrq7t027heshc7wmz0u0sjdgg5pn0cx4u8y3gc5ywaapcnrfu7rmenlqxgux5qqy364fwxs5xtgnznef0eaazvcy4c30rvnrtlmv48scxn7j2mhh83cgdjs7mxha62tvaf7480n2vm3pvzdae5x45mk29d9ev"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "with_note",
|
||||
"input": {
|
||||
"invoice": "lni1qqgqqqqqqqqqqqqqqqqqqqqqqqqqq93pqf9u9gcjv52n7pl8pc96kzrjfe4ctcshlrxk9r8tv2t5y3amfyecy5szq059sggry3jnatzrgjyqqtxqdwlm0ug0uxyerc6lnljrqtd75mfr20wq4vw2qasz0uc7h32x9s0aecdhxlk075kn046aafpuuyw8f5j652t3vha2yqrsxtqt0nu4xf9q05znnzeyq96dcrptu3zdj6c4n2nv0aa3ue5xszv3qypwm2aaz66peqm3hyh09uzvzxzmfupmdhx49w5m0rva0jyu3u3pz3gqzqqqqqqqqqqqqqqqqqqqqqqqqqq2y8qqqqqqzqqqqqpqqqcqqqqqqqqqqqzqqqqqqqqqqqq9qqq2gpr82fuc32pqwtxkappzcsrlkmgfs6g0zyct0hkhashh7hsaxz7e65slq9fkx7f65qsrazczzqjtc233yeg48ur7wrst4vy8ynntsh3p07xdv2xwkc5hgfrmkjfnstcyqz3nyfzk3d42umkj2gqjh4l7zpevq04aefl6gnu4kql3e5ymu29s4q7fcvsst9uvmqx6q6yhje3vsraqple9pnxuf5vtwz0l68r6uvvs",
|
||||
"invoice_hex": "0010000000000000000000000000000000001621024bc2a31265153f07e70e0bab08724e6b85e217f8cd628ceb62974247bb493382520203e858210324653eac434488002cc06bbfb7f10fe18991e35f9fe4302dbea6d2353dc0ab1ca076027f31ebc5462c1fdce1b737ecff52d37d75dea43ce11c74d25aa297165faa2007032c0b7cf95324a07d05398b240174dc0c2be444d96b159aa6c7f7b1e6686809910102edabbd16b41c8371b92ef2f04c1185b4f03b6dcd52ba9b78d9d7c89c8f221145001000000000000000000000000000000000a21c00000001000000020003000000000000000400000000000000050000a40467527988a82072cd6e8422c407fb6d098690f1130b7ded7ec2f7f5e1d30bd9d521f015363793aa0203e8b021024bc2a31265153f07e70e0bab08724e6b85e217f8cd628ceb62974247bb493382f0400a33224568b6aae6ed252012bd7fe1072c03ebdca7fa44f95b03f1cd09be28b0a83c9c32105978cd80da068979662c80fa00ff250ccdc4d18b709ffd1c7ae319",
|
||||
"preimage": "0101010101010101010101010101010101010101010101010101010101010101",
|
||||
"note": "test note",
|
||||
"invoice_fields": [
|
||||
{
|
||||
"type": 0,
|
||||
"len": 16,
|
||||
"hex": "00000000000000000000000000000000",
|
||||
"included": false
|
||||
},
|
||||
{
|
||||
"type": 22,
|
||||
"len": 33,
|
||||
"hex": "024bc2a31265153f07e70e0bab08724e6b85e217f8cd628ceb62974247bb493382",
|
||||
"included": false
|
||||
},
|
||||
{
|
||||
"type": 82,
|
||||
"len": 2,
|
||||
"hex": "03e8",
|
||||
"included": false
|
||||
},
|
||||
{
|
||||
"type": 88,
|
||||
"len": 33,
|
||||
"hex": "0324653eac434488002cc06bbfb7f10fe18991e35f9fe4302dbea6d2353dc0ab1c",
|
||||
"included": true
|
||||
},
|
||||
{
|
||||
"type": 160,
|
||||
"len": 118,
|
||||
"hex": "027f31ebc5462c1fdce1b737ecff52d37d75dea43ce11c74d25aa297165faa2007032c0b7cf95324a07d05398b240174dc0c2be444d96b159aa6c7f7b1e6686809910102edabbd16b41c8371b92ef2f04c1185b4f03b6dcd52ba9b78d9d7c89c8f221145001000000000000000000000000000000000",
|
||||
"included": false
|
||||
},
|
||||
{
|
||||
"type": 162,
|
||||
"len": 28,
|
||||
"hex": "00000001000000020003000000000000000400000000000000050000",
|
||||
"included": false
|
||||
},
|
||||
{
|
||||
"type": 164,
|
||||
"len": 4,
|
||||
"hex": "67527988",
|
||||
"included": false
|
||||
},
|
||||
{
|
||||
"type": 168,
|
||||
"len": 32,
|
||||
"hex": "72cd6e8422c407fb6d098690f1130b7ded7ec2f7f5e1d30bd9d521f015363793",
|
||||
"included": true
|
||||
},
|
||||
{
|
||||
"type": 170,
|
||||
"len": 2,
|
||||
"hex": "03e8",
|
||||
"included": false
|
||||
},
|
||||
{
|
||||
"type": 176,
|
||||
"len": 33,
|
||||
"hex": "024bc2a31265153f07e70e0bab08724e6b85e217f8cd628ceb62974247bb493382",
|
||||
"included": true
|
||||
},
|
||||
{
|
||||
"type": 240,
|
||||
"len": 64,
|
||||
"hex": "0a33224568b6aae6ed252012bd7fe1072c03ebdca7fa44f95b03f1cd09be28b0a83c9c32105978cd80da068979662c80fa00ff250ccdc4d18b709ffd1c7ae319",
|
||||
"included": false
|
||||
}
|
||||
]
|
||||
},
|
||||
"working": {
|
||||
"invoice_merkle_root": "0501ea6d4ad9fe7fce7edd5e3795987bd409d66c5709c2a17f9c0dfb839e3d8e",
|
||||
"invoice_sighash": "41ce7b274b0e73e60dd6abf4fa51ccae892b161adc24d4099f620b12c59a03e5",
|
||||
"invoice_signature": "0a33224568b6aae6ed252012bd7fe1072c03ebdca7fa44f95b03f1cd09be28b0a83c9c32105978cd80da068979662c80fa00ff250ccdc4d18b709ffd1c7ae319",
|
||||
"proof_merkle_root": "327c38426d1d557f3669f19cdb440187e312679eadcfb61a9a8dcb0098639467",
|
||||
"proof_leaf_hashes": [
|
||||
"f2deaf5f30be3ced89fc7c24d422819bf06af0e48a31423bbd0e2634f3c3de67",
|
||||
"f0191c35000247554b8d0a196898a794bf3de89982571178d931affb654f0c1a",
|
||||
"7e92b77b9e3843650f6cd7ee94b6753ea9df3533710b04dee686ad376515a5cb"
|
||||
],
|
||||
"proof_omitted_tlvs": [
|
||||
1,
|
||||
2,
|
||||
89,
|
||||
90,
|
||||
91,
|
||||
169
|
||||
],
|
||||
"proof_missing_hashes": [
|
||||
"bf8cb2b1d6fa9bcdcab501b59f82c65c506b7f43514737f7197f1fcfeaebad41",
|
||||
"b9406f4ce526a6a0d4e0b3a63ed89a832e31cb9939dfe1a7b5dd7232d32c02ab",
|
||||
"cd9c44b53b31700c9ed0e3330ce425f7f18fac2fc1d566a34468439274f0e316",
|
||||
"9f9830f2c3070cfbad13fde30ee36cd7143591164ed12040a9cd595c96840ac9",
|
||||
"998ab7fa9c743fb9dbdb0d8d46fbe3ad333400bd07f328dcdb6008790bc9d2db"
|
||||
]
|
||||
},
|
||||
"result": {
|
||||
"payer_sig": "2a47f98770ae814119d682a7b19f7ce9e050a3bb49d9b0a031c46d9cb57a3075ddc23a742f6d33bc4ec8e1778327494bea76d2ee564625e99bfb95cc209a7722",
|
||||
"proof_fields": [
|
||||
{
|
||||
"type": 88,
|
||||
"len": 33,
|
||||
"hex": "0324653eac434488002cc06bbfb7f10fe18991e35f9fe4302dbea6d2353dc0ab1c"
|
||||
},
|
||||
{
|
||||
"type": 168,
|
||||
"len": 32,
|
||||
"hex": "72cd6e8422c407fb6d098690f1130b7ded7ec2f7f5e1d30bd9d521f015363793"
|
||||
},
|
||||
{
|
||||
"type": 176,
|
||||
"len": 33,
|
||||
"hex": "024bc2a31265153f07e70e0bab08724e6b85e217f8cd628ceb62974247bb493382"
|
||||
},
|
||||
{
|
||||
"type": 240,
|
||||
"len": 64,
|
||||
"hex": "0a33224568b6aae6ed252012bd7fe1072c03ebdca7fa44f95b03f1cd09be28b0a83c9c32105978cd80da068979662c80fa00ff250ccdc4d18b709ffd1c7ae319"
|
||||
},
|
||||
{
|
||||
"type": 241,
|
||||
"len": 64,
|
||||
"hex": "2a47f98770ae814119d682a7b19f7ce9e050a3bb49d9b0a031c46d9cb57a3075ddc23a742f6d33bc4ec8e1778327494bea76d2ee564625e99bfb95cc209a7722"
|
||||
},
|
||||
{
|
||||
"type": 1001,
|
||||
"len": 32,
|
||||
"hex": "0101010101010101010101010101010101010101010101010101010101010101"
|
||||
},
|
||||
{
|
||||
"type": 1002,
|
||||
"len": 6,
|
||||
"hex": "0102595a5ba9"
|
||||
},
|
||||
{
|
||||
"type": 1003,
|
||||
"len": 160,
|
||||
"hex": "bf8cb2b1d6fa9bcdcab501b59f82c65c506b7f43514737f7197f1fcfeaebad41b9406f4ce526a6a0d4e0b3a63ed89a832e31cb9939dfe1a7b5dd7232d32c02abcd9c44b53b31700c9ed0e3330ce425f7f18fac2fc1d566a34468439274f0e3169f9830f2c3070cfbad13fde30ee36cd7143591164ed12040a9cd595c96840ac9998ab7fa9c743fb9dbdb0d8d46fbe3ad333400bd07f328dcdb6008790bc9d2db"
|
||||
},
|
||||
{
|
||||
"type": 1004,
|
||||
"len": 96,
|
||||
"hex": "f2deaf5f30be3ced89fc7c24d422819bf06af0e48a31423bbd0e2634f3c3de67f0191c35000247554b8d0a196898a794bf3de89982571178d931affb654f0c1a7e92b77b9e3843650f6cd7ee94b6753ea9df3533710b04dee686ad376515a5cb"
|
||||
},
|
||||
{
|
||||
"type": 1005,
|
||||
"len": 9,
|
||||
"hex": "74657374206e6f7465"
|
||||
}
|
||||
],
|
||||
"bech32": "lnp1tqssxfr986kyx3ygqqkvq6alklcslcvfj834l8lyxqkmafkjx57up2cu4qs89ntwss3vgplmd5ycdy83zv9hmmt7ctmltcwnp0va2g0sz5mr0yasyypyhs4rzfj320c8uu8qh2cgwf8xhp0zzluv6c5vad3fwsj8hdyn8qhsgq9rxgj9dzm24ehdy5sp90tluyrjcqltmjnl538etvplrngfhc5tp2punsepqktcekqd5p5f09nzeq86qrlj2rxdcngckuyll5w84cce79qz53lesac2aq2pr8tg9fa3na7wnczs5wa5nkds5qcugmvuk4arqawacga8gtmdxw7yaj8pw7pjwj2tafmd9mjkgcj7nxlmjhxzpxnhyt7s86fqqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyql6ql2qcqsyk26tw5l6qlt5zlcev436mafhnw2k5qmt8uzcew9q6mlgdg5wdlhr9l3lnl2awk5rw2qdaxw2f4x5r2wpvax8mvf4qewx89ejwwluxnmthtjxtfjcq4tekwyfdfmx9cqe8ksuveseep97lccltp0c82kdg6ydppeya8suvtflxps7tpswr8m45flmccwudkdw9p4jytya5fqgz5u6k2uj6zq4jve32ml48r587uahkcd34r0hcadxv6qp0g87v5dekmqppushjwjm07s8mrq7t027heshc7wmz0u0sjdgg5pn0cx4u8y3gc5ywaapcnrfu7rmenlqxgux5qqy364fwxs5xtgnznef0eaazvcy4c30rvnrtlmv48scxn7j2mhh83cgdjs7mxha62tvaf7480n2vm3pvzdae5x45mk29d9e07s8mgfw3jhxapqdehhgeg"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "left_subtree_omitted",
|
||||
"input": {
|
||||
"invoice": "lni1qqgqqqqqqqqqqqqqqqqqqqqqqqqqq93pqf9u9gcjv52n7pl8pc96kzrjfe4ctcshlrxk9r8tv2t5y3amfyecy5szq059sggry3jnatzrgjyqqtxqdwlm0ug0uxyerc6lnljrqtd75mfr20wq4vw2qasz0uc7h32x9s0aecdhxlk075kn046aafpuuyw8f5j652t3vha2yqrsxtqt0nu4xf9q05znnzeyq96dcrptu3zdj6c4n2nv0aa3ue5xszv3qypwm2aaz66peqm3hyh09uzvzxzmfupmdhx49w5m0rva0jyu3u3pz3gqzqqqqqqqqqqqqqqqqqqqqqqqqqq2y8qqqqqqzqqqqqpqqqcqqqqqqqqqqqzqqqqqqqqqqqq9qqq2gpr82fuc32pqwtxkappzcsrlkmgfs6g0zyct0hkhashh7hsaxz7e65slq9fkx7f65qsrazczzqjtc233yeg48ur7wrst4vy8ynntsh3p07xdv2xwkc5hgfrmkjfnstcyqz3nyfzk3d42umkj2gqjh4l7zpevq04aefl6gnu4kql3e5ymu29s4q7fcvsst9uvmqx6q6yhje3vsraqple9pnxuf5vtwz0l68r6uvvs",
|
||||
"invoice_hex": "0010000000000000000000000000000000001621024bc2a31265153f07e70e0bab08724e6b85e217f8cd628ceb62974247bb493382520203e858210324653eac434488002cc06bbfb7f10fe18991e35f9fe4302dbea6d2353dc0ab1ca076027f31ebc5462c1fdce1b737ecff52d37d75dea43ce11c74d25aa297165faa2007032c0b7cf95324a07d05398b240174dc0c2be444d96b159aa6c7f7b1e6686809910102edabbd16b41c8371b92ef2f04c1185b4f03b6dcd52ba9b78d9d7c89c8f221145001000000000000000000000000000000000a21c00000001000000020003000000000000000400000000000000050000a40467527988a82072cd6e8422c407fb6d098690f1130b7ded7ec2f7f5e1d30bd9d521f015363793aa0203e8b021024bc2a31265153f07e70e0bab08724e6b85e217f8cd628ceb62974247bb493382f0400a33224568b6aae6ed252012bd7fe1072c03ebdca7fa44f95b03f1cd09be28b0a83c9c32105978cd80da068979662c80fa00ff250ccdc4d18b709ffd1c7ae319",
|
||||
"preimage": "0101010101010101010101010101010101010101010101010101010101010101",
|
||||
"invoice_fields": [
|
||||
{
|
||||
"type": 0,
|
||||
"len": 16,
|
||||
"hex": "00000000000000000000000000000000",
|
||||
"included": false
|
||||
},
|
||||
{
|
||||
"type": 22,
|
||||
"len": 33,
|
||||
"hex": "024bc2a31265153f07e70e0bab08724e6b85e217f8cd628ceb62974247bb493382",
|
||||
"included": false
|
||||
},
|
||||
{
|
||||
"type": 82,
|
||||
"len": 2,
|
||||
"hex": "03e8",
|
||||
"included": false
|
||||
},
|
||||
{
|
||||
"type": 88,
|
||||
"len": 33,
|
||||
"hex": "0324653eac434488002cc06bbfb7f10fe18991e35f9fe4302dbea6d2353dc0ab1c",
|
||||
"included": true
|
||||
},
|
||||
{
|
||||
"type": 160,
|
||||
"len": 118,
|
||||
"hex": "027f31ebc5462c1fdce1b737ecff52d37d75dea43ce11c74d25aa297165faa2007032c0b7cf95324a07d05398b240174dc0c2be444d96b159aa6c7f7b1e6686809910102edabbd16b41c8371b92ef2f04c1185b4f03b6dcd52ba9b78d9d7c89c8f221145001000000000000000000000000000000000",
|
||||
"included": false
|
||||
},
|
||||
{
|
||||
"type": 162,
|
||||
"len": 28,
|
||||
"hex": "00000001000000020003000000000000000400000000000000050000",
|
||||
"included": false
|
||||
},
|
||||
{
|
||||
"type": 164,
|
||||
"len": 4,
|
||||
"hex": "67527988",
|
||||
"included": false
|
||||
},
|
||||
{
|
||||
"type": 168,
|
||||
"len": 32,
|
||||
"hex": "72cd6e8422c407fb6d098690f1130b7ded7ec2f7f5e1d30bd9d521f015363793",
|
||||
"included": true
|
||||
},
|
||||
{
|
||||
"type": 170,
|
||||
"len": 2,
|
||||
"hex": "03e8",
|
||||
"included": true
|
||||
},
|
||||
{
|
||||
"type": 176,
|
||||
"len": 33,
|
||||
"hex": "024bc2a31265153f07e70e0bab08724e6b85e217f8cd628ceb62974247bb493382",
|
||||
"included": true
|
||||
},
|
||||
{
|
||||
"type": 240,
|
||||
"len": 64,
|
||||
"hex": "0a33224568b6aae6ed252012bd7fe1072c03ebdca7fa44f95b03f1cd09be28b0a83c9c32105978cd80da068979662c80fa00ff250ccdc4d18b709ffd1c7ae319",
|
||||
"included": false
|
||||
}
|
||||
]
|
||||
},
|
||||
"working": {
|
||||
"invoice_merkle_root": "0501ea6d4ad9fe7fce7edd5e3795987bd409d66c5709c2a17f9c0dfb839e3d8e",
|
||||
"invoice_sighash": "41ce7b274b0e73e60dd6abf4fa51ccae892b161adc24d4099f620b12c59a03e5",
|
||||
"invoice_signature": "0a33224568b6aae6ed252012bd7fe1072c03ebdca7fa44f95b03f1cd09be28b0a83c9c32105978cd80da068979662c80fa00ff250ccdc4d18b709ffd1c7ae319",
|
||||
"proof_merkle_root": "1b0bab09a5fcccec19eb3aaafbbfa4075944fd1f65691ed715fbbc17a59b3651",
|
||||
"proof_leaf_hashes": [
|
||||
"f2deaf5f30be3ced89fc7c24d422819bf06af0e48a31423bbd0e2634f3c3de67",
|
||||
"f0191c35000247554b8d0a196898a794bf3de89982571178d931affb654f0c1a",
|
||||
"dc0b8de03f1a0b0531bff146982d7d613ef6e1ef8d3bdd9590971fc18d835ffb",
|
||||
"7e92b77b9e3843650f6cd7ee94b6753ea9df3533710b04dee686ad376515a5cb"
|
||||
],
|
||||
"proof_omitted_tlvs": [
|
||||
1,
|
||||
2,
|
||||
89,
|
||||
90,
|
||||
91
|
||||
],
|
||||
"proof_missing_hashes": [
|
||||
"bf8cb2b1d6fa9bcdcab501b59f82c65c506b7f43514737f7197f1fcfeaebad41",
|
||||
"b9406f4ce526a6a0d4e0b3a63ed89a832e31cb9939dfe1a7b5dd7232d32c02ab",
|
||||
"cd9c44b53b31700c9ed0e3330ce425f7f18fac2fc1d566a34468439274f0e316",
|
||||
"9f9830f2c3070cfbad13fde30ee36cd7143591164ed12040a9cd595c96840ac9"
|
||||
]
|
||||
},
|
||||
"result": {
|
||||
"payer_sig": "ed03ec58d5ac676539486bb6e8d6f389b6375b6693ffdf30a93919590d744fa393f945a5de3bb57d65c7f61def1cefa8aa038725b15bf0fa797dfd08ca97538a",
|
||||
"proof_fields": [
|
||||
{
|
||||
"type": 88,
|
||||
"len": 33,
|
||||
"hex": "0324653eac434488002cc06bbfb7f10fe18991e35f9fe4302dbea6d2353dc0ab1c"
|
||||
},
|
||||
{
|
||||
"type": 168,
|
||||
"len": 32,
|
||||
"hex": "72cd6e8422c407fb6d098690f1130b7ded7ec2f7f5e1d30bd9d521f015363793"
|
||||
},
|
||||
{
|
||||
"type": 170,
|
||||
"len": 2,
|
||||
"hex": "03e8"
|
||||
},
|
||||
{
|
||||
"type": 176,
|
||||
"len": 33,
|
||||
"hex": "024bc2a31265153f07e70e0bab08724e6b85e217f8cd628ceb62974247bb493382"
|
||||
},
|
||||
{
|
||||
"type": 240,
|
||||
"len": 64,
|
||||
"hex": "0a33224568b6aae6ed252012bd7fe1072c03ebdca7fa44f95b03f1cd09be28b0a83c9c32105978cd80da068979662c80fa00ff250ccdc4d18b709ffd1c7ae319"
|
||||
},
|
||||
{
|
||||
"type": 241,
|
||||
"len": 64,
|
||||
"hex": "ed03ec58d5ac676539486bb6e8d6f389b6375b6693ffdf30a93919590d744fa393f945a5de3bb57d65c7f61def1cefa8aa038725b15bf0fa797dfd08ca97538a"
|
||||
},
|
||||
{
|
||||
"type": 1001,
|
||||
"len": 32,
|
||||
"hex": "0101010101010101010101010101010101010101010101010101010101010101"
|
||||
},
|
||||
{
|
||||
"type": 1002,
|
||||
"len": 5,
|
||||
"hex": "0102595a5b"
|
||||
},
|
||||
{
|
||||
"type": 1003,
|
||||
"len": 128,
|
||||
"hex": "bf8cb2b1d6fa9bcdcab501b59f82c65c506b7f43514737f7197f1fcfeaebad41b9406f4ce526a6a0d4e0b3a63ed89a832e31cb9939dfe1a7b5dd7232d32c02abcd9c44b53b31700c9ed0e3330ce425f7f18fac2fc1d566a34468439274f0e3169f9830f2c3070cfbad13fde30ee36cd7143591164ed12040a9cd595c96840ac9"
|
||||
},
|
||||
{
|
||||
"type": 1004,
|
||||
"len": 128,
|
||||
"hex": "f2deaf5f30be3ced89fc7c24d422819bf06af0e48a31423bbd0e2634f3c3de67f0191c35000247554b8d0a196898a794bf3de89982571178d931affb654f0c1adc0b8de03f1a0b0531bff146982d7d613ef6e1ef8d3bdd9590971fc18d835ffb7e92b77b9e3843650f6cd7ee94b6753ea9df3533710b04dee686ad376515a5cb"
|
||||
}
|
||||
],
|
||||
"bech32": "lnp1tqssxfr986kyx3ygqqkvq6alklcslcvfj834l8lyxqkmafkjx57up2cu4qs89ntwss3vgplmd5ycdy83zv9hmmt7ctmltcwnp0va2g0sz5mr0ya2qgp73vppqf9u9gcjv52n7pl8pc96kzrjfe4ctcshlrxk9r8tv2t5y3amfyec9uzqpgejy3tgk64wdmf9yqft6llpqukq867u5layf72mq0cu6zd79zc2s0yuxgg9j7xdsrdqdztevckgp7sqlujsenwy6x9hp8lar3awxx03grks8mzc6kkxwefefp4md6xk7wymvd6mv6fllhes4yu3jkgdw3868ylegkjauwa404ju0asaauwwl292qwrjtv2m7ra8jl0apr9fw5u2l5p7jgqpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpq87s86s9qyp9jkjml5p7hq9l3jetr4h6n0xu4dgpkk0c93ju2p4h7s63gumlwxtlrl8746adgxu5qm6vu5n2dgx5uze6v0kcn2pjuvwtnyualcd8khwhyvkn9sp2hnvugj6nkvtspj0dpcenpnjztal337kzlsw4v635g6zrjf60pcckn7vrpukrqux0htgnlh3sacmv6u2rtygkfmgjqs9fe4v4e95yptyl6qlvsredat6lxzlremvfl37zf4pzsxdlq6hsuj9rzs3mh58zvd8nc00x0uqers6sqqj8249c6zsedzv2099l8h5fnqjhz9udjvd0ldj57rq6ms9cmcplrg9s2vdl79rfsttavyl0dc0035aam9vsju0urrvrtlahay4h0w0rssm9pakd0m55ke6na2wlx5ehzzcymmngdtfhv526tjc"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "empty_proof_omitted_tlvs_explicit",
|
||||
"input": {
|
||||
"invoice": "lni1qqgqqqqqqqqqqqqqqqqqqqqqqqqqq93pqf9u9gcjv52n7pl8pc96kzrjfe4ctcshlrxk9r8tv2t5y3amfyecy5szq059sggry3jnatzrgjyqqtxqdwlm0ug0uxyerc6lnljrqtd75mfr20wq4vw2qasz0uc7h32x9s0aecdhxlk075kn046aafpuuyw8f5j652t3vha2yqrsxtqt0nu4xf9q05znnzeyq96dcrptu3zdj6c4n2nv0aa3ue5xszv3qypwm2aaz66peqm3hyh09uzvzxzmfupmdhx49w5m0rva0jyu3u3pz3gqzqqqqqqqqqqqqqqqqqqqqqqqqqq2y8qqqqqqzqqqqqpqqqcqqqqqqqqqqqzqqqqqqqqqqqq9qqq2gpr82fuc32pqwtxkappzcsrlkmgfs6g0zyct0hkhashh7hsaxz7e65slq9fkx7f65qsrazczzqjtc233yeg48ur7wrst4vy8ynntsh3p07xdv2xwkc5hgfrmkjfnstcyqz3nyfzk3d42umkj2gqjh4l7zpevq04aefl6gnu4kql3e5ymu29s4q7fcvsst9uvmqx6q6yhje3vsraqple9pnxuf5vtwz0l68r6uvvs",
|
||||
"invoice_hex": "0010000000000000000000000000000000001621024bc2a31265153f07e70e0bab08724e6b85e217f8cd628ceb62974247bb493382520203e858210324653eac434488002cc06bbfb7f10fe18991e35f9fe4302dbea6d2353dc0ab1ca076027f31ebc5462c1fdce1b737ecff52d37d75dea43ce11c74d25aa297165faa2007032c0b7cf95324a07d05398b240174dc0c2be444d96b159aa6c7f7b1e6686809910102edabbd16b41c8371b92ef2f04c1185b4f03b6dcd52ba9b78d9d7c89c8f221145001000000000000000000000000000000000a21c00000001000000020003000000000000000400000000000000050000a40467527988a82072cd6e8422c407fb6d098690f1130b7ded7ec2f7f5e1d30bd9d521f015363793aa0203e8b021024bc2a31265153f07e70e0bab08724e6b85e217f8cd628ceb62974247bb493382f0400a33224568b6aae6ed252012bd7fe1072c03ebdca7fa44f95b03f1cd09be28b0a83c9c32105978cd80da068979662c80fa00ff250ccdc4d18b709ffd1c7ae319",
|
||||
"preimage": "0101010101010101010101010101010101010101010101010101010101010101",
|
||||
"invoice_fields": [
|
||||
{
|
||||
"type": 0,
|
||||
"len": 16,
|
||||
"hex": "00000000000000000000000000000000",
|
||||
"included": false
|
||||
},
|
||||
{
|
||||
"type": 22,
|
||||
"len": 33,
|
||||
"hex": "024bc2a31265153f07e70e0bab08724e6b85e217f8cd628ceb62974247bb493382",
|
||||
"included": true
|
||||
},
|
||||
{
|
||||
"type": 82,
|
||||
"len": 2,
|
||||
"hex": "03e8",
|
||||
"included": true
|
||||
},
|
||||
{
|
||||
"type": 88,
|
||||
"len": 33,
|
||||
"hex": "0324653eac434488002cc06bbfb7f10fe18991e35f9fe4302dbea6d2353dc0ab1c",
|
||||
"included": true
|
||||
},
|
||||
{
|
||||
"type": 160,
|
||||
"len": 118,
|
||||
"hex": "027f31ebc5462c1fdce1b737ecff52d37d75dea43ce11c74d25aa297165faa2007032c0b7cf95324a07d05398b240174dc0c2be444d96b159aa6c7f7b1e6686809910102edabbd16b41c8371b92ef2f04c1185b4f03b6dcd52ba9b78d9d7c89c8f221145001000000000000000000000000000000000",
|
||||
"included": true
|
||||
},
|
||||
{
|
||||
"type": 162,
|
||||
"len": 28,
|
||||
"hex": "00000001000000020003000000000000000400000000000000050000",
|
||||
"included": true
|
||||
},
|
||||
{
|
||||
"type": 164,
|
||||
"len": 4,
|
||||
"hex": "67527988",
|
||||
"included": true
|
||||
},
|
||||
{
|
||||
"type": 168,
|
||||
"len": 32,
|
||||
"hex": "72cd6e8422c407fb6d098690f1130b7ded7ec2f7f5e1d30bd9d521f015363793",
|
||||
"included": true
|
||||
},
|
||||
{
|
||||
"type": 170,
|
||||
"len": 2,
|
||||
"hex": "03e8",
|
||||
"included": true
|
||||
},
|
||||
{
|
||||
"type": 176,
|
||||
"len": 33,
|
||||
"hex": "024bc2a31265153f07e70e0bab08724e6b85e217f8cd628ceb62974247bb493382",
|
||||
"included": true
|
||||
},
|
||||
{
|
||||
"type": 240,
|
||||
"len": 64,
|
||||
"hex": "0a33224568b6aae6ed252012bd7fe1072c03ebdca7fa44f95b03f1cd09be28b0a83c9c32105978cd80da068979662c80fa00ff250ccdc4d18b709ffd1c7ae319",
|
||||
"included": false
|
||||
}
|
||||
]
|
||||
},
|
||||
"working": {
|
||||
"invoice_merkle_root": "0501ea6d4ad9fe7fce7edd5e3795987bd409d66c5709c2a17f9c0dfb839e3d8e",
|
||||
"invoice_sighash": "41ce7b274b0e73e60dd6abf4fa51ccae892b161adc24d4099f620b12c59a03e5",
|
||||
"invoice_signature": "0a33224568b6aae6ed252012bd7fe1072c03ebdca7fa44f95b03f1cd09be28b0a83c9c32105978cd80da068979662c80fa00ff250ccdc4d18b709ffd1c7ae319",
|
||||
"proof_merkle_root": "a98cbee700b100ede32c19f9525264d51a105751fb27e790dad011bb38415b89",
|
||||
"proof_leaf_hashes": [
|
||||
"8c9057ed88f3c5a6b6441dcac3b5e4cefb3615904d7362b86e78427fb695f461",
|
||||
"8dc54a97453dee6f207fa5216a30f1567442712ca98852bc789b73885029283c",
|
||||
"f2deaf5f30be3ced89fc7c24d422819bf06af0e48a31423bbd0e2634f3c3de67",
|
||||
"f54f80c94a87383f2a8ef7c3e461c62b67a51da5bccf6cd96a7dbab29bea51fa",
|
||||
"7849b8b856e1d2a63d9ce7dc1a78e05cbb2def1f5d7709c48e8707e0a59fe51e",
|
||||
"19e7e4eee6bf56c6c589fe50035490c1a7c91b753cb8007c4b52838a6772f997",
|
||||
"f0191c35000247554b8d0a196898a794bf3de89982571178d931affb654f0c1a",
|
||||
"dc0b8de03f1a0b0531bff146982d7d613ef6e1ef8d3bdd9590971fc18d835ffb",
|
||||
"7e92b77b9e3843650f6cd7ee94b6753ea9df3533710b04dee686ad376515a5cb"
|
||||
],
|
||||
"proof_omitted_tlvs": [],
|
||||
"proof_missing_hashes": [
|
||||
"0b510ba4c6884d603159ced2f0ca21e772424b59e52a2191bbfbcf07377805a1"
|
||||
]
|
||||
},
|
||||
"result": {
|
||||
"payer_sig": "dffe62d6446c182f2503e780fce09fc5cf310ef14a54f65dd1df124039b7a897f2940470ac0f9857f826b232289c0ac4e6927ca67d805167fb0add352f88add1",
|
||||
"proof_fields": [
|
||||
{
|
||||
"type": 22,
|
||||
"len": 33,
|
||||
"hex": "024bc2a31265153f07e70e0bab08724e6b85e217f8cd628ceb62974247bb493382"
|
||||
},
|
||||
{
|
||||
"type": 82,
|
||||
"len": 2,
|
||||
"hex": "03e8"
|
||||
},
|
||||
{
|
||||
"type": 88,
|
||||
"len": 33,
|
||||
"hex": "0324653eac434488002cc06bbfb7f10fe18991e35f9fe4302dbea6d2353dc0ab1c"
|
||||
},
|
||||
{
|
||||
"type": 160,
|
||||
"len": 118,
|
||||
"hex": "027f31ebc5462c1fdce1b737ecff52d37d75dea43ce11c74d25aa297165faa2007032c0b7cf95324a07d05398b240174dc0c2be444d96b159aa6c7f7b1e6686809910102edabbd16b41c8371b92ef2f04c1185b4f03b6dcd52ba9b78d9d7c89c8f221145001000000000000000000000000000000000"
|
||||
},
|
||||
{
|
||||
"type": 162,
|
||||
"len": 28,
|
||||
"hex": "00000001000000020003000000000000000400000000000000050000"
|
||||
},
|
||||
{
|
||||
"type": 164,
|
||||
"len": 4,
|
||||
"hex": "67527988"
|
||||
},
|
||||
{
|
||||
"type": 168,
|
||||
"len": 32,
|
||||
"hex": "72cd6e8422c407fb6d098690f1130b7ded7ec2f7f5e1d30bd9d521f015363793"
|
||||
},
|
||||
{
|
||||
"type": 170,
|
||||
"len": 2,
|
||||
"hex": "03e8"
|
||||
},
|
||||
{
|
||||
"type": 176,
|
||||
"len": 33,
|
||||
"hex": "024bc2a31265153f07e70e0bab08724e6b85e217f8cd628ceb62974247bb493382"
|
||||
},
|
||||
{
|
||||
"type": 240,
|
||||
"len": 64,
|
||||
"hex": "0a33224568b6aae6ed252012bd7fe1072c03ebdca7fa44f95b03f1cd09be28b0a83c9c32105978cd80da068979662c80fa00ff250ccdc4d18b709ffd1c7ae319"
|
||||
},
|
||||
{
|
||||
"type": 241,
|
||||
"len": 64,
|
||||
"hex": "dffe62d6446c182f2503e780fce09fc5cf310ef14a54f65dd1df124039b7a897f2940470ac0f9857f826b232289c0ac4e6927ca67d805167fb0add352f88add1"
|
||||
},
|
||||
{
|
||||
"type": 1001,
|
||||
"len": 32,
|
||||
"hex": "0101010101010101010101010101010101010101010101010101010101010101"
|
||||
},
|
||||
{
|
||||
"type": 1002,
|
||||
"len": 0,
|
||||
"hex": ""
|
||||
},
|
||||
{
|
||||
"type": 1003,
|
||||
"len": 32,
|
||||
"hex": "0b510ba4c6884d603159ced2f0ca21e772424b59e52a2191bbfbcf07377805a1"
|
||||
},
|
||||
{
|
||||
"type": 1004,
|
||||
"len": 288,
|
||||
"hex": "8c9057ed88f3c5a6b6441dcac3b5e4cefb3615904d7362b86e78427fb695f4618dc54a97453dee6f207fa5216a30f1567442712ca98852bc789b73885029283cf2deaf5f30be3ced89fc7c24d422819bf06af0e48a31423bbd0e2634f3c3de67f54f80c94a87383f2a8ef7c3e461c62b67a51da5bccf6cd96a7dbab29bea51fa7849b8b856e1d2a63d9ce7dc1a78e05cbb2def1f5d7709c48e8707e0a59fe51e19e7e4eee6bf56c6c589fe50035490c1a7c91b753cb8007c4b52838a6772f997f0191c35000247554b8d0a196898a794bf3de89982571178d931affb654f0c1adc0b8de03f1a0b0531bff146982d7d613ef6e1ef8d3bdd9590971fc18d835ffb7e92b77b9e3843650f6cd7ee94b6753ea9df3533710b04dee686ad376515a5cb"
|
||||
}
|
||||
],
|
||||
"bech32": "lnp1zcssyj7z5vfx29flqlnsuzatppeyu6u9ugtl3ntz3n4k996zg7a5jvuz2gpq86zcyypjgef743p5fzqq9nqxh0ah7y87rzv3ud0eleps9kl2d5348hq2k89qwcp87v0tc4rzc87uuxmn0m8l2tfh6aw75s7wz8r56fd299ckt74zqpcr9s9he72nyjs86pfe3vjqzaxups47g3xedv2e4fk877c7v6rgpxgszqhd4w73ddqusdcmjthj7pxprpd57qakmn2jh2dh3kwhezwg7gs3g5qpqqqqqqqqqqqqqqqqqqqqqqqqqq9zrsqqqqqpqqqqqqsqqvqqqqqqqqqqqpqqqqqqqqqqqqzsqq9yq3n4y7vg4qs89ntwss3vgplmd5ycdy83zv9hmmt7ctmltcwnp0va2g0sz5mr0ya2qgp73vppqf9u9gcjv52n7pl8pc96kzrjfe4ctcshlrxk9r8tv2t5y3amfyec9uzqpgejy3tgk64wdmf9yqft6llpqukq867u5layf72mq0cu6zd79zc2s0yuxgg9j7xdsrdqdztevckgp7sqlujsenwy6x9hp8lar3awxx03gr0luckkg3kpste9q0ncpl8qnlzu7vgw7999faja6803yspek75f0u55q3c2cruc2luzdv3j9zwq438xjf72vlvq29nlkzkax5hc3tw3l5p7jgqpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpq87s86sql5p7kgqt2y96f35gf4srzkww6tcv5g08wfpykk099gserwlmeurnw7q9587s8m8aqysgeyzhaky083dxkezpmjkrkhjva7ekzkgy6umzhph8ssnlk62lgcvdc49fw3faaehjqla9y94rpu2kw3p8zt9f3pftc7ymwwy9q2fg8nedat6lxzlremvfl37zf4pzsxdlq6hsuj9rzs3mh58zvd8nc00x0a20sry54pec8u4gaa7ru3suv2m855w6t0x0dnvk5ld6k2d755060pym3wzku8f2v0vuulwp578qtjajmmclt4msn3ywsur7pfvlu50pnelyamnt74kxckylu5qr2jgvrf7frd6newqq03949qu2vae0n9lsrywr2qqzga25hrg2r95f3fu5hu773xvz2ugh3kf34lak2ncvrtwqhr0q8udqkpf3hlc5dxpd04snaahpa7xnhhv4jzt3lsvdsd0lkl5jkaaeuwzrv58ke4lwjjm8204fmu6nxugtqn0wdp4dxaj3tfwt"
|
||||
}
|
||||
}
|
||||
],
|
||||
"invalid_vectors": [
|
||||
{
|
||||
"reason": "missing_invreq_payer_id",
|
||||
"bech32": "lnp14qs89ntwss3vgplmd5ycdy83zv9hmmt7ctmltcwnp0va2g0sz5mr0yasyypyhs4rzfj320c8uu8qh2cgwf8xhp0zzluv6c5vad3fwsj8hdyn8qhsgq9rxgj9dzm24ehdy5sp90tluyrjcqltmjnl538etvplrngfhc5tp2punsepqktcekqd5p5f09nzeq86qrlj2rxdcngckuyll5w84cce79qva0p96s9zmynmt672hpqq74p0hdag733w3hvq9wcnupgtn0ef8d690svmg6j8vaq0jlyadmq5ru35xnzaf7398gwjawyfd6adn9z4en7s86fqqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyql6ql2qcqsyk26tw5l6qlt5zlcev436mafhnw2k5qmt8uzcew9q6mlgdg5wdlhr9l3lnl2awk5rw2qdaxw2f4x5r2wpvax8mvf4qewx89ejwwluxnmthtjxtfjcq4tekwyfdfmx9cqe8ksuveseep97lccltp0c82kdg6ydppeya8suvtflxps7tpswr8m45flmccwudkdw9p4jytya5fqgz5u6k2uj6zq4jve32ml48r587uahkcd34r0hcadxv6qp0g87v5dekmqppushjwjm07s8mrq7t027heshc7wmz0u0sjdgg5pn0cx4u8y3gc5ywaapcnrfu7rmenlqxgux5qqy364fwxs5xtgnznef0eaazvcy4c30rvnrtlmv48scxn7j2mhh83cgdjs7mxha62tvaf7480n2vm3pvzdae5x45mk29d9ev"
|
||||
},
|
||||
{
|
||||
"reason": "missing_invoice_payment_hash",
|
||||
"bech32": "lnp1tqssxfr986kyx3ygqqkvq6alklcslcvfj834l8lyxqkmafkjx57up2cukqssyj7z5vfx29flqlnsuzatppeyu6u9ugtl3ntz3n4k996zg7a5jvuz7pqq5vezg45td2hxa5jjqy4a0lsswtqra0w207jyl9ds8uwdpxlz3v9g8jwryyze0rxcpksx39ukvtyqlgq07fgvehzdrzmsnl73c7hrr8c5pn4uyh2q5tvj0d0te2uyqr6597ah4r6x96xasq4mz0s9pwdl9yahg47pndr2gan5p7tun4hvzs0jxs6vt486y5ap6t4c39ht4kv52hx06qlfyqqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqsrlgragrqzqjetfd6nlgrawstlr9jk8t04x7de26srdvlstr9c5rt0ap4z3eh7uvh7870at466sdegph5eefx56sdfc9n5cld3x5r9ccuhxfemls60dwawgedxtqz40xec3948vchqry76r3nxr8yyhmlrrav9lqa2e4rg35y8yn57r33d8ucxrevxpcvlwk38l0rpm3ke4c5xkg3vnk3ypq2nn2etjtggzkfnx9t075uwslmnk7mpkx5d7lr45engq9aqlej3hxmvqy8jz7f6tdl6qlvvredat6lxzlremvfl37zf4pzsxdlq6hsuj9rzs3mh58zvd8nc00x0uqers6sqqj8249c6zsedzv2099l8h5fnqjhz9udjvd0ldj57rq606ftw7u78ppk2rmv6lhffdn4865a7dfnwy9sfhhxs6knweg45h9s"
|
||||
},
|
||||
{
|
||||
"reason": "missing_invoice_node_id",
|
||||
"bech32": "lnp1tqssxfr986kyx3ygqqkvq6alklcslcvfj834l8lyxqkmafkjx57up2cu4qs89ntwss3vgplmd5ycdy83zv9hmmt7ctmltcwnp0va2g0sz5mr0ylsgq9rxgj9dzm24ehdy5sp90tluyrjcqltmjnl538etvplrngfhc5tp2punsepqktcekqd5p5f09nzeq86qrlj2rxdcngckuyll5w84cce79qva0p96s9zmynmt672hpqq74p0hdag733w3hvq9wcnupgtn0ef8d690svmg6j8vaq0jlyadmq5ru35xnzaf7398gwjawyfd6adn9z4en7s86fqqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyql6ql2qcqsyk26tw5l6qlt5zlcev436mafhnw2k5qmt8uzcew9q6mlgdg5wdlhr9l3lnl2awk5rw2qdaxw2f4x5r2wpvax8mvf4qewx89ejwwluxnmthtjxtfjcq4tekwyfdfmx9cqe8ksuveseep97lccltp0c82kdg6ydppeya8suvtflxps7tpswr8m45flmccwudkdw9p4jytya5fqgz5u6k2uj6zq4jve32ml48r587uahkcd34r0hcadxv6qp0g87v5dekmqppushjwjm07s8mrq7t027heshc7wmz0u0sjdgg5pn0cx4u8y3gc5ywaapcnrfu7rmenlqxgux5qqy364fwxs5xtgnznef0eaazvcy4c30rvnrtlmv48scxn7j2mhh83cgdjs7mxha62tvaf7480n2vm3pvzdae5x45mk29d9ev"
|
||||
},
|
||||
{
|
||||
"reason": "missing_signature",
|
||||
"bech32": "lnp1tqssxfr986kyx3ygqqkvq6alklcslcvfj834l8lyxqkmafkjx57up2cu4qs89ntwss3vgplmd5ycdy83zv9hmmt7ctmltcwnp0va2g0sz5mr0yasyypyhs4rzfj320c8uu8qh2cgwf8xhp0zzluv6c5vad3fwsj8hdyn8qh3gr8tcfw5pgkey767hj4cgq84gtam0285vt5dmqptkylq2zum72fmw3turx6x53m8gruhe8twc9qlydp5ch205ff6r5ht3ztwhtveg4wvl5p7jgqpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpq87s86sxqyp9jkjm487s86aqh7xt9vwkl2dumj44qx6elqkxt3gxkl6r29rn0ace0u0ul6ht44qmjsr0fnjjdf4q6nst8f37mzdgxt33ewvnnhlp576a6u3j6vkq927dn3zt2we3wqxfa58rxvxwgf0h7x86ct7p64n2x3rggwf8fu8rz60esv8jcvrse7adz077xrhrdnt3gdv3ze8dzgzq48x4jhykss9vnxv2klafcaplh8dakrvdgma78tfnxsqt6pln9rwdkcqg0y9un5kml5p7cc8jm6h47v978nkcnlruyn2z9qvm7p40pey2x9prh0gwyc608s77vlcpj8p4qqpyw42t359pj6yc572t700gnxp9wytcmyc6l7m9fuxp5l5jkaaeuwzrv58ke4lwjjm8204fmu6nxugtqn0wdp4dxaj3tfwt"
|
||||
},
|
||||
{
|
||||
"reason": "missing_proof_preimage",
|
||||
"bech32": "lnp1tqssxfr986kyx3ygqqkvq6alklcslcvfj834l8lyxqkmafkjx57up2cu4qs89ntwss3vgplmd5ycdy83zv9hmmt7ctmltcwnp0va2g0sz5mr0yasyypyhs4rzfj320c8uu8qh2cgwf8xhp0zzluv6c5vad3fwsj8hdyn8qhsgq9rxgj9dzm24ehdy5sp90tluyrjcqltmjnl538etvplrngfhc5tp2punsepqktcekqd5p5f09nzeq86qrlj2rxdcngckuyll5w84cce79qva0p96s9zmynmt672hpqq74p0hdag733w3hvq9wcnupgtn0ef8d690svmg6j8vaq0jlyadmq5ru35xnzaf7398gwjawyfd6adn9z4en7s86sxqyp9jkjm487s86aqh7xt9vwkl2dumj44qx6elqkxt3gxkl6r29rn0ace0u0ul6ht44qmjsr0fnjjdf4q6nst8f37mzdgxt33ewvnnhlp576a6u3j6vkq927dn3zt2we3wqxfa58rxvxwgf0h7x86ct7p64n2x3rggwf8fu8rz60esv8jcvrse7adz077xrhrdnt3gdv3ze8dzgzq48x4jhykss9vnxv2klafcaplh8dakrvdgma78tfnxsqt6pln9rwdkcqg0y9un5kml5p7cc8jm6h47v978nkcnlruyn2z9qvm7p40pey2x9prh0gwyc608s77vlcpj8p4qqpyw42t359pj6yc572t700gnxp9wytcmyc6l7m9fuxp5l5jkaaeuwzrv58ke4lwjjm8204fmu6nxugtqn0wdp4dxaj3tfwt"
|
||||
},
|
||||
{
|
||||
"reason": "missing_proof_missing_hashes",
|
||||
"bech32": "lnp1tqssxfr986kyx3ygqqkvq6alklcslcvfj834l8lyxqkmafkjx57up2cu4qs89ntwss3vgplmd5ycdy83zv9hmmt7ctmltcwnp0va2g0sz5mr0yasyypyhs4rzfj320c8uu8qh2cgwf8xhp0zzluv6c5vad3fwsj8hdyn8qhsgq9rxgj9dzm24ehdy5sp90tluyrjcqltmjnl538etvplrngfhc5tp2punsepqktcekqd5p5f09nzeq86qrlj2rxdcngckuyll5w84cce79qva0p96s9zmynmt672hpqq74p0hdag733w3hvq9wcnupgtn0ef8d690svmg6j8vaq0jlyadmq5ru35xnzaf7398gwjawyfd6adn9z4en7s86fqqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyql6ql2qcqsyk26tw5l6qlvvredat6lxzlremvfl37zf4pzsxdlq6hsuj9rzs3mh58zvd8nc00x0uqers6sqqj8249c6zsedzv2099l8h5fnqjhz9udjvd0ldj57rq606ftw7u78ppk2rmv6lhffdn4865a7dfnwy9sfhhxs6knweg45h9s"
|
||||
},
|
||||
{
|
||||
"reason": "missing_proof_leaf_hashes",
|
||||
"bech32": "lnp1tqssxfr986kyx3ygqqkvq6alklcslcvfj834l8lyxqkmafkjx57up2cu4qs89ntwss3vgplmd5ycdy83zv9hmmt7ctmltcwnp0va2g0sz5mr0yasyypyhs4rzfj320c8uu8qh2cgwf8xhp0zzluv6c5vad3fwsj8hdyn8qhsgq9rxgj9dzm24ehdy5sp90tluyrjcqltmjnl538etvplrngfhc5tp2punsepqktcekqd5p5f09nzeq86qrlj2rxdcngckuyll5w84cce79qva0p96s9zmynmt672hpqq74p0hdag733w3hvq9wcnupgtn0ef8d690svmg6j8vaq0jlyadmq5ru35xnzaf7398gwjawyfd6adn9z4en7s86fqqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyql6ql2qcqsyk26tw5l6qlt5zlcev436mafhnw2k5qmt8uzcew9q6mlgdg5wdlhr9l3lnl2awk5rw2qdaxw2f4x5r2wpvax8mvf4qewx89ejwwluxnmthtjxtfjcq4tekwyfdfmx9cqe8ksuveseep97lccltp0c82kdg6ydppeya8suvtflxps7tpswr8m45flmccwudkdw9p4jytya5fqgz5u6k2uj6zq4jve32ml48r587uahkcd34r0hcadxv6qp0g87v5dekmqppushjwjmv"
|
||||
},
|
||||
{
|
||||
"reason": "missing_proof_signature",
|
||||
"bech32": "lnp1tqssxfr986kyx3ygqqkvq6alklcslcvfj834l8lyxqkmafkjx57up2cu4qs89ntwss3vgplmd5ycdy83zv9hmmt7ctmltcwnp0va2g0sz5mr0yasyypyhs4rzfj320c8uu8qh2cgwf8xhp0zzluv6c5vad3fwsj8hdyn8qhsgq9rxgj9dzm24ehdy5sp90tluyrjcqltmjnl538etvplrngfhc5tp2punsepqktcekqd5p5f09nzeq86qrlj2rxdcngckuyll5w84ccel5p7jgqpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpq87s86sxqyp9jkjm487s86aqh7xt9vwkl2dumj44qx6elqkxt3gxkl6r29rn0ace0u0ul6ht44qmjsr0fnjjdf4q6nst8f37mzdgxt33ewvnnhlp576a6u3j6vkq927dn3zt2we3wqxfa58rxvxwgf0h7x86ct7p64n2x3rggwf8fu8rz60esv8jcvrse7adz077xrhrdnt3gdv3ze8dzgzq48x4jhykss9vnxv2klafcaplh8dakrvdgma78tfnxsqt6pln9rwdkcqg0y9un5kml5p7cc8jm6h47v978nkcnlruyn2z9qvm7p40pey2x9prh0gwyc608s77vlcpj8p4qqpyw42t359pj6yc572t700gnxp9wytcmyc6l7m9fuxp5l5jkaaeuwzrv58ke4lwjjm8204fmu6nxugtqn0wdp4dxaj3tfwt"
|
||||
},
|
||||
{
|
||||
"reason": "wrong_proof_preimage",
|
||||
"bech32": "lnp1tqssxfr986kyx3ygqqkvq6alklcslcvfj834l8lyxqkmafkjx57up2cu4qs89ntwss3vgplmd5ycdy83zv9hmmt7ctmltcwnp0va2g0sz5mr0yasyypyhs4rzfj320c8uu8qh2cgwf8xhp0zzluv6c5vad3fwsj8hdyn8qhsgq9rxgj9dzm24ehdy5sp90tluyrjcqltmjnl538etvplrngfhc5tp2punsepqktcekqd5p5f09nzeq86qrlj2rxdcngckuyll5w84cce79qva0p96s9zmynmt672hpqq74p0hdag733w3hvq9wcnupgtn0ef8d690svmg6j8vaq0jlyadmq5ru35xnzaf7398gwjawyfd6adn9z4en7s86fqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq06ql2qcqsyk26tw5l6qlt5zlcev436mafhnw2k5qmt8uzcew9q6mlgdg5wdlhr9l3lnl2awk5rw2qdaxw2f4x5r2wpvax8mvf4qewx89ejwwluxnmthtjxtfjcq4tekwyfdfmx9cqe8ksuveseep97lccltp0c82kdg6ydppeya8suvtflxps7tpswr8m45flmccwudkdw9p4jytya5fqgz5u6k2uj6zq4jve32ml48r587uahkcd34r0hcadxv6qp0g87v5dekmqppushjwjm07s8mrq7t027heshc7wmz0u0sjdgg5pn0cx4u8y3gc5ywaapcnrfu7rmenlqxgux5qqy364fwxs5xtgnznef0eaazvcy4c30rvnrtlmv48scxn7j2mhh83cgdjs7mxha62tvaf7480n2vm3pvzdae5x45mk29d9ev"
|
||||
},
|
||||
{
|
||||
"reason": "proof_omitted_tlvs_not_ascending",
|
||||
"bech32": "lnp1tqssxfr986kyx3ygqqkvq6alklcslcvfj834l8lyxqkmafkjx57up2cu4qs89ntwss3vgplmd5ycdy83zv9hmmt7ctmltcwnp0va2g0sz5mr0yasyypyhs4rzfj320c8uu8qh2cgwf8xhp0zzluv6c5vad3fwsj8hdyn8qhsgq9rxgj9dzm24ehdy5sp90tluyrjcqltmjnl538etvplrngfhc5tp2punsepqktcekqd5p5f09nzeq86qrlj2rxdcngckuyll5w84cce79qva0p96s9zmynmt672hpqq74p0hdag733w3hvq9wcnupgtn0ef8d690svmg6j8vaq0jlyadmq5ru35xnzaf7398gwjawyfd6adn9z4en7s86fqqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyql6ql2qcqsyk2649dl6qlt5zlcev436mafhnw2k5qmt8uzcew9q6mlgdg5wdlhr9l3lnl2awk5rw2qdaxw2f4x5r2wpvax8mvf4qewx89ejwwluxnmthtjxtfjcq4tekwyfdfmx9cqe8ksuveseep97lccltp0c82kdg6ydppeya8suvtflxps7tpswr8m45flmccwudkdw9p4jytya5fqgz5u6k2uj6zq4jve32ml48r587uahkcd34r0hcadxv6qp0g87v5dekmqppushjwjm07s8mrq7t027heshc7wmz0u0sjdgg5pn0cx4u8y3gc5ywaapcnrfu7rmenlqxgux5qqy364fwxs5xtgnznef0eaazvcy4c30rvnrtlmv48scxn7j2mhh83cgdjs7mxha62tvaf7480n2vm3pvzdae5x45mk29d9ev"
|
||||
},
|
||||
{
|
||||
"reason": "proof_omitted_tlvs_contains_zero",
|
||||
"bech32": "lnp1tqssxfr986kyx3ygqqkvq6alklcslcvfj834l8lyxqkmafkjx57up2cu4qs89ntwss3vgplmd5ycdy83zv9hmmt7ctmltcwnp0va2g0sz5mr0yasyypyhs4rzfj320c8uu8qh2cgwf8xhp0zzluv6c5vad3fwsj8hdyn8qhsgq9rxgj9dzm24ehdy5sp90tluyrjcqltmjnl538etvplrngfhc5tp2punsepqktcekqd5p5f09nzeq86qrlj2rxdcngckuyll5w84cce79qva0p96s9zmynmt672hpqq74p0hdag733w3hvq9wcnupgtn0ef8d690svmg6j8vaq0jlyadmq5ru35xnzaf7398gwjawyfd6adn9z4en7s86fqqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyql6ql2quqqzqjetfd6nlgrawstlr9jk8t04x7de26srdvlstr9c5rt0ap4z3eh7uvh7870at466sdegph5eefx56sdfc9n5cld3x5r9ccuhxfemls60dwawgedxtqz40xec3948vchqry76r3nxr8yyhmlrrav9lqa2e4rg35y8yn57r33d8ucxrevxpcvlwk38l0rpm3ke4c5xkg3vnk3ypq2nn2etjtggzkfnx9t075uwslmnk7mpkx5d7lr45engq9aqlej3hxmvqy8jz7f6tdl6qlvvredat6lxzlremvfl37zf4pzsxdlq6hsuj9rzs3mh58zvd8nc00x0uqers6sqqj8249c6zsedzv2099l8h5fnqjhz9udjvd0ldj57rq606ftw7u78ppk2rmv6lhffdn4865a7dfnwy9sfhhxs6knweg45h9s"
|
||||
},
|
||||
{
|
||||
"reason": "proof_omitted_tlvs_contains_signature_field",
|
||||
"bech32": "lnp1tqssxfr986kyx3ygqqkvq6alklcslcvfj834l8lyxqkmafkjx57up2cu4qs89ntwss3vgplmd5ycdy83zv9hmmt7ctmltcwnp0va2g0sz5mr0yasyypyhs4rzfj320c8uu8qh2cgwf8xhp0zzluv6c5vad3fwsj8hdyn8qhsgq9rxgj9dzm24ehdy5sp90tluyrjcqltmjnl538etvplrngfhc5tp2punsepqktcekqd5p5f09nzeq86qrlj2rxdcngckuyll5w84cce79qva0p96s9zmynmt672hpqq74p0hdag733w3hvq9wcnupgtn0ef8d690svmg6j8vaq0jlyadmq5ru35xnzaf7398gwjawyfd6adn9z4en7s86fqqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyql6ql2quqsyk26tw5lrlgrawstlr9jk8t04x7de26srdvlstr9c5rt0ap4z3eh7uvh7870at466sdegph5eefx56sdfc9n5cld3x5r9ccuhxfemls60dwawgedxtqz40xec3948vchqry76r3nxr8yyhmlrrav9lqa2e4rg35y8yn57r33d8ucxrevxpcvlwk38l0rpm3ke4c5xkg3vnk3ypq2nn2etjtggzkfnx9t075uwslmnk7mpkx5d7lr45engq9aqlej3hxmvqy8jz7f6tdl6qlvvredat6lxzlremvfl37zf4pzsxdlq6hsuj9rzs3mh58zvd8nc00x0uqers6sqqj8249c6zsedzv2099l8h5fnqjhz9udjvd0ldj57rq606ftw7u78ppk2rmv6lhffdn4865a7dfnwy9sfhhxs6knweg45h9s"
|
||||
},
|
||||
{
|
||||
"reason": "proof_omitted_tlvs_contains_proof_field",
|
||||
"bech32": "lnp1tqssxfr986kyx3ygqqkvq6alklcslcvfj834l8lyxqkmafkjx57up2cu4qs89ntwss3vgplmd5ycdy83zv9hmmt7ctmltcwnp0va2g0sz5mr0yasyypyhs4rzfj320c8uu8qh2cgwf8xhp0zzluv6c5vad3fwsj8hdyn8qhsgq9rxgj9dzm24ehdy5sp90tluyrjcqltmjnl538etvplrngfhc5tp2punsepqktcekqd5p5f09nzeq86qrlj2rxdcngckuyll5w84cce79qva0p96s9zmynmt672hpqq74p0hdag733w3hvq9wcnupgtn0ef8d690svmg6j8vaq0jlyadmq5ru35xnzaf7398gwjawyfd6adn9z4en7s86fqqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyql6ql2pyqsyk26tw5l6qlfl5p7hg9l3jetr4h6n0xu4dgpkk0c93ju2p4h7s63gumlwxtlrl8746adgxu5qm6vu5n2dgx5uze6v0kcn2pjuvwtnyualcd8khwhyvkn9sp2hnvugj6nkvtspj0dpcenpnjztal337kzlsw4v635g6zrjf60pcckn7vrpukrqux0htgnlh3sacmv6u2rtygkfmgjqs9fe4v4e95yptyenz4hl2w8g0aem0dsmr2xl0366ve5qz7s0uegmndkqzrep0ya9klaq0kxpuk74a0np03uakylclpy6s3grxlsdtcwfz33ggam6r3xxneu8hn87qv3cdgqqfr42judpgvk3x98jjlnm6yesft3z7xexxhlke20psd8ay4h0w0rssm9pakd0m55ke6na2wlx5ehzzcymmngdtfhv526tjc"
|
||||
},
|
||||
{
|
||||
"reason": "proof_omitted_tlvs_contains_high_field",
|
||||
"bech32": "lnp1tqssxfr986kyx3ygqqkvq6alklcslcvfj834l8lyxqkmafkjx57up2cu4qs89ntwss3vgplmd5ycdy83zv9hmmt7ctmltcwnp0va2g0sz5mr0yasyypyhs4rzfj320c8uu8qh2cgwf8xhp0zzluv6c5vad3fwsj8hdyn8qhsgq9rxgj9dzm24ehdy5sp90tluyrjcqltmjnl538etvplrngfhc5tp2punsepqktcekqd5p5f09nzeq86qrlj2rxdcngckuyll5w84cce79qva0p96s9zmynmt672hpqq74p0hdag733w3hvq9wcnupgtn0ef8d690svmg6j8vaq0jlyadmq5ru35xnzaf7398gwjawyfd6adn9z4en7s86fqqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyql6ql2pvqsyk26tw5lamnt9qq06qlt5zlcev436mafhnw2k5qmt8uzcew9q6mlgdg5wdlhr9l3lnl2awk5rw2qdaxw2f4x5r2wpvax8mvf4qewx89ejwwluxnmthtjxtfjcq4tekwyfdfmx9cqe8ksuveseep97lccltp0c82kdg6ydppeya8suvtflxps7tpswr8m45flmccwudkdw9p4jytya5fqgz5u6k2uj6zq4jve32ml48r587uahkcd34r0hcadxv6qp0g87v5dekmqppushjwjm07s8mrq7t027heshc7wmz0u0sjdgg5pn0cx4u8y3gc5ywaapcnrfu7rmenlqxgux5qqy364fwxs5xtgnznef0eaazvcy4c30rvnrtlmv48scxn7j2mhh83cgdjs7mxha62tvaf7480n2vm3pvzdae5x45mk29d9ev"
|
||||
},
|
||||
{
|
||||
"reason": "proof_omitted_tlvs_contains_included_tlv_field",
|
||||
"bech32": "lnp1tqssxfr986kyx3ygqqkvq6alklcslcvfj834l8lyxqkmafkjx57up2cu4qs89ntwss3vgplmd5ycdy83zv9hmmt7ctmltcwnp0va2g0sz5mr0yasyypyhs4rzfj320c8uu8qh2cgwf8xhp0zzluv6c5vad3fwsj8hdyn8qhsgq9rxgj9dzm24ehdy5sp90tluyrjcqltmjnl538etvplrngfhc5tp2punsepqktcekqd5p5f09nzeq86qrlj2rxdcngckuyll5w84cce79qva0p96s9zmynmt672hpqq74p0hdag733w3hvq9wcnupgtn0ef8d690svmg6j8vaq0jlyadmq5ru35xnzaf7398gwjawyfd6adn9z4en7s86fqqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyql6ql2quqsykzetfd6nlgrawstlr9jk8t04x7de26srdvlstr9c5rt0ap4z3eh7uvh7870at466sdegph5eefx56sdfc9n5cld3x5r9ccuhxfemls60dwawgedxtqz40xec3948vchqry76r3nxr8yyhmlrrav9lqa2e4rg35y8yn57r33d8ucxrevxpcvlwk38l0rpm3ke4c5xkg3vnk3ypq2nn2etjtggzkfnx9t075uwslmnk7mpkx5d7lr45engq9aqlej3hxmvqy8jz7f6tdl6qlvvredat6lxzlremvfl37zf4pzsxdlq6hsuj9rzs3mh58zvd8nc00x0uqers6sqqj8249c6zsedzv2099l8h5fnqjhz9udjvd0ldj57rq606ftw7u78ppk2rmv6lhffdn4865a7dfnwy9sfhhxs6knweg45h9s"
|
||||
},
|
||||
{
|
||||
"reason": "proof_omitted_tlvs_not_sequential",
|
||||
"bech32": "lnp1tqssxfr986kyx3ygqqkvq6alklcslcvfj834l8lyxqkmafkjx57up2cu4qs89ntwss3vgplmd5ycdy83zv9hmmt7ctmltcwnp0va2g0sz5mr0yasyypyhs4rzfj320c8uu8qh2cgwf8xhp0zzluv6c5vad3fwsj8hdyn8qhsgq9rxgj9dzm24ehdy5sp90tluyrjcqltmjnl538etvplrngfhc5tp2punsepqktcekqd5p5f09nzeq86qrlj2rxdcngckuyll5w84cce79qva0p96s9zmynmt672hpqq74p0hdag733w3hvq9wcnupgtn0ef8d690svmg6j8vaq0jlyadmq5ru35xnzaf7398gwjawyfd6adn9z4en7s86fqqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyql6ql2qcqsyktyv4n06qlt5zlcev436mafhnw2k5qmt8uzcew9q6mlgdg5wdlhr9l3lnl2awk5rw2qdaxw2f4x5r2wpvax8mvf4qewx89ejwwluxnmthtjxtfjcq4tekwyfdfmx9cqe8ksuveseep97lccltp0c82kdg6ydppeya8suvtflxps7tpswr8m45flmccwudkdw9p4jytya5fqgz5u6k2uj6zq4jve32ml48r587uahkcd34r0hcadxv6qp0g87v5dekmqppushjwjm07s8mrq7t027heshc7wmz0u0sjdgg5pn0cx4u8y3gc5ywaapcnrfu7rmenlqxgux5qqy364fwxs5xtgnznef0eaazvcy4c30rvnrtlmv48scxn7j2mhh83cgdjs7mxha62tvaf7480n2vm3pvzdae5x45mk29d9ev"
|
||||
},
|
||||
{
|
||||
"reason": "proof_leaf_hashes_too_few",
|
||||
"bech32": "lnp1tqssxfr986kyx3ygqqkvq6alklcslcvfj834l8lyxqkmafkjx57up2cu4qs89ntwss3vgplmd5ycdy83zv9hmmt7ctmltcwnp0va2g0sz5mr0yasyypyhs4rzfj320c8uu8qh2cgwf8xhp0zzluv6c5vad3fwsj8hdyn8qhsgq9rxgj9dzm24ehdy5sp90tluyrjcqltmjnl538etvplrngfhc5tp2punsepqktcekqd5p5f09nzeq86qrlj2rxdcngckuyll5w84cce79qva0p96s9zmynmt672hpqq74p0hdag733w3hvq9wcnupgtn0ef8d690svmg6j8vaq0jlyadmq5ru35xnzaf7398gwjawyfd6adn9z4en7s86fqqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyql6ql2qcqsyk26tw5l6qlt5zlcev436mafhnw2k5qmt8uzcew9q6mlgdg5wdlhr9l3lnl2awk5rw2qdaxw2f4x5r2wpvax8mvf4qewx89ejwwluxnmthtjxtfjcq4tekwyfdfmx9cqe8ksuveseep97lccltp0c82kdg6ydppeya8suvtflxps7tpswr8m45flmccwudkdw9p4jytya5fqgz5u6k2uj6zq4jve32ml48r587uahkcd34r0hcadxv6qp0g87v5dekmqppushjwjm07s8mzq7t027heshc7wmz0u0sjdgg5pn0cx4u8y3gc5ywaapcnrfu7rmenlqxgux5qqy364fwxs5xtgnznef0eaazvcy4c30rvnrtlmv48scxs"
|
||||
},
|
||||
{
|
||||
"reason": "proof_leaf_hashes_too_many",
|
||||
"bech32": "lnp1tqssxfr986kyx3ygqqkvq6alklcslcvfj834l8lyxqkmafkjx57up2cu4qs89ntwss3vgplmd5ycdy83zv9hmmt7ctmltcwnp0va2g0sz5mr0yasyypyhs4rzfj320c8uu8qh2cgwf8xhp0zzluv6c5vad3fwsj8hdyn8qhsgq9rxgj9dzm24ehdy5sp90tluyrjcqltmjnl538etvplrngfhc5tp2punsepqktcekqd5p5f09nzeq86qrlj2rxdcngckuyll5w84cce79qva0p96s9zmynmt672hpqq74p0hdag733w3hvq9wcnupgtn0ef8d690svmg6j8vaq0jlyadmq5ru35xnzaf7398gwjawyfd6adn9z4en7s86fqqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyql6ql2qcqsyk26tw5l6qlt5zlcev436mafhnw2k5qmt8uzcew9q6mlgdg5wdlhr9l3lnl2awk5rw2qdaxw2f4x5r2wpvax8mvf4qewx89ejwwluxnmthtjxtfjcq4tekwyfdfmx9cqe8ksuveseep97lccltp0c82kdg6ydppeya8suvtflxps7tpswr8m45flmccwudkdw9p4jytya5fqgz5u6k2uj6zq4jve32ml48r587uahkcd34r0hcadxv6qp0g87v5dekmqppushjwjm07s8myq7t027heshc7wmz0u0sjdgg5pn0cx4u8y3gc5ywaapcnrfu7rmenlqxgux5qqy364fwxs5xtgnznef0eaazvcy4c30rvnrtlmv48scxn7j2mhh83cgdjs7mxha62tvaf7480n2vm3pvzdae5x45mk29d9evqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq"
|
||||
},
|
||||
{
|
||||
"reason": "proof_missing_hashes_too_few",
|
||||
"bech32": "lnp1tqssxfr986kyx3ygqqkvq6alklcslcvfj834l8lyxqkmafkjx57up2cu4qs89ntwss3vgplmd5ycdy83zv9hmmt7ctmltcwnp0va2g0sz5mr0yasyypyhs4rzfj320c8uu8qh2cgwf8xhp0zzluv6c5vad3fwsj8hdyn8qhsgq9rxgj9dzm24ehdy5sp90tluyrjcqltmjnl538etvplrngfhc5tp2punsepqktcekqd5p5f09nzeq86qrlj2rxdcngckuyll5w84cce79qva0p96s9zmynmt672hpqq74p0hdag733w3hvq9wcnupgtn0ef8d690svmg6j8vaq0jlyadmq5ru35xnzaf7398gwjawyfd6adn9z4en7s86fqqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyql6ql2qcqsyk26tw5l6qltszlcev436mafhnw2k5qmt8uzcew9q6mlgdg5wdlhr9l3lnl2awk5rw2qdaxw2f4x5r2wpvax8mvf4qewx89ejwwluxnmthtjxtfjcq4tekwyfdfmx9cqe8ksuveseep97lccltp0c82kdg6ydppeya8suvtflxps7tpswr8m45flmccwudkdw9p4jytya5fqgz5u6k2uj6zq4j0aq0kxpuk74a0np03uakylclpy6s3grxlsdtcwfz33ggam6r3xxneu8hn87qv3cdgqqfr42judpgvk3x98jjlnm6yesft3z7xexxhlke20psd8ay4h0w0rssm9pakd0m55ke6na2wlx5ehzzcymmngdtfhv526tjc"
|
||||
},
|
||||
{
|
||||
"reason": "proof_missing_hashes_too_many",
|
||||
"bech32": "lnp1tqssxfr986kyx3ygqqkvq6alklcslcvfj834l8lyxqkmafkjx57up2cu4qs89ntwss3vgplmd5ycdy83zv9hmmt7ctmltcwnp0va2g0sz5mr0yasyypyhs4rzfj320c8uu8qh2cgwf8xhp0zzluv6c5vad3fwsj8hdyn8qhsgq9rxgj9dzm24ehdy5sp90tluyrjcqltmjnl538etvplrngfhc5tp2punsepqktcekqd5p5f09nzeq86qrlj2rxdcngckuyll5w84cce79qva0p96s9zmynmt672hpqq74p0hdag733w3hvq9wcnupgtn0ef8d690svmg6j8vaq0jlyadmq5ru35xnzaf7398gwjawyfd6adn9z4en7s86fqqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyql6ql2qcqsyk26tw5l6qltczlcev436mafhnw2k5qmt8uzcew9q6mlgdg5wdlhr9l3lnl2awk5rw2qdaxw2f4x5r2wpvax8mvf4qewx89ejwwluxnmthtjxtfjcq4tekwyfdfmx9cqe8ksuveseep97lccltp0c82kdg6ydppeya8suvtflxps7tpswr8m45flmccwudkdw9p4jytya5fqgz5u6k2uj6zq4jve32ml48r587uahkcd34r0hcadxv6qp0g87v5dekmqppushjwjmvqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqplgra3s09h40tuctu08d3878cfx5y2qehur27rjg5v2z8w7suf3570pauelsrywr2qqzga25hrg2r95f3fu5hu773xvz2ugh3kf34lak2ncvrflf9dmmncuyxeg0dnt7a99kw5l2nhe4xdcskpx7u6r26dm9zkjuk"
|
||||
},
|
||||
{
|
||||
"reason": "wrong_invoice_signature",
|
||||
"bech32": "lnp1tqssxfr986kyx3ygqqkvq6alklcslcvfj834l8lyxqkmafkjx57up2cu4qs89ntwss3vgplmd5ycdy83zv9hmmt7ctmltcwnp0va2g0sz5mr0yasyypyhs4rzfj320c8uu8qh2cgwf8xhp0zzluv6c5vad3fwsj8hdyn8qhsgq9nxgj9dzm24ehdy5sp90tluyrjcqltmjnl538etvplrngfhc5tp2punsepqktcekqd5p5f09nzeq86qrlj2rxdcngckuyll5w84cce79qva0p96s9zmynmt672hpqq74p0hdag733w3hvq9wcnupgtn0ef8d690svmg6j8vaq0jlyadmq5ru35xnzaf7398gwjawyfd6adn9z4en7s86fqqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyql6ql2qcqsyk26tw5l6qlt5zlcev436mafhnw2k5qmt8uzcew9q6mlgdg5wdlhr9l3lnl2awk5rw2qdaxw2f4x5r2wpvax8mvf4qewx89ejwwluxnmthtjxtfjcq4tekwyfdfmx9cqe8ksuveseep97lccltp0c82kdg6ydppeya8suvtflxps7tpswr8m45flmccwudkdw9p4jytya5fqgz5u6k2uj6zq4jve32ml48r587uahkcd34r0hcadxv6qp0g87v5dekmqppushjwjm07s8mrq7t027heshc7wmz0u0sjdgg5pn0cx4u8y3gc5ywaapcnrfu7rmenlqxgux5qqy364fwxs5xtgnznef0eaazvcy4c30rvnrtlmv48scxn7j2mhh83cgdjs7mxha62tvaf7480n2vm3pvzdae5x45mk29d9ev"
|
||||
},
|
||||
{
|
||||
"reason": "wrong_proof_signature",
|
||||
"bech32": "lnp1tqssxfr986kyx3ygqqkvq6alklcslcvfj834l8lyxqkmafkjx57up2cu4qs89ntwss3vgplmd5ycdy83zv9hmmt7ctmltcwnp0va2g0sz5mr0yasyypyhs4rzfj320c8uu8qh2cgwf8xhp0zzluv6c5vad3fwsj8hdyn8qhsgq9rxgj9dzm24ehdy5sp90tluyrjcqltmjnl538etvplrngfhc5tp2punsepqktcekqd5p5f09nzeq86qrlj2rxdcngckuyll5w84cce79qvl0p96s9zmynmt672hpqq74p0hdag733w3hvq9wcnupgtn0ef8d690svmg6j8vaq0jlyadmq5ru35xnzaf7398gwjawyfd6adn9z4en7s86fqqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyql6ql2qcqsyk26tw5l6qlt5zlcev436mafhnw2k5qmt8uzcew9q6mlgdg5wdlhr9l3lnl2awk5rw2qdaxw2f4x5r2wpvax8mvf4qewx89ejwwluxnmthtjxtfjcq4tekwyfdfmx9cqe8ksuveseep97lccltp0c82kdg6ydppeya8suvtflxps7tpswr8m45flmccwudkdw9p4jytya5fqgz5u6k2uj6zq4jve32ml48r587uahkcd34r0hcadxv6qp0g87v5dekmqppushjwjm07s8mrq7t027heshc7wmz0u0sjdgg5pn0cx4u8y3gc5ywaapcnrfu7rmenlqxgux5qqy364fwxs5xtgnznef0eaazvcy4c30rvnrtlmv48scxn7j2mhh83cgdjs7mxha62tvaf7480n2vm3pvzdae5x45mk29d9ev"
|
||||
},
|
||||
{
|
||||
"reason": "contains_invreq_metadata",
|
||||
"bech32": "lnp1qqq5ykppqvjx204vgdzgsqpvcp4mldl3plscny0rt707gvpdh6ndydfacz43e2pqwtxkappzcsrlkmgfs6g0zyct0hkhashh7hsaxz7e65slq9fkx7fmqggzf0p2xyn9z5ls0ecwpw4ssujwdwz7y9lce43ge6mzjapy0w6fxwp0qsq2xv3y269k4tnw6ffqz27hlcg89sp7hh98lfz0jkcr78xsn03gkz5re8pjzpvh3nvqmgrgj7tx9jq05q8ly5xvm3x33dcfllgu0t33nu2qe67zt4q29kf8kh4u4wzqpa2zlwm63arzarwcq2a38czshxljjwm52lqek34ywe6ql97f6mkpg8ergdx96naz2wsa96ugjm46mx29tn8aq05jqqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpl5p75pspqfv45kafl5p7hg9l3jetr4h6n0xu4dgpkk0c93ju2p4h7s63gumlwxtlrl8746adgxu5qm6vu5n2dgx5uze6v0kcn2pjuvwtnyualcd8khwhyvkn9sp2hnvugj6nkvtspj0dpcenpnjztal337kzlsw4v635g6zrjf60pcckn7vrpukrqux0htgnlh3sacmv6u2rtygkfmgjqs9fe4v4e95yptyenz4hl2w8g0aem0dsmr2xl0366ve5qz7s0uegmndkqzrep0ya9klaq0kxpuk74a0np03uakylclpy6s3grxlsdtcwfz33ggam6r3xxneu8hn87qv3cdgqqfr42judpgvk3x98jjlnm6yesft3z7xexxhlke20psd8ay4h0w0rssm9pakd0m55ke6na2wlx5ehzzcymmngdtfhv526tjc"
|
||||
}
|
||||
]
|
||||
}
|
||||
Reference in New Issue
Block a user