Bitcoin application : Common Technical Specifications ===================================================== Ledger Firmware Team Application version 1.3.3 == 1.1.9 - Split specification from common firmware - Add display and segwit options to GET WALLET PUBLIC KEY == 1.2.8 - Add CashAddr option when creating a transaction (Bitcoin Cash) == 1.3.2 - Add GET WALLET PUBLIC KEY tokens == 1.3.3 - Add Overwinter hard fork support (ZCash) - Add Sapling hard fork support (ZCash, Komodo) == 1.4.2 - Add support for signing trusted segwit inputs - Display specific warning when signing legacy (i.e. non-trusted) segwit inputs == About This specification describes the APDU messages interface to communicate with the Bitcoin application. It is based on the HW.1 firmware specification detailed on https://github.com/LedgerHQ/btchip-doc == Wallet usage APDUs === GET WALLET PUBLIC KEY ==== Description This command returns the public key and Base58 encoded address for the given BIP 32 path. The Base58 encoded address can be displayed on the device screen. This call might trigger a user validation (with or without token) if the device has the public key protection setting enabled. The last token approved by the user is saved, re-using it in following calls makes it possible to avoid requesting more validation in a row to the user. ==== Coding 'Command' [width="80%"] |============================================================================================================================== | *CLA* | *INS* | *P1* | *P2* | *Lc* | *Le* | E0 | 40 | 00 : do not display the address 01 : display the address 02 : display a validation token | 00 : return a legacy address 01 : return a P2SH-P2WPKH address 02 : return a Bech32 encoded P2WPKH address | variable | variable |============================================================================================================================== 'Input data' [width="80%"] |============================================================================================================================== | *Description* | *Length* | Number of BIP 32 derivations to perform (max 10) | 1 | First derivation index (big endian) | 4 | ... | 4 | Last derivation index (big endian) | 4 | Optional hexadecimal validation token (big endian) | 4 |============================================================================================================================== 'Output data' [width="80%"] |============================================================================================================================== | *Description* | *Length* | Public Key length | 1 | Uncompressed Public Key | var | Bitcoin address length | 1 | Bitcoin address | var | BIP32 Chain code | 32 |============================================================================================================================== === GET TRUSTED INPUT ==== Description This command is used to extract a Trusted Input (encrypted transaction hash, output index, output amount) from a transaction. The transaction data to be provided should be encoded using bitcoin standard raw transaction encoding. Scripts can be sent over several APDUs. Other individual transaction elements split over different APDUs will be rejected. 64 bits varints are rejected. ==== Coding 'Command' [width="80%"] |============================================================================================================================== | *CLA* | *INS* | *P1* | *P2* | *Lc* | *Le* | E0 | 42 | 00 : first transaction data block 80 : subsequent transaction data block | 00 | var | var |============================================================================================================================== 'Input data (first block)' [width="80%"] |============================================================================================================================== | *Description* | *Length* | Input index to lookup (big endian) | 4 | Transaction data | var |============================================================================================================================== 'Input data (next block)' [width="80%"] |============================================================================================================================== | *Description* | *Length* | Transaction data | var |============================================================================================================================== 'Output data (non last block)' None 'Output data (last block)' [width="80%"] |============================================================================================================================== | *Description* | *Length* | Trusted Input | 56 |============================================================================================================================== === UNTRUSTED HASH TRANSACTION INPUT START ==== Description This command is used to compose an opaque SHA-256 hash for a new transaction. This transaction can be verified by the user on screen. The transaction data to be provided should be encoded using bitcoin standard raw transaction encoded as follows: - A 1 byte flag is added before each input in the transaction - the following flags are valid: * 0x00 if the input is passed as a non Trusted Input (passing the original 36 bytes prevout). Non Trusted Inputs will generate a specific warning on screen as fees cannot be computed in that case. * 0x01 if the input is passed as a Trusted Input, previously computed by the dongle (either from a non-Segragated Witness or from a Segregated Witness input). In this case, each input outpoint is replaced by the Trusted Input length (1 byte) and the Trusted Input data. A Segregated Witness Trusted Input is more secure than its "untrusted" counpterpart (flag 0x02 below) as the prevout amount is included in the Trusted Input and is cryptographically verified for integrity. When using this mode with Segregated Witness inputs, all transaction inputs shall be passed as Trusted Segregated Witness Inputs, and the signature mechanism defined for version 0 witness program in BIP 143 (https://github.com/bitcoin/bips/blob/master/bip-0143.mediawiki) will be used. * 0x02 if the input is passed as a Segregated Witness Input, defined as the concatenation of the original 36 bytes prevout and the original 8 bytes little endian amount associated to this input. This mode does not enforce the integrity of the prevout amount associated to the Segregated Witness Input and will be deprecated in a future revision of the app. For now, a warning screen is displayed on the device, offering users the choice either to abandon or to proceed with the operation. When using this mode, all transaction inputs shall be passed as Segregated Witness Inputs, and the signature mechanism defined for version 0 witness program in BIP 143 (https://github.com/bitcoin/bips/blob/master/bip-0143.mediawiki) will be used. - The input scripts shall be prepared by the host for the transaction signing process as per bitcoin rules : the current input script being signed shall be the previous output script (or the redeeming script when consuming a P2SH output, or the scriptCode when consuming a BIP 143 output), and other input script shall be null. - The encoded transaction data shall be provided up to (and not including) the number of outputs. - Scripts can be sent over several APDUs. Other individual transaction elements split over different APDUs will be rejected. 64 bits varints are rejected. - When using Segregated Witness Inputs or Overwinter/Sapling, the signing mechanism differs slightly : * The transaction shall be processed first with all inputs having a null script length (to be done twice if the dongle has been powercycled to retrieve the authorization code) * Then each input to sign shall be processed as part of a pseudo transaction with a single input and no outputs. - When using Overwinter/Sapling, the UNTRUSTED HASH SIGN command shall be sent with an empty authorization and nExpiryHeight following the first UNTRUSTED HASH TRANSACTION INPUT FINALIZE FULL command. ==== Coding 'Command' [width="80%"] |============================================================================================================================== | *CLA* | *INS* | *P1* | *P2* | *Lc* | *Le* | E0 | 44 | 00 : first transaction data block 80 : subsequent transaction data block | 00 : start signing a new transaction 02 : start signing a new transaction containing Segregated Witness Inputs 03 : start signing a new transaction encoding addresses with CashAddr (Bitcoin Cash) 04 : start signing a new transaction following Overwinter rules (Zcash) 05 : start signing a new transaction following Sapling rules (Zcash, Komodo) 80 : continue signing another input of the current transaction | var | var |============================================================================================================================== 'Input data' [width="80%"] |============================================================================================================================== | *Description* | *Length* | Transaction data | var |============================================================================================================================== 'Output data' None === UNTRUSTED HASH SIGN ==== Description This command is used to sign a given secure hash using a private key (after re-hashing it following the standard Bitcoin signing process) to finalize a transaction input signing process. This command will be rejected if the transaction signing state is not consistent or if a user validation is required and the provided user validation code is not correct. ==== Coding 'Command' [width="80%"] |============================================================================================================================== | *CLA* | *INS* | *P1* | *P2* | *Lc* | *Le* | E0 | 48 | 00 | 00 | var | var |============================================================================================================================== 'Input data' [width="80%"] |============================================================================================================================== | *Description* | *Length* | Number of BIP 32 derivations to perform (max 10) | 1 | First derivation index for the private key to use (big endian) | 4 | ... | 4 | Last derivation index for the private key to use (big endian) | 4 | RFU (0x00) | 1 | Lock Time (big endian) | 4 | SigHashType | 1 | nExpiryHeight (big endian, only present for Overwinter/Sapling) | 4 |============================================================================================================================== 'Output data' [width="80%"] |============================================================================================================================== | *Description* | *Length* | Signed hash, as ASN-1 encoded R & S components. Mask first byte with 0xFE | var | SigHashType | 1 |============================================================================================================================== === UNTRUSTED HASH TRANSACTION INPUT FINALIZE FULL ==== Description This command is used to compose an opaque SHA-256 hash from the transaction outputs. This command is rejected if all inputs advertised at the beginning of the transaction have not been processed first. Only standard output scripts are accepted : * Pay-to-PubkeyHash (OP_DUP OP_HASH160 [pubKeyHash] OP_EQUALVERIFY OP_CHECKSIG) * Pay-to-Script-Hash (OP_HASH160 [script hash] OP_EQUAL) * A single maximum 80 bytes OP_RETURN with a null value * A P2WPKH (00 [20 bytes]) or P2WSH (00 [30 bytes]) version 0 witness program ==== Coding 'Command' [width="80%"] |============================================================================================================================== | *CLA* | *INS* | *P1* | *P2* | *Lc* | *Le* | E0 | 4A | 00 : more input data to be sent 80 : last input data block to be sent FF : BIP 32 path specified for the change address | 00 | var | var |============================================================================================================================== 'Input data (first block, no providing a BIP 32 path)' [width="80%"] |============================================================================================================================== | *Description* | *Length* | Start of output data, containing the number of outputs encoded as a Bitcoin varint | var |============================================================================================================================== 'Input data (providing a BIP 32 path)' [width="80%"] |============================================================================================================================== | *Description* | *Length* | Number of BIP 32 derivations to perform (max 10) | 1 | First derivation index for the private key to use (big endian) | 4 | ... | 4 | Last derivation index for the private key to use (big endian) | 4 |============================================================================================================================== 'Input data (optional next blocks)' [width="80%"] |============================================================================================================================== | *Description* | *Length* | Output data continued | var |============================================================================================================================== 'Output data (providing a BIP 32 path)' None 'Output data (not last block)' [width="80%"] |============================================================================================================================== | *Description* | *Length* | RFU (00) | 1 |============================================================================================================================== 'Output data (last block)' [width="80%"] |============================================================================================================================== | *Description* | *Length* | RFU (00) | 1 | Transaction user validation flag 0x00 : no user validation requested | 1 |============================================================================================================================== === SIGN MESSAGE ==== Description This command is used to sign message using a private key. The signature is performed as follows : - The data to sign is the magic "\x18Bitcoin Signed Message:\n" - followed by the length of the message to sign on 1 byte (if requested) followed by the binary content of the message - The signature is performed on a double SHA-256 hash of the data to sign using the selected private key The signature is returned using the standard ASN-1 encoding. To convert it to the proprietary Bitcoin-QT format, the host has to : - Get the parity of the first byte (sequence) : P - Add 27 to P if the public key is not compressed, otherwise add 31 to P - Return the Base64 encoded version of P || r || s If the low end word of one component of the BIP 32 derivation path includes 0xB11D or 0xB11E the message is immediately signed without confirmation (typically used for BitID). ==== Coding 'Command' [width="80%"] |============================================================================================================================== | *CLA* | *INS* | *P1* | *P2* | *Lc* | *Le* | E0 | 4E | 00 : prepare message 80 : sign message| 01 : when preparing, first part of the message 80 : when preparing, next part of the message | var | var |============================================================================================================================== 'Input data in prepare mode (first block)' [width="80%"] |============================================================================================================================== | *Description* | *Length* | Number of BIP 32 derivations to perform (max 10) | 1 | First derivation index of the private key to use (big endian) | 4 | ... | 4 | Last derivation index of the private key to use (big endian) | 4 | Message length (big endian, coded on 1 byte for legacy calls) | 2 | Message data | var |============================================================================================================================== 'Input data in prepare mode (next blocks)' [width="80%"] |============================================================================================================================== | *Description* | *Length* | Message data | var |============================================================================================================================== 'Input data in sign mode' [width="80%"] |============================================================================================================================== | *Description* | *Length* | User validation code length (or 00 in server mode) | 1 | User validation code | var |============================================================================================================================== 'Output data in prepare mode (not last block)' [width="80%"] |============================================================================================================================== | *Description* | *Length* | RFU (00) | 1 |============================================================================================================================== 'Output data in prepare mode (last block)' [width="80%"] |============================================================================================================================== | *Description* | *Length* | RFU (00) | 1 | Transaction user validation flag 0x00 : no user validation requested | 1 |============================================================================================================================== 'Output data in sign mode' [width="80%"] |============================================================================================================================== | *Description* | *Length* | ASN-1 encoded message signature with Y parity indicated in the first (sequence) byte | variable |============================================================================================================================== == Test and utility APDUs === GET RANDOM ==== Description This command returns random bytes from the dongle hardware random number generator ==== Coding 'Command' [width="80%"] |============================================================================================================================== | *CLA* | *INS* | *P1* | *P2* | *Lc* | *Le* | E0 | C0 | 00 | 00 | 00 | variable |============================================================================================================================== 'Input data' None 'Output data' [width="80%"] |============================================================================================================================== | *Description* | *Length* | Random bytes | variable |============================================================================================================================== 'Availability' This function is always available. === GET FIRMWARE VERSION ==== Description This command returns the firmware version of the dongle and additional features supported ==== Coding 'Command' [width="80%"] |============================================================================================================================== | *CLA* | *INS* | *P1* | *P2* | *Lc* | *Le* | E0 | C4 | 00 | 00 | 00 | 07 |============================================================================================================================== 'Input data' None 'Output data' [width="80%"] |============================================================================================================================== | *Description* | *Length* | Features flag 0x01 : public keys are compressed (otherwise not compressed) 0x02 : implementation running with screen + buttons handled by the Secure Element 0x04 : implementation running with screen + buttons handled externally 0x08 : NFC transport and payment extensions supported 0x10 : BLE transport and low power extensions supported 0x20 : implementation running on a Trusted Execution Environment | 01 | Architecture | 01 | Firmware major version | 01 | Firmware minor version | 01 | Firmware patch version | 01 | Loader ID major version (if applicable) | 01 | Loader ID minor version (if applicable) | 01 |============================================================================================================================== 'Availability' This function is always available. === GET COIN VERSION ==== Description This command returns the name of the current app, its ticker, its P2PKH and P2SH prefixes and its coin family. ==== Coding 'Command' [width="80%"] |============================================================================================================================== | *CLA* | *INS* | *P1* | *P2* | *Lc* | *Le* | E0 | 16 | 00 | 00 | 00 | variable |============================================================================================================================== 'Input data' None 'Output data' [width="80%"] |============================================================================================================================== | *Description* | *Length* | P2PKH prefix | 02 | P2SH prefix | 02 | Coin family | 01 | Length of coin name | 01 | Coin name | variable | Length of coin ticker | 01 | Coin ticker | variable |============================================================================================================================== 'Availability' This function is always available. == Transport protocol === General transport description Ledger APDUs requests and responses are encapsulated using a flexible protocol allowing to fragment large payloads over different underlying transport mechanisms. The common transport header is defined as follows : [width="80%"] |============================================================================================================================== | *Description* | *Length* | Communication channel ID (big endian) | 2 | Command tag | 1 | Packet sequence index (big endian) | 2 | Payload | var |============================================================================================================================== The Communication channel ID allows commands multiplexing over the same physical link. It is not used for the time being, and should be set to 0101 to avoid compatibility issues with implementations ignoring a leading 00 byte. The Command tag describes the message content. Use TAG_APDU (0x05) for standard APDU payloads, or TAG_PING (0x02) for a simple link test. The Packet sequence index describes the current sequence for fragmented payloads. The first fragment index is 0x00. === APDU Command payload encoding APDU Command payloads are encoded as follows : [width="80%"] |============================================================================================================================== | *Description* | *Length* | APDU length (big endian) | 2 | APDU CLA | 1 | APDU INS | 1 | APDU P1 | 1 | APDU P2 | 1 | APDU length | 1 | Optional APDU data | var |============================================================================================================================== APDU payload is encoded according to the APDU case [width="80%"] |======================================================================================= | Case Number | *Lc* | *Le* | Case description | 1 | 0 | 0 | No data in either direction - L is set to 00 | 2 | 0 | !0 | Input Data present, no Output Data - L is set to Lc | 3 | !0 | 0 | Output Data present, no Input Data - L is set to Le | 4 | !0 | !0 | Both Input and Output Data are present - L is set to Lc |======================================================================================= === APDU Response payload encoding APDU Response payloads are encoded as follows : [width="80%"] |============================================================================================================================== | *Description* | *Length* | APDU response length (big endian) | 2 | APDU response data and Status Word | var |============================================================================================================================== === USB mapping Messages are exchanged with the dongle over HID endpoints over interrupt transfers, with each chunk being 64 bytes long. The HID Report ID is ignored. == Status Words The following standard Status Words are returned for all APDUs - some specific Status Words can be used for specific commands and are mentioned in the command description. 'Status Words' [width="80%"] |=============================================================================================== | *SW* | *Description* | 6700 | Incorrect length | 6982 | Security status not satisfied (Bitcoin dongle is locked or invalid access rights) | 6A80 | Invalid data | 6A82 | File not found | 6B00 | Incorrect parameter P1 or P2 | 6Fxx | Technical problem (Internal error, please report) | 9000 | Normal ending of the command |================================================================================================ == Data structures The format of the data structures is provided for interoperability and validation purposes. A typical user will not need to manipulate them directly. === Encoded trusted input An encoded trusted input is stored internally as follow. The signature is the last block of a Triple DES CBC encryption of the previous data by the trusted input encryption key. [width="80%"] |============================================================================================================================== | *Description* | *Length* | Magic version (*32*) | 1 | Flags RFU | 1 | Nonce | 2 | Associated transaction hash | 32 | Index in associated transaction (little endian) | 4 | Associated amount (little endian) | 8 | Signature | 8 |==============================================================================================================================