Switch to open source.Explore →
← All apps
Lightning · Spark

Spark Signer

Spark wallet cold signer

Runs the Spark SDK in the browser with a custom signer that delegates every key op to Passport. No seed or FROST nonce ever in the browser.

View the code

Last updated Jul 2026

Passport Prime

Wallet · protected by Passport

Overview

A hardware signer for Spark (Lightning + on-chain) wallets. A browser GUI and a CLI companion run the stock @buildonspark/spark-sdk (pinned to 0.8.6) with a custom PrimeRemoteSigner that forwards every secret-touching operation (key derivation, FROST nonce, signing) to the device over newline-delimited JSON-RPC. No seed, private key, or FROST nonce ever exists in the companion.

FROST nonces are generated in device RAM, returned only as a commitment, and deleted before signing; a reboot wipes outstanding nonces and the wallet retries with a fresh commitment. Spend requests pass an on-device policy gate (per-tx, daily/weekly caps, optional allowlist) before a human slides to approve. Verified M0–M2 end-to-end on REGTEST against the KeyOS hosted simulator.

What it does

  • PrimeRemoteSigner delegates ~15 secret-touching SDK methods to the device; seed-export methods are disabled outright.
  • FROST nonces are RAM-only, single-use, commitment-only; reboot wipes them, so replay or reuse finds nothing.
  • On-device policy gate (per-tx, rolling daily/weekly caps, freeze switch, optional allowlist) with persist-before-sign.
  • L1 deposit claims and refunds are reconstructed and verified on-device, with the sighash bound to the checked amount and recipient.
  • Spark transfers and Lightning are policy-gated and human-approved, shown with an explicit "reported by companion" caveat.
  • Receiving re-keys an incoming leaf into the device’s sole control; it completes silently and never counts against the spend limits.
  • WebSocket on the simulator (ws://127.0.0.1:9911); USB CDC-ACM on hardware (M3). A Noise_XX session layer is designed for v1.5.
  • SDK is pinned exactly to 0.8.6: a re-audit is required on every SDK bump.

See it in action

Technical breakdown

How the app is built, for developers evaluating the platform.

01

Keys never touch the browser

PrimeRemoteSigner (src/lib/prime-remote-signer.ts) implements the SDK’s SparkSigner interface and routes every key operation to the device: getIdentityPublicKey, getRandomSigningCommitment, signFrost, aggregateFrost, ECIES decrypt, secret splitting, and more. Seed-export methods (getStaticDepositSecretKey, generateMnemonic, mnemonicToSeed) throw. The SDK is handed an all-zero dummy seed; the device derives m/8797555’/account’/{0..4}’ from its own entropy.

02

Transport

The companion talks to the device over newline-delimited JSON-RPC ({id, method, params} → {id, result|error}), WebSocket on the simulator (ws://127.0.0.1:9911), USB CDC on hardware. Read-only methods time out at 10 s; approval-gated methods at 180 s, since a human may be deciding on the device screen. A single Lightning payment can burst 120+ sign calls.

03

Policy & intent verification

The policy engine (ported from the Nunchuk POC: per-tx, daily/weekly, freeze, allowlist) decides AutoSign / RequireApproval / Reject and flushes the ledger before any signature releases. L1 deposit claims and refunds are reconstructed on-device with the sighash bound to a verified amount and recipient; live unilateral-exit broadcast is not yet done. A Spark transfer splits into power-of-2 leaf denominations, so no single signature carries the operation total, which is why transfers and Lightning are policy-gated but companion-asserted in v1, with hardware bring-up and a Noise session layer on the roadmap.

Dig into the source

README, architecture notes, and the wire protocol live in the repo.

View the code

Browse by category