Skip to content

feat: expose custom transport API via from_transport()#126

Open
frijolo wants to merge 2 commits into
BitBoxSwiss:masterfrom
frijolo:custom-transport
Open

feat: expose custom transport API via from_transport()#126
frijolo wants to merge 2 commits into
BitBoxSwiss:masterfrom
frijolo:custom-transport

Conversation

@frijolo

@frijolo frijolo commented Jul 10, 2026

Copy link
Copy Markdown

Summary

Adds a public BitBox::from_transport() constructor that accepts any communication::ReadWrite implementation and performs the U2F-HID framing internally. This lets callers delegate raw USB I/O to platform-specific code, instead of relying on hidapi.

Two small changes:

  • Make the communication module public, exposing the ReadWrite trait and Error.
  • Remove the feature gate on FIRMWARE_CMD so from_transport (available without the usb/wasm/simulator features) can perform the framing.

Motivation

We want to drive a BitBox02 from Android, where USB access must go through the Java UsbManager API and hidapi is not available. The existing constructors (from_hid_device, usb::get_any_bitbox02) all assume hidapi, so there is currently no way to connect on such platforms.

With from_transport(), a caller implements only the ReadWrite trait over their platform's transport (on Android, a channel bridged to the Java USB stack) and gets a fully functional BitBox — the U2F-HID framing is handled by the library, exactly as it is for the USB path. Desktop/hidapi callers are unaffected.

This mirrors how the official BitBoxApp already drives the device on Android: its GoViewModel.java opens the device through UsbManager/UsbDeviceConnection, performs the bulkTransfer() I/O in Java, and hands a ReadWriteCloser to the Go backend (no hidapi on Android). from_transport() is simply the Rust/bitbox-api equivalent of that pattern.

What changed

  • src/lib.rs: new pub async fn from_transport(transport: Box<dyn communication::ReadWrite>, noise_config: Box<dyn NoiseConfig>) -> Result<BitBox<R>, Error>; mod communicationpub mod communication.
  • src/communication.rs: FIRMWARE_CMD is no longer gated behind usb/wasm/simulator, since from_transport needs it without those features.

No existing API changes; this is purely additive.

Testing

  • Builds with and without the usb feature.
  • Downstream: an Android app connects to and signs with a physical BitBox02 through a channel-based ReadWrite transport built on from_transport() — pairing, xpub export, wallet/policy registration, and PSBT signing (singlesig + multisig) all verified on-device.

@frijolo frijolo closed this Jul 10, 2026
Add a public BitBox::from_transport() that accepts any communication::ReadWrite
implementation and performs the U2F-HID framing internally. This lets callers
delegate raw USB I/O to platform-specific code (e.g. Android, where USB access
requires Java APIs unavailable to hidapi) by implementing only the ReadWrite
trait over their transport.

- Make the communication module public to expose the ReadWrite trait and Error.
- Remove the feature gate on FIRMWARE_CMD so from_transport (available without
  the usb/wasm/simulator features) can perform the framing.
@frijolo frijolo reopened this Jul 14, 2026
@frijolo
frijolo force-pushed the custom-transport branch from 5ddf6ee to f2f9922 Compare July 14, 2026 09:25
Comment thread src/lib.rs Outdated
Comment on lines 118 to 122

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could reuse Self::from_transport here and in from_simulator below

Comment thread src/lib.rs Outdated

mod antiklepto;
mod communication;
pub mod communication;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about pub use comminucation::ReadWrite instead, to keep the public API surface smaller?

- from_hid_device and from_simulator now delegate to from_transport()
  instead of duplicating the U2fHidCommunication::from(...) call.
- Keep the communication module private; re-export ReadWrite (and
  Error, which appears in its method signatures and is therefore
  required by any external implementor) from the crate root instead.
@frijolo

frijolo commented Jul 16, 2026

Copy link
Copy Markdown
Author

Applied both suggestions:

  • from_hid_device/from_simulator now reuse from_transport() internally.
  • communication module stays private; re-exporting ReadWrite (and Error,
    which its methods return) from the crate root instead.

Built and verified successfully in our downstream app on both desktop
(Linux) and Android — the latter being what exercises from_transport(),
the core of this PR. Full on-device BitBox02 validation is still
pending on my end (no physical hardware until next week); will follow
up once that's done.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants