Bitcoin hardware wallet based on the USB OpenCryptoToken (or similar projects). To get an acceptable level of security, though, at least a display should be fitted on the token (for user authentication).

You can discuss this proposal on the forum


Upon first boot, a new empty wallet and corresponding keys are generated. The private key never leaves the token.

When connected to a USB host, a serial connection is initiated. The possible interactions between host and token are limited to:

  • Host → Token
    • getbalance: Querying the available balance on the token
    • getaddress: Querying for an address that can be used to send a transaction to the token
    • sendtransaction [amount] [address]: Ask the token to send [amount] to [address]
    • auth [input]: Reply to a getauth query, including the [input] entered by the user
    • rx: Give the token a message that was broadcasted on the network
  • Token → Host
    • balance [amount]: Reply to a getbalance query
    • address [address]: Reply to a getaddress query
    • transaction [transaction data]: Reply to a sendtransaction query
    • getauth [msg]: Ask the host to display [msg] and prompt for input from the user
    • tx: Broadcast a message on the network

Example transaction

  1. The token is plugged in the host.
  2. The host sends a sendtransaction [amount] [address] query to the token.
  3. The token performs authentication of the user (see below).
  4. If authentication is successful a transaction sending [amount] to [address] is created and returned to the host in a transaction [transaction data] reply.

User authentication might work like this:

  • Suppose that the user and token know a common PIN code P (M decimal digits long).
  • To authenticate the user the token generates a random number R made up of M decimal digits.
  • The token displays R on its screen and sends a getauth request to the host
  • The user reads R from the token display, mentally performs a simple transform of the authentication code (e.g. digit-wise modulo 10 addition of R and P) and then types the result (T) on the host.
  • The host sends an auth reply to the token, containing the input from the user
  • The token performs the same filtering operation done by the user and compares its result with the contents of the auth reply. If they are equal, authentication was successful. If they differ, authentication fails. Each time an authentication fails, the minimum amount of time between two authentication attempts increases (this amount is reset to the default upon succesful authentication).

As an example of the above consider the following:

  • P = 1921
  • R = Random() = 0432
  • T = Transform( 1921, 0432 ) = (1+0) mod 10, (9+4) mod 10, (2+3) mod 10, (1+2) mod 10 = 1353

The rationale behind this transform step is to never have to type the PIN code on the (potentially untrusted) host.


Since the token must be able to work when plugged in, it should have the ability to receive signed messages from the network.

To do this, a token can be paired with one (or more) trusted nodes. During the pairing procedure, the token and the node exchange their public keys.

When the token is plugged into any node connected to the network, it asks the node to fetch and pass to token any message signed with the token's public key. The token checks the signature of each incoming message and, if it matches the public key of one of the trusted nodes, it accepts the message.

The messages might contain important transactions the token should know about (e.g. transactions that are supposed to be received by the token) or other information (revocation lists, remote commands, etc.).

This is necessary because the token has no control whatsoever on the network stack, so the host could theorically tamper all packets in transit. The only way around this problem is pairing the token to a trusted node and exchange only signed (and optionally encrypted) messages.


Display: Good Display YM0802D (8x2) or YM12832H-1 (128x32)

1985-2019 CAFxX