Evidence and its practical limits
Potential exculpatory factors
Evidence that may narrow the criticism of Spark or support its design. Each factor is limited to the implementation, setting or test actually reviewed.
Consumer recovery standard. For mobile recovery, the relevant test is a released wallet that preserves current state and completes the exit when operators are unavailable. SDK code, APIs and bindings are development groundwork until a wallet implements and demonstrates the complete flow. Their existence does not establish an available consumer recovery safeguard. Recovery is complete when the selected funds are confirmed and spendable under the user’s control; a further sweep is not universally required.
-
In the reviewed configuration, a new Bitcoin signature requires the user's contribution plus two operator shares. Even all three current operator shares alone do not supply the unknown current user's signing key.
Practical limit. The user key prevents an arbitrary spend with current operator shares alone, but it does not compel service. One operator can block the reviewed fresh all-participant operations; two can withhold the signing threshold. A hostile operator can therefore deny normal access without obtaining the user key. A separate conflicting-spend scenario requires two matching retained historical operator shares, the matching former-owner key, and a spendable output with the necessary ancestry. This is conditional, not evidence of theft. A wallet freeze alone cannot invalidate an already valid presigned Bitcoin exit.
Sources: User and operator signing contributions · Reviewed operator threshold · Key changes during ownership transfer · Preparation failure and rollback · Secret-share storage, versions and deletion design · Conditional former-owner spend and current-share boundary
-
With complete current exit state, signing material and fee funding, the exit can proceed without fresh operator signatures. The upstream offline-exit test stops the operators before preparing and signing packages, then mines the exit and checks the final destination value.
Practical limit. A hostile operator can withhold its recovery records or assistance; all three can withhold every operator-held copy available to them. If required state was not saved and cannot be obtained elsewhere, the seed does not recreate it. Honest surviving operators or independent backups may still help, and operator refusal cannot cancel a complete valid presigned exit. The inspected test begins with synchronized simple deposit leaves; its full infrastructure was not rerun for this review. It does not establish a released phone recovery flow or affordable recovery for arbitrary mainnet histories. The safeguard depends on preparation before cooperation ends.
Sources: Offline preparation from saved state · Operator-offline integration test · Incomplete recovery chains cannot be exited · Limits on withholding recovery records
-
The current Breez SDK constructs and signs exit transactions including sweeps, exports and imports recovery state, and checks confirmations and timelocks. Its Flutter bridge invokes the Rust implementation, and a persistent tree store preserves collected data. These helpers reduce the work a wallet must implement.
Practical limit. SDK helpers cannot retrieve state that refusing operators will not provide, nor do they make an unimplemented wallet flow usable during an outage. The app must preserve complete current recovery data and the returned exit state, supply Bitcoin fee funding, broadcast packages, schedule checks and resume across interruptions. Depending on the refusing service to supply a missing backup or fee sponsorship would leave an additional refusal point. No complete in-app flow was found in the dated reviewed surfaces; uninspected private implementations remain unverified. Mobile recovery is possible, but its protection must be delivered before the user needs it.
Sources: Flutter recovery implementation · Persistent tree storage · Responsibilities left to the application · Dated consumer-wallet review · Incomplete recovery chains cannot be exited · Recovery falls back to persisted wallet state · Fee funding and backup failure observations
-
A live mainnet swap at multiplicity 0 reorganized 38 leaves into 10 in 23.7 seconds, preserving the full 89,569-sat balance. At 1 sat/vB, the current planner then selected 81,920 sats as economical to exit, compared with 65,536 sats before optimization. This is a demonstrated improvement in the quoted economics; the resulting unilateral exit is still awaiting Bitcoin confirmations and timelocks. The earlier offline calculation on the saved 99,999-sat wallet remains a separate counterfactual below.
Same 89,569-sat mainnet balance, before and after live optimization| Measure | Before | After |
|---|
| Available leaves | 38 | 10 |
|---|
| Sats selected at 1 sat/vB | 65,536 | 81,920 |
|---|
| Sats excluded as uneconomical | 24,033 | 7,649 |
|---|
| Quoted exit fees, including optional sweep | 2,276 | 4,640 |
|---|
| Selected value minus quoted fees | 63,260 | 77,280 |
|---|
The quote selects more value after optimization, so its total fee also increases. These are same-balance planner quotes, not confirmed recovery proceeds. The live swap caused no balance reduction; sampled available funds fell to zero for roughly 23 seconds while the leaves were reserved. An offline variation with a 37-leaf batch cap planned the same ten denominations while leaving 65,536 sats outside the swap. That alternative was not tested live.
Same saved balance, three optimization settings| Policy | Leaves | Sats in largest two |
|---|
| Saved distribution; matches setting 2 | 36 | 49,152 |
|---|
| Current default: setting 1 | 21 | 65,536 |
|---|
| Exit priority: setting 0 | 10 | 98,304 |
|---|
The saved distribution exactly matches the current planner's target for setting 2, which plans no changes. This match does not prove which setting ran historically. These amounts describe denomination plans before fees; they are not measured recovery proceeds.
Practical limit. The favorable swap relied on a working SSP and operators. In the reviewed SDK, claiming its replacement leaves requires all-operator preparation, so one refusing operator can block completion. Once refusal begins, the user cannot assume it can improve the existing leaf structure. A wallet must schedule optimization, reconcile pending swaps and preserve complete replacement ancestry. Two of ten new leaves in this run required custom parent queries while an operator was reachable. The selected paths still had 1,200- and 3,200-block relative waits, roughly 8.3 and 22.2 days plus prior confirmations; 7,649 sats remained outside the economical selection. Optimization completed, but the subsequent exit remained pending at the recorded checkpoint. This desktop result is not a shipping mobile recovery flow.
Sources: Exit cost planning · Economical leaf selection · Optimizer denomination targets · Optimizer defaults · Payment-oriented denomination targets · Optimization invokes an SSP swap · Operator and SSP swap requests · Optimization policies and scheduling · Physical fee funding and sweep headroom · Experiment inputs, observations and quotes · SDK optimization swap claims the incoming counter-transfer · Incoming claim: all-operator consensus · Preparation failure and rollback
-
open-ssp runs its own Spark liquidity wallet and executes Lightning payments through LDK. Its inspected regtest includes completed-payment and balance assertions, and the reviewed commit's CI reports success. An SSP does not inherently have to be owned by Lightspark or by a signing operator.
Practical limit. Writing an SSP does not guarantee that the existing operators will serve it. The official operator code contains a Lightning receive-sender allowlist applied by every participant during preparation. One operator that enables the gate and excludes the provider can block the covered receive-swap flow. The gate defaults off and its production setting is unverified, but the exclusion capability is present. The open-ssp test uses forks with operator authorization disabled; it proves neither mainnet admission nor usable liquidity or automatic failover. Operators cannot prohibit independent software or a separate deployment, but a replacement SSP cannot bypass required cooperation on the existing one.
Sources: Independent wallet and service configuration · Lightning execution through LDK · Settlement assertions · Reported successful CI run · Pinned forks · Test authorization setting · Optional provider allowlist · Receive-sender check on every participant · Preparation failure and rollback
-
The reviewed Breez defaults request private mode. Operator code checks the authenticated identity before allowing covered reads of a private wallet. Knowing a wallet's public key therefore does not automatically grant access to its balance.
Practical limit. Private mode is an access rule enforced by the server, not encryption that conceals the records from its operator. One malicious operator can inspect or disclose the wallet metadata available to it without agreement from the other two. It can disregard its own query restrictions or publish a separate copy. Some transfer queries also remain readable when a counterparty is public. The setting protects against covered ordinary API lookups; it does not protect against the party holding the database. This describes available capabilities, not evidence that operators have disclosed private records.
Sources: Breez privacy default · Privacy setting initialization · Private-wallet access policy · Public counterparty transfer access · Non-signers still store transfer records · Sender and recipient fields in transfer state
-
The reviewed JavaScript and Breez defaults disable the Spark identity embedding decoded by spark-invoice-doxxer. Breez also rejects a recognized embedded address when it was not requested, and checks that a requested address matches the receiver.
Practical limit. Disabling public embedding does not hide the invoice-to-wallet link from operators: the reviewed receive records store the invoice, payment hash and wallet identity together. One malicious operator can correlate the records available to it and target that identity with refusal controls, irrespective of what a public invoice decoder sees. If a wallet enables embedding, invoice holders can also extract its Spark identity. Identifying a real person still requires additional information. The defaults reduce one public disclosure route; they do not prevent operator-side surveillance or targeted denial of covered operations.
Sources: JavaScript embedding defaults · Breez embedding default · Embedded-address validation · Operator invoice and identity storage · Wallet-specific refusal control · Preparation failure and rollback
-
Breez implements ordinary LNURL payment flows that obtain a BOLT11 invoice and pass it into the normal payment path. UMA is not a universal protocol prerequisite for these payments.
Practical limit. Using BOLT11 or LNURL does not oblige an SSP to execute the Lightning payment or an operator to prepare the Spark-side swap. A refusing provider can stop its configured payment path, and one required operator can obstruct covered fresh swap operations. Either can condition the cooperation it controls on identification or other access requirements without making UMA a protocol requirement. Changing invoice format does not remove those service dependencies. These are conditional policy powers, not evidence that ordinary Spark payments currently require universal KYC or compulsory UMA.
Sources: Ordinary LNURL payment implementation · Operator refusal capabilities and conditions · Lightning swap: all-operator consensus · Preparation failure and rollback · Wallet-specific refusal control · Conditional service access and KYC
-
Operator code supports a separate database for sensitive shares that must not enter backups, secret-version rotation and cleanup of obsolete versions. These mechanisms address the risk of retaining old signing material.
Practical limit. Cleanup code cannot force a malicious operator to forget a copy it retained before deletion. The separate store is optional, legacy paths remain and cleanup is best-effort; public code cannot attest production configuration or destruction of every copy. Two matching retained historical shares, together with the matching former-owner key and a spendable output with the necessary ancestry, create a conditional conflicting-spend risk. One operator deleting its share does not neutralize the other two under the reviewed threshold. The controls reduce accidental retention when followed, but do not prove hostile operators follow them or that any historical shares were actually retained.
Sources: Secret storage, rotation and cleanup design · Key rotation preserves the combined leaf key · The user contribution plus the operator threshold · Three configured operators; threshold two · Required conditions for a historical-key spend
-
The provider executes Lightning payments through its node, allowing a Spark wallet user to avoid running a Lightning node and managing its channels. This is a practical architectural benefit of the service-provider model.
Practical limit. The operational burden is delegated to a party that can refuse the service. Both reviewed SDK defaults use Lightspark's SSP; if it refuses or becomes unavailable, the user cannot make that configured Lightning path execute a payment. A replacement provider would still need usable integration, liquidity and required operator cooperation. The default SSP also receives payment requests linked to the Spark wallet identity. This convenience therefore leaves availability and privacy dependencies with service providers. No comparative speed, fee, reliability or throughput benchmark was performed, and outsourcing Lightning operations does not deliver an independent recovery flow in the wallet.
Sources: SDK Lightning payment flow · Provider executes Lightning payments · Default provider configuration and limits · SSP payment requests and wallet identity · Required operator cooperation for Lightning sends
Reviewed September 11, 2026. These entries describe the cited source versions and test coverage. They do not attest to production configurations or replace the dated consumer-wallet survey. Several contributions are specifically the work of Breez or independent developers. Practical limits examine adversarial refusal, data withholding, disclosure and secret retention where supported by the cited code. These are conditional capabilities, not findings that operators have exercised them. Download factors, sources and limits.