Signer profile
What an air-gapped signer should have to show you.
Air-gapped signers agree by convention on things no BIP writes down. The profile writes them down as requirements, each naming the check that decides it, and the conformance kit turns the testable ones into JSON vectors any signer can run.
- State
- Draft 0.1
- Date
- 24 September 2026
- Requirements
- 63 in 7 areas
- Test cases
- 116 in 13 files
- Adopted by
- No one yet
- Discussion
- GitHub issues
Scope
Four questions a user cannot answer today.
- Where did the seed come from?A rule for turning dice into a seed that anyone can repeat with coreutils, and the arithmetic for how many rolls are enough.
- What will this signature authorise?What a signer must show before it signs, what counts as change, and which findings must disable signing until an explicit, single-use override.
- Which software is asking for my passphrase?A number the user can recompute from source before entering a PIN, and what that number does and does not prove.
- What hardware does the argument assume?Capabilities rather than models: a display only the signer drives, a way in that is not a network, and radios absent or with their drivers and firmware removed.
The kit
Expected values from outside the implementation.
None of these came from nullroute: review cases are PSBTs built and judged by Bitcoin Core, dice and manifests come from the BIP texts and coreutils, and the QR cases from reference encoders. Every file is pinned by a SHA256SUMS that coreutils can check.
| Vector file and requirements | nullroute | Your signer |
|---|---|---|
bbqr-psbt | 12 of 12 | not run |
dice-accounting | 25 of 25 | not run |
dice-to-entropy | 17 of 17 | not run |
manifest-root | 2 of 2 | not run |
review-change | 9 of 9 | not run |
review-fee-and-amounts | 7 of 7 | not run |
review-input-amounts | 7 of 7 | not run |
review-ownership | 5 of 5 | not run |
review-sighash | 13 of 13 | not run |
review-timelocks | 9 of 9 | not run |
review-unknown-fields | 2 of 2 | not run |
sign-override | 3 of 3 | not run |
ur-psbt | 5 of 5 | not run |
| 116 cases in 13 files | 116 of 116 | none yet |
From this build’s make conformance. The second column is for your signer, and it stays empty until somebody runs the kit against one.
Coverage
Where nullroute meets it, and where it does not yet.
nullroute is held to the profile as one implementation among others, not as its reference. Most requirements are met; the rest wait on hardware or a manual procedure.
| Area | Requirements | Met | With a caveat | Open |
|---|---|---|---|---|
| Entropy SP-ENT | 11 | 9 | 1 | 1 |
| Pre-signing review SP-REV | 21 | 19 | 2 | 0 |
| Signing SP-SIG | 1 | 1 | 0 | 0 |
| Attestation SP-ATT | 12 | 9 | 2 | 1 |
| Hardware SP-HW | 10 | 2 | 4 | 4 |
| Transport SP-TX | 7 | 6 | 1 | 0 |
| Dependencies SP-DEP | 1 | 0 | 1 | 0 |
Not yet met without qualification
- SP-ENT-8Met for sampling; screen copy manual
- SP-ENT-11Manual
- SP-REV-5Met in the headless render; unverified on the panel
- SP-REV-21Met in tests; unverified on the panel
- SP-ATT-1Met in tests; unverified on the panel
- SP-ATT-10Met in tests; unverified on hardware
- SP-ATT-12Manual
- SP-HW-1Unverified until bring-up
- SP-HW-2Met in the headless render; unverified on the panel
- SP-HW-3Met against a software decoder; unverified with a camera
- SP-HW-4Unverified until bring-up
- SP-HW-5Unverified until bring-up
- SP-HW-6Met in the image; unverified on the running device
- SP-HW-8Met in the build; unverified on hardware
- SP-HW-10Measured on Pi 4 per its spec
- SP-TX-5Met for PSBT and transaction frames
- SP-DEP-1Met for what nullroute implements; valid vectors outside that are asserted refused, each with its reason
Disagree
Positions others may reject.
A profile nobody has argued with is not yet worth adopting. These are the positions people who build signers and coordinators may reasonably dispute.
- 100 rolls, not 99.Three signers accept 99, which is 255.911 bits. The profile asks for 100, and the cost is that a 99-roll seed from those devices cannot be reproduced here.
- A segwit v0 input without its previous transaction blocks signing.Its amount is the coordinator’s word, and BIP-174 describes the attack that exploits it. The block can be lifted for one signature, never stored.
- Schnorr signatures with aux_rand fixed to zero.BIP-340 notes that fresh randomness there increases protection against fault injection. The profile gives that up so anyone holding the seed can recompute every signature byte for byte.
- Change is only what the signer can re-derive.Anything the PSBT merely claims is shown as a payment, with the claim reported.
If you build a signer or a coordinator, the most useful thing you can do is run the kit against it, or tell us which requirement is wrong. Open an issue.