Skip to content
wizardsardinePublic

About

[WIP] Bitcoin Hardware Wallet Interface in rust [WIP]

Resources

Stars

25 stars

Watchers

6 watching

Forks

Repository files navigation

BHWI, the Bitcoin Hardware Wallet Interface

BHWI is a sans-IO Bitcoin hardware wallet interface. For each device it implements an interpreter that encodes commands, decodes device responses and routes data to its recipients, while leaving all I/O (transport, async runtime, HTTP) to the caller. That lets one Rust core serve every target platform, from desktop and mobile to the browser (WASM) and other languages through FFI. And because every device sits behind one common interface, applications share a single dependency tree instead of pulling a separate client library (and its transitive dependencies) per hardware wallet. It ships a CLI plus a Python-HWI-compatible hwi binary.

bhwi embedded in a host app

Keeping I/O out of the core matters because driving a hardware wallet is rarely one request/response: registering a Miniscript descriptor before signing, answering a Ledger's Merkle-proof data requests, or routing through a Jade PIN server all take several round trips. Rather than commit every caller to one execution model, BHWI leaves that choice to them: each device is a small state machine that performs no I/O itself, so it fits synchronous, asynchronous, FFI and WASM callers alike. This matters most across an FFI boundary, where the host language often brings its own native I/O stack: a sans-IO core lets that language plug in its own transport directly instead of embedding a Rust runtime. The repository ships bhwi-async for those who want a ready-made rust async layer. See docs/VISION.md for the full rationale behind this design.

Concretely, each device is an Interpreter: the caller calls start, feeds device replies back through exchange until no further Transmit is returned, then end yields the response. Throughout, the caller performs the actual I/O for each Transmit payload the interpreter hands back.

pub trait Interpreter {
    type Command;
    type Transmit;
    type Response;
    type Error;
    fn start(&mut self, command: Self::Command) -> Result<Self::Transmit, Self::Error>;
    fn exchange(&mut self, data: Vec<u8>) -> Result<Option<Self::Transmit>, Self::Error>;
    fn end(self) -> Result<Self::Response, Self::Error>;
}

bhwi-async is one such driver: it pumps the common interpreter (BitBox02, Coldcard, Jade, KeepKey, Ledger, Specter-DIY, and Trezor) over HID, USB serial, TCP, UDP, or the browser and routes each Transmit to the device transport, the Jade PIN server, or a typed host-interaction provider via its Recipient.

Workspace

crate description
bhwi Core sans-IO interpreters and the common command/response model.
bhwi-async async/await HWI trait over the interpreters, with protocol framing.
bhwi-async-transport Native device channels (HID/USB/serial/TCP) and discovery.
bhwi-cli bhwi command-line tool and the hwi parity binary.
bhwi-wasm WebAssembly bindings for browser callers.

Supported devices

Every device implements the full HWI trait: unlock, get_info, get_master_fingerprint, get_extended_pubkey, sign_message, display_address, register_wallet and sign_tx. Three capability gaps remain: backup_device is supported on BitBox02 and Coldcard but not on Jade, KeepKey, Ledger, Specter-DIY, or Trezor; register_wallet is unsupported on KeepKey and Trezor, which verify supported multisig descriptors at display and signing time instead; and get_info is unsupported on Specter-DIY, whose protocol exposes no firmware version. See docs/SPECTER.md for the Specter-DIY setup and limits.

CLI

bhwi is a Unix-friendly command-line tool over bhwi-async:

cargo build -p bhwi-cli

All devices are built by default. Build a subset with the bitbox, coldcard, jade, keepkey, ledger, specter and trezor features:

cargo build -p bhwi-cli --no-default-features --features jade,ledger

The same features exist on bhwi, bhwi-async and bhwi-async-transport, and each forwards to the crate below it. device install-udev-rules is Linux only.

command subcommand purpose
address get get an address from the device
descriptor pubkeys get pubkey descriptors from the device
descriptor keypool get a ranged keypool descriptor from the selected device
descriptor register register a named wallet policy with the selected device
device list list all available devices
device backup start a backup on the selected device
device setup initialize an unseeded device
device wipe erase wallet material from the selected device
device restore restore an unseeded device via its mnemonic flow
device toggle-passphrase toggle mnemonic-passphrase use on the selected device
device prompt-pin ask the selected device to show its PIN keypad
device send-pin send the keypad positions shown on the device screen
device install-udev-rules install udev rules for hardware wallet device access
xpub get get an extended public key at a derivation path
psbt sign sign a PSBT with the selected device
message sign sign a message with the selected device

Shared --fingerprint, --device-type, --device-path, --network, --format, and --passphrase options work before a command group, between the group and action, or after the action. For example:

bhwi message sign --network testnet --fingerprint f5acc2fd \
  --message hello --path "m/44'/1'/0'/0"

Output is chainable by default (no headers). Use --format pretty or --format json where supported; PSBT, address, and xpub output remains plain regardless of format.

HWI parity

bhwi-cli also builds a Python-HWI-compatible hwi binary. A parity suite checks its output against Bitcoin Core HWI for the devices where parity is claimed. See docs/HWI_PARITY.md.

Documentation

License

BHWI is released under the terms of the license in LICENSE. The BitBox02 integration additionally carries BITBOX_LICENSE.

About

[WIP] Bitcoin Hardware Wallet Interface in rust [WIP]

Resources

Stars

25 stars

Watchers

6 watching

Forks

Releases

Packages

Used by

Contributors

Languages