Roadmap
Built in phases, and held to them.
The signer is phases 1 to 4. The wallet layer, phase 5, is a lower assurance tier, and the companion, phase 6, runs on a networked machine and never on the device. Neither starts until the signer has run on the board and been reviewed. Keep real money off it until then.
Phases
What is built.
| Phase | Scope | State |
|---|---|---|
| 1 | Spec system, entropy, BIP-39/32, daemon, lock screen, networks | Complete: Complete |
| 2 | Descriptors, addresses, PSBT review, signing. Provisioning tier 0. | Complete with exceptions: Complete, except tier 0 signing and publishing, which are planned. PSBT version 2 is refused by decision, not supported |
| 3 | Encrypted store, passphrase, multisig, cosigner registration, tier 1 boot attestation | Complete: Complete |
| 4 | BIP-322 message signing, BIP-85 child seeds, BIP-329 labels | Complete: Complete |
| 5 | Wallet layer, optional and lower assurance | Not started: Not started |
| 6 | Bridge companion, runs on a networked machine | Not started: Not started |
| 7 | Miniscript, taproot script paths, SeedXOR. Tier 2. | Not started: Not started |
Source: the status table in README.md, read when this site was built. The state column is quoted, not summarised.
The order is the point. The tier boundary in the threat model and the phase order are what keep a large feature set from eroding the assurance of the small part that holds keys. The wallet layer is specified so that it can propose a transaction and never sign one, and so that removing it leaves a working signer with no other change. The direction of that dependency is already a lint rule with its own tests, before a line of the wallet exists.
Next
What comes next, and what each step proves.
- 1
Hardware bring-up on a Pi 5 and a Pi 4
The firmware path from power-on to the kernel, the panel and its touch controller, the webcam streaming to the kiosk, the layout on the real panel, and the Argon2id cost on the board. Each is recorded with evidence rather than a claim.
When it landsThe profile rows that say "unverified until bring-up" or "unverified on the panel" move, one at a time, as their evidence is committed. Photographs of the real device replace the panel renders.
- 2
An outside review of the code that holds keys
That somebody other than the author has read the entropy, derivation, review and signing paths and the specs they are held to. The spec system proves the code matches its specs; only a reviewer can say the specs are right.
When it landsThe word "unaudited" comes off this site when the review and its fixes are published.
- 3
A first tagged release
That a card image can be published with its SHA256SUMS, a signature and a manifest root, so a lock screen has a published number to be compared against. The build already pins its Debian packages to one archive snapshot, so a later build of the same tag sees the same inputs.
When it landsThe lock screen stops being comparable only against your own build.
- 4
The signer profile through public review
Whether people who build signers and coordinators accept the positions the profile takes, and whether a second implementation can meet it as written.
When it landsThe profile leaves version 0.1 with a record of each decision and who argued it.
17 of the profile’s 63 conformance rows for this device are not yet met without qualification, most of them waiting on the board. Which ones, and why.
Log
What has landed, and when.
- 2026-10-28The verification guide is shorter and 23 statements in it that the code contradicts are corrected. Among them: the command for recomputing the verity salt used version 0.4.0 and could never match a build, and the manual Bitcoin Core recovery imported no change descriptor, which Core 31 needs to build a spend.
make test-repronamed a test by an old name and had silently stopped running the cross-check against libsecp256k1; it now fails unless every named test ran. The boot test now needs systemd to report starting the daemon, not merely to mention it. - 2026-10-28The signer signs only the inputs the review counted as the wallet's (INV-SIG-13). It passed each key to a library call that signs every input whose script contains the key, so an input locking this device's key under another script, as p2pkh or inside a stranger's multisig, was signed while the review showed it as someone else's money; that call also dropped every per-input error. Found by checking the threat model against the code.
- 2026-10-28The descriptor parser refuses what BIPs 381 to 387 call invalid: a script where its BIP does not allow it, a key its context does not allow, and a multisig past its context's limit (INV-DPARSE-12). Twenty two of the BIPs' published invalid descriptors used to parse and be refused only by the evaluator, and the device's own descriptor.parse method reported them as parsed.
- 2026-10-28The docs can be searched (the header, Ctrl K, Cmd K or "/"), from an index this build writes, with nothing sent anywhere. Code blocks have a copy button. The install guide opens with the three ways in, and the user manual is a third shorter with every refusal kept. Condensing it surfaced seven statements the code contradicts, now corrected. Two were also on the device's own screens: five places offered an SD card transport that is not built, and one said every device in a quorum holds the same wallet. The read-back command in the install and verification guides could never match, because it read whole 4 MB blocks of an image that is not a multiple of 4 MB; it now reads exactly the image's length.
- 2026-10-28nullroute.diy is a product page and a documentation set. The home page says what the device is, how using it goes, how to check it and what to buy, in that order. The docs are ten chapters in five groups with a sidebar, one page per section: 84 pages cut from the same repository files, keeping the anchors GitHub gives them, so every cross-reference resolves. The check, device and profile sub-pages folded into the docs, with redirects.
- 2026-10-27A heartbeat answered after the screen that sent it had gone updated that screen anyway. Under test that threw "window is not defined" into whichever file ran next, which is why
make ui-racefailed about one run in several under load. The answer now updates nothing (INV-UI-98). - 2026-10-27INV-PROV-13 says no wireless kernel module is on the card, and the prune behind it removed 802.11 and Bluetooth only. Both kernels also shipped a Realtek SDIO Wi-Fi driver in staging, 802.15.4, NFC, packet radio, cellular modems, two FM transmitters and HackRF. All are removed now, and the assertion's globs fail a card that still carries any of them.
- 2026-10-27The card carries a Pi 5 bring-up path beside the Pi 4's. A Pi 5 boots Raspberry Pi's 6.18.50 kernel, pinned by digest, because only that kernel drives the official 7 inch panel there;
config.txtgives each board its own section. The Pi 5 is listed underbring_up:and notboards:until it boots with the panel lit. The initramfs now asks the kernel's own dependency data which modules to load. The boot partition is typed FAT and marked bootable, as Raspberry Pi's builder marks it (INV-PROV-35); every earlier card had it typed "Linux filesystem". - 2026-10-27BIP-387 and BIP-389's published descriptor vectors are run, so every descriptor document the signer profile claims now has its vectors run. BIP-389's found a defect: multipath elements of different lengths, and a repeated value such as
<1;1>, parsed and derived addresses. Both are refused (INV-DPARSE-11). SP-DEP-1 has a conformance row for the first time. - 2026-10-27BIP-174's published Input Finalizer PSBT and Transaction Extractor transaction are reproduced byte for byte by the call the signer finalises with (INV-SIG-12). The vector file carried them unchecked, on the grounds that the device did not play those roles; it plays both whenever its signature completes a quorum.
- 2026-10-27A BSMS file's first address is checked against this device's own derivation, and a file stating another is refused (INV-COORD-7), as BIP-129 asks of a signer. It had been shown as an unchecked claim, so two of Sparrow's tampered test files were read; they are refused now.
- 2026-10-27Whether to sign is decided by one function,
signVerdict, that the signer, the review screen's Sign button and the conformance adapter all call (INV-SIG-11). The signer had readsignablealone; it now also holds a review that carries a blocking warning, as the screen already did.
Source: CHANGELOG.md, read when this site was built, has the 32 entries in full; these are the latest 12. The whole history is the repository’s commit log.
Limits
What it does not protect against.
- No secure element
- Someone holding the SD card is limited by your passphrase and Argon2id at 64 MiB and three passes, and nothing else. Use it as one key in a multisig quorum with devices from other makers, never as sole custody.
- The boot partition is not covered
- dm-verity detects modification of the system partition and does not prevent it. An attacker who rewrites the boot partition supplies their own root hash. A signed boot chain closes that in phase 7, last on purpose, because it burns one-time fuses.
- The browser is the weakest part
- The screens run in a Chromium kiosk, so trust is kept out of them: the daemon holds the keys, and the screens see only public data and transactions.
- Side channels and physical attack
- Power, electromagnetic and timing attacks against the Pi, and sophisticated attacks on the card or the chip, are out of scope and stated so.
- A person who knows the code
- Hidden profiles and a wipe PIN are planned for phase 7. When they exist they buy time against somebody unsophisticated and nothing more, because this codebase is public.
The full list is in the threat model, and it is long on purpose. If a limit there is understated, that is worth reporting: overclaiming in the threat model is itself a security bug here.