Skip to content

dsisigner/dsisigner

Repository files navigation

dsisigner

dsisigner is a Nintendo DSi homebrew Bitcoin signing device. It is stateless, air-gapped, and communicates only through QR codes for PSBT signing workflows.

It is designed to look like an ordinary old handheld game. The root ROM is currently named breakout.nds, the title is Breakout, and the app boots into a playable Breakout-style game before signer mode is entered.

The goal is not to make a general-purpose hardware wallet. The goal is a verifiable, QR-only Bitcoin signer whose physical presence is less obvious in social and physical situations where a dedicated signing device can create risk.

Hardware Preview

The photos below show dsisigner running on real Nintendo DSi hardware. The QR data shown is dummy test data.

Breakout decoy game running on a Nintendo DSi dsisigner seed entry menu on a Nintendo DSi dsisigner signed PSBT QR display on a Nintendo DSi
Breakout decoy Signer mode QR-only output

Status

This is experimental pre-release software. Treat it as code for review and controlled testing unless you have independently reviewed the source, build process, and exact ROM artifact you plan to run.

  • It handles Bitcoin seed material, passphrases, private keys, PSBTs, and signatures. Mistakes can lose funds.
  • It is stateless by design. Seeds, passphrases, private keys, and PSBT signing secrets must not be written to SD, NAND, logs, screenshots, or settings.
  • Communication is QR-only. WiFi, Bluetooth, sockets, HTTP clients, and other network paths are out of scope.
  • DEBUG builds can write SD debug logs. Do not use DEBUG builds for production signing.
  • Test with small amounts first, and verify every release artifact before use.

Do not trust the maintainer, a binary download, or a GitHub account by default. Trust should come from source review, local build checks, release signatures when available, and independent verification.

Why Nintendo DSi?

  • Common second-hand hardware that does not obviously signal Bitcoin custody.
  • Built-in cameras for QR scanning.
  • Two screens and a touch panel for transaction review and input.
  • Memory Pit boot flow works without permanent console modification.
  • BlocksDS makes native DSi homebrew development practical.
  • No need for a custom hardware supply chain.

For the full background, threat model, and hardware rationale, see docs/project-context.md.

What It Does

Implemented or code-supported features include:

  • BIP-39 mnemonic entry, generation, validation, and passphrase support
  • SeedQR, CompactSeedQR, and plaintext mnemonic QR input
  • Dice, camera entropy, coin flip, and final-word seed creation helpers
  • BIP-32 derivation with BIP-44, BIP-49, BIP-84, BIP-86, and BIP-48 account support
  • xpub, descriptor, account, and address QR display
  • Address verification from scanned addresses
  • PSBT v0 parsing, review, validation, and signing
  • P2WPKH, P2WSH multisig, and P2TR key-path signing
  • Change output verification with optional wallet descriptor import
  • BC-UR, BBQR, Specter QR, and crypto-account decode paths
  • Panic wipe and inactivity timeout wipe

Not supported:

  • P2TR script-path signing
  • MuSig or other multi-party signing protocols
  • Networking
  • Permanent secret storage
  • DS-mode fallback

Boot Flow

On real hardware, dsisigner is normally launched through the DSi Camera app using the Memory Pit exploit. The ROM then starts as Breakout.

Signer mode is entered only from the Breakout Game Over or All Clear screen by pressing this command one button at a time:

Up, Up, Down, Down, Left, Right, Left, Right, B, A, Start

See docs/boot-guide.md for the full real-hardware setup.

Development Build

Prerequisites:

  • Docker with Docker Compose V2
  • Git submodules initialized
git submodule update --init --recursive
docker compose run --rm build make DEBUG=1
./tools/build.sh test

docker compose run --rm build make DEBUG=1 is the normal development build. The helper script ./tools/build.sh build does not add DEBUG=1.

Release-Style Package

For a non-debug package:

./tools/build.sh clean
./tools/build.sh setup-pit nofacebook   # or: facebook
./tools/build.sh package

The package output is:

output/sd/
|-- boot.nds
`-- private/
    `-- ds/
        `-- app/
            `-- 484E494A/
                `-- pit.bin

If you previously built with DEBUG=1, clean first or use a fresh checkout so stale debug objects cannot be reused in a release-style package.

Verification

Signed release images and artifact attestations are planned but not yet available. Until they exist, SHA256 values are integrity checks, not maintainer identity proof.

Contributing and Security

Security reports should use GitHub private vulnerability reporting. Do not include mnemonics, passphrases, xprvs, private keys, or sensitive PSBTs in public issues.

Acknowledgements

dsisigner is inspired by SeedSigner's stateless, air-gapped signing model and by the broader Bitcoin self-custody and homebrew communities. Development also used assistance from OpenAI Codex (GPT-5.5); released code and project decisions remain the maintainers' responsibility.