# Security model: short FAQ


**Draft, not yet verified on hardware.**

Answers for stock firmware v1.4.3: what the SeedHammer II stores, what can leave it, which firmware it runs, and how to handle seeds, descriptors and plates.

<p class="alert alert-warning">Seed words are typed on the machine's touchscreen only, never through a phone, a computer or a chat assistant. Any request for them in a message or on a website is a scam; an account posing as SeedHammer has sent such requests.</p>

## The model in short {#summary}

| Question | Answer |
| --- | --- |
| Does it keep anything after power-off? | No. In normal use the firmware writes nothing durable. |
| Can a stolen machine reveal a seed? | Not a genuine board running signed stock firmware. Replace a board you suspect was swapped; do not test it. |
| Can it send what I type? | Its only radio is NFC, on only on the start screen, where a phone that reads it sees an empty tag. The USB-C port also carries data, see [What can leave the machine](#leaks). |
| Can the sound give words away? | Not through timing: each letter of a seed word and each SeedQR module takes a fixed time. The motors still trace the shapes, and the job length varies only with the word count and the fingerprint line ([Timing and sound](#timing)). |
| Does it create seeds? | No, by design, to avoid the random-number bugs seen in signing devices. Bring a finished seed. |
| How large is the attack surface? | Small: no seed generation and no channel that sends out what you enter. |
| Is a descriptor secret? | No. It reveals every address of the wallet. |
| Can I run my own firmware? | Yes, with the hash of your own signing key written into the chip's one-time memory. That write cannot be undone. |

## What the machine keeps {#storage}

| Part | What it holds | Written by v1.4.3 |
| --- | --- | --- |
| RP2350 microcontroller, RAM | words, descriptor and job while powered | yes, volatile |
| RP2350 one-time memory (OTP) | boot key hash, secure-boot flag, USB drive labels | only by the [secure-boot setup](#lock-boot), never anything you enter |
| W25Q128 flash chip (16 MB) | the firmware image | no; a firmware upgrade writes it through the chip's built-in boot mode |
| TMC2209 stepper drivers on the board; display driver on the LCD module | their own small OTP areas | no |

While the machine is on, anyone who sees "Engrave Seed" can read the words; after 3 minutes without input a screen saver covers the screen.

| To | Do |
| --- | --- |
| Drop a seed without engraving it | On "Engrave Seed" tap back, hold the trash on "DISCARD SEED?" for 1 second, then unplug the machine. Discarding returns to the start screen but does not clear the words from RAM. |
| Clear the words after a job | When "Engrave Plate" shows "Engraving completed successfully.", unplug the machine and wait for the screen to go dark. |

Hidden hardware that records what you type cannot be ruled out from the outside; it could sit anywhere, even in the motors, but away from the controller board it is hard to hide and captured data is hard to send out. Fit a board you trust, or destroy the old one ([Lending, selling and travel](#lending)).

## Which firmware runs {#firmware}

| Item | Detail |
| --- | --- |
| Firmware source | public domain since 2026-04-23, <a href="https://github.com/seedhammer/seedhammer" target="_blank">github.com/seedhammer/seedhammer</a> |
| Board and machine design files | <a href="https://github.com/seedhammer/hardware" target="_blank">github.com/seedhammer/hardware</a> |
| Build | deterministic: a build from source matches the released image bit for bit, except for the signature (unverified, see [Rebuild a release](#reproduce)) |

### Rebuild a release {#reproduce}

- Install Nix with flakes enabled.
- Check out the tag `v1.4.3` of the firmware repository.
- Run `nix run .#build-firmware`. It writes `seedhammerii-v1.4.3.uf2`.
- Run `nix run .#copy-signature <official .uf2> <your .uf2>` to copy the official signature into your build.
- Compare the two files, for example with `shasum -a 256`. The hashes match (unverified).

### Read the lock mark {#unlocked}

With secure boot on, the RP2350 starts only firmware signed by a key whose hash is written into its OTP.

| Line at the bottom right of "Backup Wallet" | Meaning |
| --- | --- |
| "Firmware: v1.4.3" | the firmware version |
| "Hardware: v1.5", for example | secure boot is on and the SeedHammer key is the only valid boot key |
| "Hardware: v1.5 (UNLOCKED)" | secure boot is off, or the SeedHammer key is not the only valid boot key |

![Start screen "Backup Wallet" with the firmware and hardware lines at the bottom right](/static/img/security-faq-01.webp)
<!-- capture: II screen, start screen "Backup Wallet", firmware v1.4.3, bottom-right lines "Firmware: v1.4.3" and "Hardware: v1.N" on a locked unit (no " (UNLOCKED)"); second frame of a unit with an owner boot key showing "Hardware: v1.N (UNLOCKED)" -->

The running firmware draws " (UNLOCKED)": firmware signed with another key shows whatever its author chose.

- Install the official release yourself, as in [Firmware upgrade](/doc/manual/firmware-upgrade).
- Connect the machine's power supply and wait for "Backup Wallet".
- Read the hardware line. Without " (UNLOCKED)", secure boot is on and only the SeedHammer key is valid.

A shipped unit on v1.4.3 shows no " (UNLOCKED)" (unverified).

### Use your own signing key {#own-key}

The RP2350 has four boot-key slots and a stock machine uses one.

You can write the hash of your own public key into a free slot and sign your own builds; it takes development work.

The firmware repository includes `cmd/picosign` for signing on an external device: it extracts the data to be signed from an image and replaces the image's signature with one made elsewhere.

The OTP write cannot be undone.

Afterwards stock firmware shows " (UNLOCKED)", because the SeedHammer key is no longer the only valid key.

Keep your key offline, like a seed: anyone who holds it can make firmware your machine will run.

### The secure-boot setup command {#lock-boot}

| NFC text on the start screen | Result |
| --- | --- |
| exactly `command: lock-boot`, nothing after it | writes the USB drive labels and the SeedHammer key hash to OTP, turns secure boot on and restarts |
| `command: ` with any other text after it, even a trailing line break | unknown command |

Only the start screen accepts the command.

On a machine that is not yet locked, secure boot stays on for good afterwards.

The command adds the SeedHammer key and removes none. An owner key written earlier stays valid.

On a locked machine the command only restarts it (unverified).

## What can leave the machine {#leaks}

| Channel | v1.4.3 |
| --- | --- |
| Radio parts in the published board files | the NFC chip (ST25R3916) and its antenna; no Wi-Fi or Bluetooth part |
| Radio parts on a shipped board | the same (unverified) |
| NFC on | only while "Backup Wallet" is shown; off during "Input Seed", "Input Words", "Engrave Seed" and "Engrave Plate" |
| NFC toward a phone | a tag the phone writes to; a phone that reads it sees an empty tag |
| NFC with no phone near | polls as a reader for physical NFC tags (ISO 15693 and ISO 14443A Type 2), see [NFC tags, cards and desktop writers](/doc/manual/capability-sheet#tags) |
| NFC on receipt | "Scanning...", then "Unknown format" or "Scan error" for about one second, or the next screen |
| USB-C data | firmware upgrades reach the chip's built-in boot mode through the port |
| USB serial log | opened by a release build (unverified) |
| Log content | no seed words, no descriptors; the only text you send that can appear is an unrecognised `command: ` text from NFC |
| USB-C power | runs only on a USB-PD offer of 20 V to 28 V at 3 A or more; on a computer port without one, the machine restarts into upgrade mode |

Compare every engraved plate with what you meant to engrave.

### Disconnect the NFC chip {#nfc-off}

In the published board files, three solder jumpers (JP2, JP3, JP4) beside the silkscreen text "NFC CUT HERE" carry the clock, data and interrupt lines between the microcontroller and the NFC chip.

Power is not affected: the USB-C power controller sits on the microcontroller side.

**Important:** treat this as permanent; afterwards descriptors, and anything else sent over NFC, can no longer reach the machine.

Seed entry on the touchscreen runs on a separate bus and keeps working (unverified).

- Unplug the machine.
- Sever the thin link between the two pads of each of the three jumpers.
- Confirm with a multimeter that none of the three conducts across its pads.

![Controller board with the three NFC solder jumpers beside the text NFC CUT HERE](/static/img/security-faq-02.webp)
<!-- capture: photo, SH II controller board front, silkscreen "NFC CUT HERE" with solder jumpers JP2, JP3, JP4 beside it, intact; second photo with the jumpers open; note board version -->

### Timing and sound {#timing}

| What is engraved | Timing | Detail |
| --- | --- | --- |
| Seed words | constant | each letter takes the time of the slowest letter, and every word takes 8 letters, the length of the longest BIP39 word |
| SeedQR on a seed plate | constant | a fixed number of module steps of equal time, set by the QR size |
| codex32 share text and QR | constant | as for seed words and the SeedQR |
| Word numbers, fingerprint line, codex32 share identifier | varies with the content | none of them is secret |
| Descriptor text and QR | varies with the content | a descriptor is not a secret |

Constant time evens out duration only.

The stepper motors still trace the letter shapes and visit the QR modules; anyone who can film the plate or tap the motor wires can read it.

The total job length varies only with the number of words and with the fingerprint line.

## Seeds and phones {#seeds}

| Input | Rule |
| --- | --- |
| Seed words | Tap the checkmark on "Backup Wallet", choose **12 WORDS** or **24 WORDS** on "Input Seed", then type on "Input Words" ([Enter a seed](/doc/manual/seed-entry)). |
| Seed words as NFC text | The machine accepts them. Never send them from a phone or a signer: the words would stay on the phone, or travel over radio from a signer such as a Coldcard. |
| Descriptors | Use NFC Tools on iPhone or Android for descriptors only ([Send a descriptor with NFC Tools](/doc/manual/nfc-tools-transfer)). NFC Tools writes with the phone in airplane mode (unverified). |

v1.4.3 cannot create a seed and does not compute a last word.

The checkmark on "Engrave Seed" appears only when every word is filled, and a failed checksum shows "Invalid Seed".

To make a seed by hand, roll dice against a published word table, compute only the last (checksum) word with an offline device you trust, and type the full seed.

## Descriptors {#descriptors}

A descriptor is not a secret, but it reveals every address of the wallet: whoever reads it can follow every payment and the balance.

It cannot spend.

| Case | Risk | What to do |
| --- | --- | --- |
| A multisig descriptor is lost | the larger risk: it holds the other cosigners' public keys; if one seed is lost, the remaining seeds cannot rebuild the wallet without it | keep it on steel |
| It sits on a phone for the NFC transfer | the same privacy risk, no theft risk | avoid email, chat and cloud notes when you move it to the phone |
| Each plate can carry the full descriptor | one found plate reveals the wallet's addresses | choose which plates carry it ([What fits on a plate](/doc/manual/multisig-and-fit)) |

## Splitting a seed {#splitting}

| Question | Answer |
| --- | --- |
| Part of a seed on each plate? | Never: every word on a plate shortens the search for the rest. With 9 of 12 words known, three missing words leave about 8.6 billion combinations (2048 x 2048 x 2048), and the checksum rules out 15 of every 16, which leaves about 537 million for recovery software to try. |
| Which seeds does v1.4.3 engrave? | Only complete seeds with a valid checksum. The touchscreen takes 12 or 24 words; NFC text takes any multiple of 3 words up to 24 (unverified). |
| Shares? | The machine neither splits nor combines shares, and "SLIP-39" is not offered. A codex32 share reaches it only over NFC and passes through the sending device ([Shares](/doc/manual/capability-sheet#shares)). |
| Redundancy? | Use a multisig: each plate holds one complete seed, and the descriptor goes on the plates you choose. |
| Shares inside a multisig? | Stacking schemes adds steps an heir must undo correctly. A plain 2-of-3 with the plates in separate places is easier to recover. |

## Lending, selling and travel {#lending}

The controller board unplugs from the frame and stores nothing.

Replacing it is never required; swapping it lets you decide what happens to the electronics that saw your seed.

| Situation | Do |
| --- | --- |
| Selling or lending the machine | Fit another board and keep the old one; destroying it is possible but not recommended. |
| Borrowing a machine | Fit your own board first. |
| A new board | Install the current release before use ([Firmware upgrade](/doc/manual/firmware-upgrade)). |
| Removing the board | See [Hardware and spare parts](/doc/manual/hardware-and-spares). |
| Keeping seeds off the machine | Optional: punch seeds by hand and use the machine only for descriptor plates. |
| Travel with the machine | Machines and blank plates have travelled in cabin luggage without trouble. |
| Travel with plates | Plan as if an inspector reads and photographs any engraved plate. Do not carry seed plates across borders. |
| Destroying a plate | Grind every engraved face with an angle grinder or a flap disc until no character or QR module can be read; it takes seconds. Wear eye and hearing protection. |

## If it does not work {#troubleshooting}

| Symptom | Cause | Fix |
| --- | --- | --- |
| **The start screen shows "(UNLOCKED)" after the hardware version.** | Secure boot is off, or a boot key other than the SeedHammer key is valid. | Expected if you added your own key. Otherwise install the official release yourself and look again; if " (UNLOCKED)" stays, do not engrave seeds with this board and replace it. This assumes shipped units on v1.4.3 show no " (UNLOCKED)" (unverified, see [Read the lock mark](#unlocked)). |
| **The screen stays dark after you install the official release.** | Power, or a board that refuses SeedHammer-signed firmware because secure boot is on and only another key is valid (unverified). | Connect the machine's own supply ([Power supply and first start](/doc/manual/power-and-first-start#troubleshooting)). If the screen still stays dark, do not engrave seeds with this board. |
| **"Scan error" keeps flashing with the NFC jumpers open.** | The start screen keeps polling an NFC chip it can no longer reach (unverified). | Expected; seed entry runs on a separate bus and is not affected (unverified). |
| **"Invalid Seed" with "The seed phrase is invalid." for a seed made with dice.** | The last word carries a checksum and v1.4.3 does not compute it. | Compute the last word with an offline device you trust, tap the checkmark to return to "Engrave Seed", select the last word and correct it with the pencil. |

<!--
bench-checks:
  - [x] cite firmware source for no durable writes, secure boot and the constant-time engraving path (drafting
        2026-10-10, v1.4.3 = ea4b65b, lab/check/upstream identical to upstream/main for every file below; reviewer to
        re-read):
        durable writes: only callers of driver/otp writes are cmd/controller/platform_sh2.go:510-519 LockBoot and
        :666-694 writeOTPValues; no machine.Flash, EraseBlocks or WriteAt in non-test code; driver/tmc2209 only
        reads OTP (OTP_READ); driver/ili9488 and ft6x36 have no OTP code; bip39.RandomWord and FixChecksum are called
        only from tests and cmd/biptool (host tool), gui never calls them.
        secure boot: platform_sh2.go:70 signKeyHash, :246-249 FeatureSecureBoot, :712-739 isSecureBootEnabled
        (enabled && ours && nvalid == 1), gui/gui.go:2370-2373 " (UNLOCKED)"; driver/otp/otp.go:14 NumBootKeySlots = 4,
        :93-95 EnableSecureBoot, :102-157 AddBootKey (returns the existing slot when the key is already valid),
        :289-296 IsBootKeyValid (revoked slots not counted); lock-boot trigger gui/gui.go:1415-1421.
        constant time: backup/backup.go:61-73 EngraveSeed (ConstantQR), :75-87 EngraveSeedString (ConstantQR),
        :227-240 wordColumn -> ConstantStringer.PaddedString, :242-249 stringColumn -> ConstantStringer.String;
        engrave/engrave.go:1251-1277 paddedString loops `for range longest`; bip39/wordlist.go:7-9 ShortestWord 3,
        LongestWord 8; gui/gui.go:454-480 engraveSeed passes them. Not constant: fingerprint line backup.go:178-187
        (engrave.String), word numbers backup.go:230, codex32 identifier (Title) via engrave.String, descriptor EngraveText backup.go:286 (engrave.QR) and :321
        (engrave.String). Constant time covers duration only: paddedString pads each letter with a Delay but still
        traces the real glyph (engrave/engrave.go:1300-1303, engraveSpline), and ConstantQR's path visits the data
        modules (engrave.go:406-478); company: head signals carry no seed data, only the XY steppers do (harvest
        HARVEST.md security-model, BOM/engraving-head item). Page says timing only, not "nothing learned".
        fix stage 2026-10-10 (review findings): lock-boot needs the exact text: gui/scan.go:55-57 cmdPrefix keeps the
        whole rest, gui/gui.go:1415 case "lock-boot", :1422-1423 default "unknown debug command" (logged with %q).
        LockBoot adds the key and sets CRIT1 bit 0 only, removes no key: otp.go:93-95, :102-157 (valid occupied
        slots skipped). NFC mnemonic: bip39/bip39.go:229-247 Parse (up to 24 words), :107-117 Valid (multiple of 3),
        routed to "Engrave Seed" by engraveObjectFlow (device-screen-map 1.4). Reader role: nfc/poller/poller.go:103-120
        (device-screen-map 1.4 and 6; nfc-tools-transfer section 0 "Physical tags"). Read-back: nfc/type4/type4.go
        emptyFile, a phone sees an empty tag (nfc-tools-transfer section 0 "Read-back"). Discard: gui/gui.go:1866-1883,
        ConfirmYes returns, nothing clears the mnemonic. Touch bus: platform_sh2.go:144-146 touchI2C = I2C1 vs
        dataI2C = I2C0, :207-210, :259-263 touch on touchI2C, :269 NFC on the dataI2C multiplexer. picosign:
        cmd/picosign/main.go:1-7 (hash extracts the data, sign replaces the signature). PD gate: platform_sh2.go:428-441
        rebootIntoBOOTSEL (device-screen-map 1.1). README "Reproducible builds" is hedged ("designed to be
        deterministic", "should match").
        NFC: gui/gui.go:1340-1390 reader opened and closed with StartScreen.Flow; driver/st25r3916/st25r3916.go:297-302
        Close writes 0 to regOpCtrl; nfc/type4/type4.go:103-105 emptyFile, :232-249 read serves only the capability
        container or the empty file. No SECURITY.md in `git ls-tree upstream/main`.
  - [ ] photograph the three NFC isolation traces on the PCB: JP2 (DATA_SCL), JP3 (DATA_SDA), JP4 (NFC_INT), bridged
        solder jumpers between RP2350 U16 and ST25R3916 U11, silkscreen "NFC\nCUT\nHERE" at (100.25, 120.3)
        (github.com/seedhammer/hardware 9d187f7, mainboard/pcb/mainboard.kicad_pcb line 61416); AP33772S reaches the
        bus through PCA9306 U9 on the MCU side; confirm on a shipped board and note its version
  - [ ] with the jumpers open: start screen behaviour (expect "Scan error" about every 2 s from the poller error path,
        gui/scan.go:44-47, gui/gui.go:1370-1388); seed entry and engraving still work (page says "keeps working (unverified)", from
        the separate touch bus)
  - [ ] shipped stock unit on v1.4.3: no " (UNLOCKED)"; unit with an owner key in a second valid slot on stock
        v1.4.3: " (UNLOCKED)" shown (the maintainer's own unit has an owner key burned and can serve). The
        troubleshooting advice to replace a board that stays "(UNLOCKED)" depends on this; if factory or early units
        were never locked, rewrite that item
  - [ ] official release on a test board with secure boot on and only a non-SeedHammer key valid: board refuses it
        and stays in upgrade mode, screen dark on the machine's own power supply (RP2350 boot ROM behaviour; test unit
        only)
  - [ ] "command: lock-boot" over NFC on a locked unit: restart only, mark unchanged (test unit only)
  - [ ] reproducible build: nix build of tag v1.4.3, copy-signature from the official UF2, SHA-256 equal
  - [ ] NFC Tools Read on the start screen shows an empty tag (iPhone and Android)
  - [ ] physical tags: an NTAG (ISO 14443A Type 2) and an ISO 15693 (Type 5) tag carrying a Text record, held to the
        start screen with no phone near; does the machine read them (SYNTHESIS F12; owner capability-sheet#tags, the
        page links there)
  - [ ] an 18-word seed with a valid checksum sent as NFC Text on v1.4.3: reaches "Engrave Seed" and engraves
        (bip39.Parse accepts any multiple of 3 up to 24); also 15 and 21 words
  - [ ] optional acoustic test: record two 12-word seed jobs with different words and compare per-letter timing and
        total length (the page claims timing only; listening demonstrates but does not prove constant time)
  - [ ] NFC Tools writes in airplane mode on iOS and Android (SYNTHESIS G bench check 1)
  - [ ] shipped board parts match the published design; no radio part besides ST25R3916 and its antenna
  - [ ] codex32 share sent as NFC text on v1.4.3 (SYNTHESIS F19); owner of the statement is capability-sheet#shares (this page now links there instead of its own Check)
  - [ ] board removal steps and connector count (the chat says three plugs; the PCB has the LCD FPC, two motor XH-4,
        the solenoid XH-2 and two 3-pin wafers, so the page gives no number)
  - [ ] screen saver covers "Engrave Seed" after 3 minutes (gui/gui.go:2351 idleTimeout)
  - [ ] on page (#leaks) as unverified: does a release build enumerate a USB serial device when it boots from a 20 V PD
        computer port (flake.nix release tinygo-flags pass no -serial; TinyGo's rp2350 default is usb); release log
        lines carry no seed words or descriptors (gui/scan.go:45, gui/gui.go:1372, :1418, :1423 logs the unknown
        command text, platform_sh2.go:672)
  - [ ] reviewer item, not on page: LockBoot sets only CRIT1 bit 0 (otp.go:93-95); is SWD debug still open on a
        locked unit, and are the boot-key OTP rows page-locked against writes from BOOTSEL
notes:
  - Edit pass 2026-10-10 (manuals/EDIT_BRIEF.md): every body Check: became an "(unverified)" mark; each already
    had a bench item above. Left the body: the intro's sourcing sentences (written for cautious owners and for
    reviewers; each answer said what it rests on) and the summary's "Rests on" column: power-off, stolen machine,
    sound, creates seeds and own firmware = firmware source + company statement; send what I type = firmware
    source + hardware files; descriptor secret = how descriptors work.
  - Verify fix 2026-10-10: company statements (harvest HARVEST.md security-model, Q09 Q10 Q13 Q58, SYNTHESIS C)
    restored in the body without attribution: recorder anywhere, hard to hide and to send data from away from the
    board (#storage); no seed generation by design against random-number bugs, small attack surface (#summary);
    destroying boards possible but not recommended, cabin luggage (#lending); account posing as SeedHammer (warning,
    from the old scam row); owner key takes development work (#own-key). Still only here: the engraving head's
    signals carry no seed data, only the stepper motors do, and listening to the rhythm demonstrates constant time
    without proving it. Also dropped: no SECURITY.md in the firmware repository (evidence above); "the manual has
    no step-by-step guide" for an owner key; the README link on the Build row (README wording hedged, see above).
  - Sending a seed straight from a signer over NFC (a company answer in the chat) conflicts with the house rule that
    seeds are typed on the machine. Harmonized 2026-10-10: seed-entry now carries the warning (research/BRIEF.md
    direct signer tap bullet) and #seeds here says "from a phone or a signer" with a link; still revisit after the
    descriptor-coldcard bench check.
  - Q49 "a laptop finds the rest in minutes" is not repeated; the page gives the arithmetic only.
  - Q45 "three plugs" not repeated (see bench check). Dice-roll entry and other announced plans are not mentioned.
sources: manuals/REVIEW-wave1.md sections 2 to 4 (harmonized, see manuals/HARMONIZE-wave1.md); research/BRIEF.md; research/device-screen-map.md sections 1.1, 1.2, 1.3, 1.4, 1.6, 1.7, 3, 5 (item 5), 6;
  research/nfc-tools-transfer.md section 0 (Read-back, Physical tags) and seed note; harvest/HARVEST.md
  security-model items (grinder, recorder anywhere, driver OTP, engraving head); research/desktop-wallets.md 2.2 and 3; firmware github.com/seedhammer/seedhammer v1.4.3 (ea4b65b) README.md,
  flake.nix, cmd/controller/platform_sh2.go, driver/otp/otp.go, driver/st25r3916/st25r3916.go, gui/gui.go, gui/scan.go,
  nfc/type4/type4.go, nfc/poller/poller.go, backup/backup.go, engrave/engrave.go, bip39/bip39.go, bip39/wordlist.go, cmd/picosign/main.go;
  hardware github.com/seedhammer/hardware 9d187f7 mainboard/pcb/mainboard.kicad_pcb; harvest Q09 Q10 Q13 Q31 Q44 Q45
  Q46 Q47 Q48 Q49 (scam item from Q58); SYNTHESIS C rows 2025-06-20, 2025-08-16, 2026-01-08, 2026-04-23, 2026-07-26,
  2026-08-03, 2026-08-13, 2026-08-22; SYNTHESIS F12, F13, F14, F19
-->
