The IOTA application does not preserve any states or information on application shutdown. Deterministic seed generation assures that the same private key is generated for the same input.
The IO between host and the IOTA application is APDU compatible with the following general properties:
- Everything is encoded in Little-Endian without any padding or alignment.
- Strings have a fixed length but can be null-terminated if they are shorter.
- Integer numbers are either encoded as unsigned byte (1 byte), unsigned 32-bit (4 bytes) or signed 64-bit (8 bytes) using two's complement representation.
- Boolean values are encoded in one byte, with
0x00
meaningfalse
and any other value meaningtrue
. - IOTA addresses are always transferred in their 81 character base-27 encoding without checksum information.
The 24 word recovery phrase and the optional passphrase of the Ledger Nano S are used according to BIP39 to derive a 512 bits (= 64 bytes) seed. The 512 bits extended private key (k, c) of the provided BIP32 path is then hashed using Kerl. As Kerl expects multiples of 48 bytes as input, the following 98 bytes are absorbed to derive the the final 243 trit IOTA seed:
k[0:32] + c[0:16] + k[16:32] + c[0:32]
The desired BIP32 path is included in the input of PUBKEY
and TX
so that the correct addresses are used.
Generates an address for the corresponding seed plus the provided index and returns the address.
The execution time of PUBKEY
is about 2s for security level 2.
Field | Type | Content | Range |
---|---|---|---|
CLA | byte (1) | Always 0x7A |
|
INS | byte (1) | 0x02 |
|
P1 | byte (1) | 0x00 : return address0x01 : return and display address |
|
P2 | byte (1) | ignored | |
L | byte (1) | Number of bytes to follow | [0, 255] |
security | byte (1) | set the used security level | [1, 3] |
length | unsigned int32 (4) | number of levels in BIP32 path | [2, 5] |
path[1] | unsigned int32 (4) | first level of BIP32 path | [0, 232-1] |
path[2] | unsigned int32 (4) | second level of BIP32 path | [0, 232-1] |
... | ... | ... | ... |
path[length] | unsigned int32 (4) | last level of BIP32 path | [0, 232-1] |
idx | unsigned int32 (4) | Index of the address | [0, 232-1] |
Field | Type | Content |
---|---|---|
address | 81 char string (81) | Base-27 encoding of public address |
SW1-SW2 | byte (2) | 0x9000 for success |
Sets the next transaction of a bundle. Each transaction must only be transferred once.
The first call of this function for a new bundle must include the security level as well as the BIP32 path that is used for the entire bundle. This is indicated by a P1 value of 0x00
, while all successive transactions only contain the actual transaction data and have a P1 value of 0x80
.
After the last transaction of the bundle has been transferred the Ledger Nano S performs check, to assure the validity of the bundle. A bundle is valid, if all the following conditions are fulfilled:
- The bundle contains at least 2 transactions.
- The transactions are in the following order: output tx (exactly 1), input txs (at least 1 plus meta), change tx (at most 1)
- Meta transactions have to be included and must follow their respective input transaction (similar to a finalized bundle in iota.lib.js)
- The last index is identical for all transactions and corresponds to the index of the last transaction.
- The provided indices must match the addresses.
- The index of the change transaction (if present) must be strictly greater than all the input indices.
- The addresses of all transactions must be pairwise distinct.
- The total values of all transactions sum up to 0.
- The normalized bundle hash does not contain a
M
.
After the last transaction of a valid bundle has been transferred, the bundle information is displayed on the display and the user has to accept or deny the bundle. After a bundle has been set, the state needs to be reset in order to set a new bundle.
Field | Type | Content | Range |
---|---|---|---|
CLA | byte (1) | Always 0x7A |
|
INS | byte (1) | 0x03 |
|
P1 | byte (1) | 0x00 |
|
P2 | byte (1) | ignored | |
L | byte (1) | Number of bytes to follow | [0, 255] |
security | byte (1) | set the used security level | [1, 3] |
length | unsigned int32 (4) | number of levels in BIP32 path | [2, 5] |
path[1] | unsigned int32 (4) | first level of BIP32 path | [0, 232-1] |
path[2] | unsigned int32 (4) | second level of BIP32 path | [0, 232-1] |
... | ... | ... | ... |
path[length] | unsigned int32 (4) | last level of BIP32 path | [0, 232-1] |
address | 81 char string (81) | Base-27 encoding of transaction address | |
address_idx | unsigned int32 (4) | Corresponding index of the address; ignored for non-input transactions |
[0, 232-1] |
value | signed int64 (8) | Transaction value | < 0 for input transactions ≥ 0 otherwise |
obsolete_tag | 27 char string (27) | Base-27 encoding of transaction tag | |
index | unsigned int32 (4) | Index of that transaction in the bundle | [0, 7] |
last_index | unsigned int32 (4) | Last transaction index in the bundle | [1, 7] |
timestamp | unsigned int32 (4) | Timestamp | [0, 232-1] |
Field | Type | Content | Range |
---|---|---|---|
CLA | byte (1) | Always 0x7A |
|
INS | byte (1) | 0x03 |
|
P1 | byte (1) | 0x80 |
|
P2 | byte (1) | ignored | |
L | byte (1) | Number of bytes to follow | [0, 255] |
address | 81 char string (81) | Base-27 encoding of transaction address | |
address_idx | unsigned int32 (4) | Corresponding index of the address; ignored for non-input transactions |
[0, 232-1] |
value | signed int64 (8) | Transaction value | < 0 for input transactions ≥ 0 otherwise |
obsolete_tag | 27 char string (27) | Base-27 encoding of transaction tag | |
index | unsigned int32 (4) | Index of that transaction in the bundle | [0, 7] |
last_index | unsigned int32 (4) | Last transaction index in the bundle | [1, 7] |
timestamp | unsigned int32 (4) | Timestamp | [0, 232-1] |
Field | Type | Content |
---|---|---|
finalized | bool (1) | Whether the bundle was finalized, i.e. the last transaction has been transmitted |
hash | 81 char string (81) | Base-27 encoding of the bundle hash; undefined if bundle was not finalized |
SW1-SW2 | byte (2) | 0x9000 for success |
Queries a single signature fragment (= 243 trytes). In order to transfer the entire signature, the command needs to be called multiple times for the same transaction index.
This command is only executable after a complete valid bundle has been transferred using TX
and the user has accepted this bundle.
Called multiple times for the same index, to query all signature fragments. The index must only be changed after the complete signature of an input has been transmitted.
Field | Type | Content | Range |
---|---|---|---|
CLA | byte (1) | Always 0x7A |
|
INS | byte (1) | 0x04 |
|
P1-P2 | byte (2) | ignored | |
L | byte (1) | Number of bytes to follow | [0, 255] |
transaction_idx | unsigned int32 (4) | Index of the input transaction in the bundle; must be an input transaction |
[0, 7] |
Field | Type | Content |
---|---|---|
signature_fragment | 243 char string (243) | Base-27 encoding of the signature fragment |
fragments_remaining | bool (1) | true if more fragments need to be queried |
SW1-SW2 | byte (2) | 0x9000 for success |
This command returns specific application configuration and can be called in any state. The application version uses Semantic Versioning.
Field | Type | Content | Range |
---|---|---|---|
CLA | byte (1) | Always 0x7A |
|
INS | byte (1) | 0x10 |
|
P1-P2 | byte (2) | ignored | |
L | byte (1) | 0x00 |
Field | Type | Content | Range |
---|---|---|---|
app_version_major | byte (1) | Major version | [0, 255] |
app_version_minor | byte (1) | Minor version | [0, 255] |
app_version_patch | byte (1) | Patch version | [0, 255] |
app_max_bundle_size | byte (1) | Max supported number of transactions in one bundle | [0, 255] |
app_flags | byte (1) | Bit flags for supported features |
Called to reset the current state, e.g. reset current bundle. Must be called after all signatures have been queried before a new bundle can be set.
Field | Type | Content | Range |
---|---|---|---|
CLA | byte (1) | Always 0x7A |
|
INS | byte (1) | 0xFF |
|
P1-P2 | byte (2) | ignored | |
L | byte (1) | 0x00 |
Field | Type | Content |
---|---|---|
SW1-SW2 | byte (2) | 0x9000 for success |
The following codes are returned in the case of an error:
SW1 | SW2 | Description |
---|---|---|
0x90 |
0x00 |
Success |
0x67 |
0x00 |
Incorrect Length - the received data has invalid length for this instruction |
0x6a |
0x80 |
Command Invalid Data - the data is not in the format or within the ranges specified above |
0x6B |
0x00 |
Incorrect P1 or P2 - P1, P2 is invalid for that particular instruction |
0x6C |
0x00 |
Incorrect Length L - the length specified in the header does not match |
0x6D |
0x00 |
Instruction not Supported - invalid INS-code |
0x6E |
0x00 |
CLA not Supported - invalid CLA-code |
0x69 |
0x00 |
Command not Allowed - the application is in an invalid state for the command |
0x69 |
0x82 |
Security Status not Satisfied - the dongle is locked and must be unlocked with a PIN |
0x69 |
0x85 |
Conditions of Use not Satisfied - the transaction was declined by the user |
0x69 |
0xAX |
Invalid Bundle - the provided bundle does not fulfill all the requirements |
0x6F |
0xXX |
Unspecified Internal Error |