Skip to the content
nullroute
Browse the docs

The trust boundary between the signer and the wallet layer

nullroute is designed around two assurance tiers. One of them exists.

packages/wallet has not been written, phase 5 has not been opened, and the verifier reports the literal signer, so there is nothing to distinguish and the lock screen does not distinguish it. This section described the boundary in the present tense, which is the wrong tense for a boundary with one side. What follows is the design the phase ordering exists to protect, and INV-WALLET-1 is enforced today by a lint rule in the direction that can be enforced without the second package.

Tier 1, the signer (packages/core, packages/daemon, packages/ui) is small on purpose. Every parser and every branch that runs near a private key is a place where a bug becomes a loss. This tier is verified to the standard described in VERIFICATION.md, and it is what a default build contains.

Tier 2, the wallet layer (packages/wallet) adds UTXO tracking, coin control, and transaction construction. It roughly doubles the code on the device, and most of that new code processes attacker-influenceable data: UTXO snapshots, labels, and transaction history that arrived across the air gap from a machine that is on the internet.

That is an acceptable trade only because the boundary is enforced rather than promised:

  1. packages/wallet may import from packages/core. Never the reverse. A lint rule enforces the direction and CI tests it. (INV-WALLET-1)
  2. The wallet layer proposes transactions. It cannot sign them. Signing is reached only through the same review and confirmation path as an externally supplied PSBT, with no shortcut for self-constructed transactions. (INV-WALLET-2)
  3. Removing packages/wallet from the build yields a fully functional signer with no code changes anywhere else, and changes the manifest root hash so you can prove which one you are running.
  4. Wallet-tier invariants are about correctness and clarity. Key-safety invariants live in core and hold regardless of what the wallet layer does.

If you want the smallest attack surface, run a default signer-only build and keep your wallet software on a separate machine.


Rendered from docs/THREAT-MODEL.md, the same bytes that ship with the code. SHA-256 d932f13db7fe836f45194ab98069c47dc556d4f29b2cfbf0ef1ab3bf7b334ffd