mirror of
https://github.com/trezor/trezor-firmware.git
synced 2024-11-30 03:18:20 +00:00
322 lines
15 KiB
Markdown
322 lines
15 KiB
Markdown
|
# Message Workflows
|
||
|
|
||
|
> This page was migrated from the Trezor Wiki. The content here may contain
|
||
|
outdated information.
|
||
|
|
||
|
In general, the API implements a simple request-response protocol. The
|
||
|
computer sends a request to the device and the device sends back a
|
||
|
response. The response can be a simple Success message, a Failure
|
||
|
message, or an answer to the request giving the requested data.
|
||
|
Moreover, the response can be a request from the device to the computer,
|
||
|
e.g., for entering the PIN, the
|
||
|
passphrase or giving some other information. In
|
||
|
that case the computer should send the corresponding Ack packet to
|
||
|
answer the request and wait for another response.
|
||
|
|
||
|
## Initialize/Features
|
||
|
|
||
|
As first message, the computer should send an empty Initialize packet
|
||
|
and expect a Features packet as response. The Initialize packet will
|
||
|
cause the device to stop what it is currently doing and should work at
|
||
|
any time. Thus, it can also be used to recover from previous errors.
|
||
|
|
||
|
## Button meta-workflow
|
||
|
|
||
|
If the device requires the user to press a button, it will reply with a
|
||
|
ButtonRequest to the computer. The computer should immediately send a
|
||
|
ButtonAck acknowledging the request. But it should also display an
|
||
|
indication to the user that it should follow the instruction on the
|
||
|
device. The field code in the ButtonRequest message explains what type
|
||
|
of request the user should acknowledge with a button.
|
||
|
|
||
|
If the user never presses the button, there will never be a reply to the
|
||
|
ButtonAck message. The computer can use Cancel to abort the current
|
||
|
operation. This should result in a Failure response.
|
||
|
|
||
|
## PinMatrix meta-workflow
|
||
|
|
||
|
If the device requires the user to unlock the device with a PIN, it will
|
||
|
reply with a PinMatrixRequest. The field type gives some explanation
|
||
|
what PIN is required (current pin, new pin, or confirmation of new pin).
|
||
|
The computer should display an empty pin matrix and let the user enter
|
||
|
the pin. The computer should encode the PIN as if the numbers are
|
||
|
ordered like they are on the numeric keypad. The encoded PIN should then
|
||
|
be send with a PinMatrixAck message.
|
||
|
|
||
|
## Passphrase meta-workflow
|
||
|
|
||
|
If the device requires the user to enter the passphrase, it will reply
|
||
|
with a PassphraseRequest. The computer should ask the user for the
|
||
|
passphrase and send it in clear text with a PassphraseAck message.
|
||
|
|
||
|
## GetAddress
|
||
|
|
||
|
The message GetAddress (send from the computer to the device) serves two
|
||
|
purposes. It can be used to get a valid address or to display the
|
||
|
address on the device. The field address_n gives the bip-32
|
||
|
path to the
|
||
|
address. The field coin_name should be set to some
|
||
|
supported coin (see the Feature message for a list of supported coins).
|
||
|
For multisig addresses multisig must be filled out with all
|
||
|
participating master public keys and their bip-32 path. The script_type
|
||
|
field has the same meaning as for transaction inputs when signing:
|
||
|
|
||
|
- SPENDADDRESS (standard P2PKH address)
|
||
|
- SPENDMULTISIG (P2SH multisig address)
|
||
|
- SPENDWITNESS (native segwit P2WPKH or
|
||
|
multisig p2wsh address)
|
||
|
- SPENDP2SHWITNESS (segwit encapsulated in a p2sh
|
||
|
address)
|
||
|
|
||
|
If show_display is set the address is displayed to the user. In any
|
||
|
case, it is also sent to the computer with an Address response.
|
||
|
|
||
|
## GetPublicKey
|
||
|
|
||
|
The message GetPublicKey can be used to get a bip-32 master public key
|
||
|
from the trezor or to display it to the user. The field address_n gives
|
||
|
the bip-32 path to the master key. The field ecdsa_curve_name can be
|
||
|
used to get Ed25519 or
|
||
|
NIST256P1 public keys.
|
||
|
|
||
|
## SignTx
|
||
|
|
||
|
> The following may contain imprecise/obsolete information. Refer to
|
||
|
[Bitcoin signing flow](communication/bitcoin-signing.md) for more relevant
|
||
|
information.
|
||
|
|
||
|
Signing a transaction is a little bit complicated. The reason is that
|
||
|
transactions can be several hundred kilobytes in size, but Trezor has
|
||
|
only 64 kilobytes memory. So it is the task of the computer to split the
|
||
|
transactions in small pieces and send only those pieces that Trezor
|
||
|
requested. The general workflow is given below
|
||
|
|
||
|
![](Developers_guide_signtx_workflow.png)
|
||
|
|
||
|
The computer starts the transaction signing process by sending a SignTx
|
||
|
message. From then on, the device drives all further communications by
|
||
|
sending requests to the computer until it finally sends a TxRequest with
|
||
|
request set to TXFINISHED. This final message should not be acknowledged
|
||
|
by the computer.
|
||
|
|
||
|
The SignTx message contains only the meta data of the transaction that
|
||
|
should be signed, i.e., the number of inputs and outputs, the coin name,
|
||
|
the version number, and lock_time (only for pre-signed time locked
|
||
|
transactions). If the device was not unlocked before, it will respond
|
||
|
with the usual PinMatrixRequest and PasswordRequest messages to
|
||
|
authenticate the user. See the corresponding sections above. It may also
|
||
|
send a ButtonRequest at any time to indicate that the user should
|
||
|
confirm a transaction output or the total fee.
|
||
|
|
||
|
Then the main process begins and Trezor will respond with TxRequest
|
||
|
messages, which should be answered by TxAck message. A TxRequest message
|
||
|
has up to three parts.
|
||
|
|
||
|
1. Parts of the signed transactions.
|
||
|
2. A signature for one of the inputs.
|
||
|
3. A request for one piece of the new transaction or a previous
|
||
|
transaction.
|
||
|
|
||
|
If the field serialized.serialized_tx is set, it contains a chunk of the
|
||
|
signed transaction in serialized format. The chunks are returned in the
|
||
|
right order and just concatenating all returned chunks will result in
|
||
|
the signed transaction.
|
||
|
|
||
|
If the field serialized.signature is set, it contains a signature for
|
||
|
one of the inputs. The signatures are returned in the same order as they
|
||
|
appear in the serialized transactions. I.e., the non-segwit signatures
|
||
|
come before the segwit signatures, since the latter are part of the
|
||
|
witness, which is serialized at the end. Apart from that, the signatures
|
||
|
are returned in the order the inputs appear in the transaction. The
|
||
|
signatures are not really needed, as they are already in the serialized
|
||
|
transaction. They can be useful for combining multisig signatures
|
||
|
without having to parse the transactions again.
|
||
|
|
||
|
If the field request equals TXFINISHED, this message contained the last
|
||
|
chunk of the transaction. The signing is finished and the computer must
|
||
|
not reply to this packet. In any other case, the device requested some
|
||
|
piece of some transaction, which is specified by request and details.
|
||
|
This request must be answered by a TxAck package containing the
|
||
|
requested piece of data.
|
||
|
|
||
|
If the field details.tx_hash is not set, some piece of the transaction
|
||
|
that should be signed is requested. Otherwise, this field contains the
|
||
|
hash of some input transaction and some piece of that transaction is
|
||
|
requested.
|
||
|
|
||
|
For request = TXMETA, the fields tx.version, tx.lock_time, tx.inputs_cnt
|
||
|
(number of inputs), and tx.outputs_cnt must be filled. For ZCash
|
||
|
transactions also tx.extra_data_len must be given. This will only be
|
||
|
requested for input transactions (for the signed transaction it was
|
||
|
given in the SignTx call).
|
||
|
|
||
|
For request = TXINPUT, the field details.request_index contains the
|
||
|
number of the input requested (starting with zero). The reply must fill
|
||
|
the structure tx.inputs\[0\] (there must be exactly one input in the
|
||
|
reply). Which fields must be set depends on whether details.tx_hash is
|
||
|
set (an input of some previous transaction is requested, that is spend
|
||
|
in the new transaction), or whether an input of the new transaction is
|
||
|
requested. In both cases prev_hash, prev_index and sequence must be set.
|
||
|
For a previous transaction, the script_sig must be set to the raw
|
||
|
signature data.
|
||
|
|
||
|
But if details.tx_hash is unset, the data must instead describe the
|
||
|
private key that should be used to sign the input. This is specified by
|
||
|
address_n (the bip-32 path to the private key), script_type and
|
||
|
multisig. The field multisig is only given for multisig transactions and
|
||
|
contains the master public keys and the derivation paths for all
|
||
|
signers. The field script_type can be
|
||
|
|
||
|
- SPENDADDRESS (standard p2pkh address)
|
||
|
- SPENDMULTISIG (p2sh multisig address)
|
||
|
- SPENDWITNESS (native segwit p2wpkh or multisig p2wsh address)
|
||
|
- SPENDP2SHWITNESS (segwit encapsulated in a p2sh address)
|
||
|
|
||
|
Note, that for segwit script_type does not distinguish between multisig
|
||
|
or p2wpkh addresses. Instead the presence of the multisig decides this.
|
||
|
For segwit inputs also the amount field must be set to the amount of
|
||
|
satoshis in the input transaction.
|
||
|
|
||
|
For request = TXOUTPUT, the field details.request_index contains the
|
||
|
number of the output requested (starting with zero). If details.tx_hash
|
||
|
is set, this is an output of a previous transaction and the
|
||
|
tx.bin_outputs\[0\] field must be filled in the TxAck reply. Otherwise,
|
||
|
the tx.outputs\[0\] field must be filled. For change outputs, the field
|
||
|
address_n must be filled and address must be omitted. If the change is
|
||
|
multisig, the multisig must be filled and it must use the same extended
|
||
|
public keys as all inputs. For a change address, the script_type should
|
||
|
be PAYTOADDRESS, PAYTOMULTISIG, PAYTOWITNESS or PAYTOP2SHWITNESS
|
||
|
matching the corresponding cases SPEND... for inputs. For
|
||
|
OP_RETURN outputs, set script_type =
|
||
|
PAYTOOPRETURN and set the op_return_data field. Otherwise address should
|
||
|
be set to a base58 encoded address and
|
||
|
script_type to PAYTOADDRESS. Older firmware required script_type =
|
||
|
PAYTOSCRIPTHASH for p2sh addresses, though (and newer firmware still
|
||
|
support this).
|
||
|
|
||
|
## SignMessage/VerifyMessage
|
||
|
|
||
|
### Sign message
|
||
|
|
||
|
Signing messages can be used to prove ownership of a specific address.
|
||
|
To sign message with Trezor device, it is needed to send the message
|
||
|
which the user wants to sign and also specify BIP-32 path which to use
|
||
|
for message signing. There are also two optional arguments: to specify
|
||
|
coin (Bitcoin is default, for more information about available coins
|
||
|
check this GitHub
|
||
|
[page](https://github.com/trezor/trezor-firmware/blob/master/core/src/apps/common/coininfo.py))
|
||
|
and specify script type (0 = SPENDADDRESS/standard P2PKH address, 1 =
|
||
|
SPENDMULTISIG/P2SH multisig address, 2 = EXTERNAL/reserved for external
|
||
|
inputs (coinjoin), 3 = SPENDWITNESS/native SegWit, 4 =
|
||
|
SPENDP2SHWITNESS/SegWit over P2SH (backward compatible))
|
||
|
|
||
|
### Verify message
|
||
|
|
||
|
Verify message asks device to verify if the signature is a signed
|
||
|
message with the given address. The arguments of the message are
|
||
|
signature, message being verified, address and coin which should be used
|
||
|
for verifying.
|
||
|
|
||
|
## CipherKeyValue
|
||
|
|
||
|
Cipher key value provides symmetric encryption in the Trezor device,
|
||
|
where the key doesn't exit the device, and where the user might be
|
||
|
forced to confirm the encryption/decryption on the display. The data
|
||
|
sent to the device are The following data are BIP-32 derivation path,
|
||
|
key (that is being shown on the device), value, encrypt/decrypt
|
||
|
direction, should user confirm on encrypt?, should user confirm on
|
||
|
decrypt? and optional IV. Value is what is actually being encrypted. The
|
||
|
key for the encryption is constructed from the private key on the BIP
|
||
|
address, the key displayed on the device, and the two informations about
|
||
|
whether to ask for confirmation. It is constructed in such a way, that
|
||
|
different path, key or the confirm information will get a different
|
||
|
encryption key and IV. So, you cannot "skip" the confirmation by using
|
||
|
different input. IV can be either manually set, or it is computed
|
||
|
together with the key. The value must be divisible into 16-byte blocks.
|
||
|
The application has to pad the blocks itself and ensure safety; for
|
||
|
example, by using PKCS7. See
|
||
|
<https://github.com/satoshilabs/slips/blob/master/slip-0011.md>.
|
||
|
|
||
|
## ResetDevice
|
||
|
|
||
|
Reset device message performs Trezor device
|
||
|
setup and generates new wallet with new recovery
|
||
|
seed. The device must be in unitialized
|
||
|
state, the firmware is already installed but it has not been initialized
|
||
|
yet. If it is initialized and the user wants to perform a reset device,
|
||
|
the device must be wiped first. If the Trezor is prepared for its
|
||
|
initialization the screen is showing "Go to trezor.io". The reset device
|
||
|
can be done in Trezor Wallet interface (https://trezor.io/start) and
|
||
|
also with Python trezorctl command. After sending
|
||
|
message to the device, device warn us to never make a digital copy of
|
||
|
your recovery seed and never upload it online, this message has to be
|
||
|
confirmed by pressing on "I understand" on the device. After confirmed,
|
||
|
the device produces internal entropy which is random of 32 bytes,
|
||
|
requests external entropy which is produced in computer and computes
|
||
|
mnemonic (recovery seed) using internal, external entropy and given
|
||
|
strength (12, 18 or 24 words). Trezor Wallet
|
||
|
interface doesn't provide option to choose how many words there should
|
||
|
be in the generated mnemonic (recovery seed). It is hardcoded to 12
|
||
|
words for Trezor Model T but if done with python's trezorctl command it
|
||
|
can be chosen (for initialization with python's trezorctl command, 24
|
||
|
words mnemonic is default). After showing mnemonic on the Trezor device,
|
||
|
Trezor Model T requires 2 random words to
|
||
|
be entered to the device to confirm the user has written down the
|
||
|
mnemonic properly. If there are errors in entered words, the device
|
||
|
shows the recovery seed again. If the backup check is successful, the
|
||
|
setup is finished. If the Trezor Wallet interface is used, user is asked
|
||
|
to set the label and pin (setting up the pin can be skipped) for the
|
||
|
wallet, this is optional when using python trezorctl command.
|
||
|
|
||
|
## RecoveryDevice
|
||
|
|
||
|
Recovery device lets user to recover BIP39 seed into
|
||
|
empty Trezor device. First the device asks user for the number of words
|
||
|
in recovered seed, the words are typed in one by one - on the device
|
||
|
screen when using Trezor model T, with Trezor One the user can decide to
|
||
|
do the advanced recovery (with entering seed using matrix similarly to
|
||
|
entering PIN) or standard recovery (with entering the seed to the host
|
||
|
computer one by one in random order). The process continues with
|
||
|
optional check of the seed validity and optional setting up the PIN,
|
||
|
which has to be confirmed. Finally the recovered wallet is saved into
|
||
|
device storage. The same process is used with the dry run recovery, the
|
||
|
differences are that this process can be done only with already
|
||
|
initialized deviice and that the mnemonic is not saved into the device
|
||
|
but it is only compared to the mnemonic already loaded into the device
|
||
|
with the successful result (The seed is valid and matches the one in the
|
||
|
device) or unsuccessful result(The seed is valid but does not match the
|
||
|
one in the device).
|
||
|
|
||
|
## LoadDevice
|
||
|
|
||
|
Load device lets user to load the device with the specific recovery
|
||
|
seed. This command is the subset of the recovery device and it can not
|
||
|
be done with Trezor Wallet interface, only with python command
|
||
|
trezorctl. This message can be used only if the device is not
|
||
|
initialized.
|
||
|
|
||
|
## WipeDevice
|
||
|
|
||
|
Wipe device lets user wipe the device. It is possible to wipe only
|
||
|
user's wallet or erase all the data from the Trezor device including
|
||
|
installed firmware. Wiping device in Trezor Wallet interface wipes only
|
||
|
user's wallet. It is also possible to wipe the firmware with python
|
||
|
trezorctl command, Trezor device must be in bootloader mode.
|
||
|
|
||
|
## ApplySettings
|
||
|
|
||
|
Apply settings lets user change settings on the Trezor device, mainly
|
||
|
its homescreen, label and passphrase settings. Passphrase can be set to
|
||
|
enabled or disabled. Furthermore it can be set that passphrase is
|
||
|
entered solely on device or solely on host, by default the device always
|
||
|
ask where the user wants to enter the passphrase. All these settings
|
||
|
have to be confirmed by user on the device.
|
||
|
|
||
|
## ChangePin
|
||
|
|
||
|
This message lets user change, remove or set new PIN. First the user is
|
||
|
asked to enter old PIN if it was set before. The user is then asked to
|
||
|
enter new PIN and re-enter it to confirm match. It is also possible to
|
||
|
not enter new PIN, so the Change PIN message will just remove the old
|
||
|
one. The action has to be confirmed by user.
|