-
Notifications
You must be signed in to change notification settings - Fork 13
Integration manual
The integration of the application consists of several parts: the development of an application for the device and the protocol of interaction (check this repo) and the integration of the communication library, implementation of the protocol of interaction with the device in the final application.
The source code for the application is contained in this repository. The build and install instructions is here.
At this moment (the application is in development), there are 2 commands: obtaining a public key (also returns a private key and the test message signature for debugging, in production it is necessary to remove) and the signature of the passed message.
Waves uses ED25519 signature with X25519 keys (Montgomery form), but Ledger (like most of integrated cryptography devices) don't support X25519 keys. But there're the libraries with conversion functions from ED25519 keys to X25519 (Curve25519) crypto_sign_ed25519_pk_to_curve25519(curve25519_pk, ed25519_pk)
for public key and
crypto_sign_ed25519_sk_to_curve25519(curve25519_sk, ed25519_skpk)
for private key:
I use the ED25519 keys and the signature inside the Ledger application, then you need to convert the keys from the device to X25519 format using that function on the client-side. Looks like the ED25519 algo from Ledger SDK already install 'sign' bit into the signature from the public key, so no additional conversation for signature are needed (unlike the signature of libsodium).
Service statuses:
SW_OK 0x9000
SW_USER_CANCELLED 0x9100
SW_SIGN_DATA_NOT_MATCH 0x9101
SW_DEPRECATED_SIGN_PROTOCOL 0x9102
SW_INCORRECT_PRECISION_VALUE 0x9103
SW_INCORRECT_TRANSACTION_TYPE_VERSION 0x9104
SW_PROTOBUF_DECODING_FAILED 0x9105
SW_CONDITIONS_NOT_SATISFIED 0x6985
SW_BUFFER_OVERFLOW 0x6990
SW_INCORRECT_P1_P2 0x6A86
SW_INS_NOT_SUPPORTED 0x6D00
SW_CLA_NOT_SUPPORTED 0x6E00
SW_SECURITY_STATUS_NOT_SATISFIED 0x6982
bip32 path bytes are the bytes of 5 int values. Waves bip32 path prefix is 5741564' = 0x80579bfc
, so the bip32 path of first used address on the device is 44'/5741564'/0'/0'/1'
. In bytes this is 0x8000002c80579bfc800000008000000080000001
.
hex message bytes
80 04 01 57 14 8000002c80579bfc800000008000000080000001
80 [command: 1 byte: 04 hex] [ask user confirmation: 1 byte: 01 hex] [chain id: 1 byte: 00 hex] [payload size: 1 byte: 14 hex: 20 bytes] [bip32 path bytes: 20 bytes: ...]
Chain ID for testnet is 'T' and 'W' for mainnet.
If request success:
[public key bytes: 32 bytes] [base58 address bytes: 35 bytes] [service status: 2 bytes: should be 9000 = SW_OK]
or
SW_USER_CANCELLED
(9100) if the user canceled the request
The error code will return in error cause.
SW_CONDITIONS_NOT_SATISFIED
(6985) if some required condition was failed
SW_DEVICE_IS_LOCKED
(6986) if the device is locked
Approved request:
HID => 80040057148000002c80579bfc800000008000000080000001
HID <= 67e0088be66a1995b4b296df863d10389a2e4fd9369224290a134ec1a1aab0613350485a31676e63335a45467079335433655671597171414b45564577536a757433629000
publicKey (base58): 7zV8VPvP2Pz119hj2RcRm6HDz25hkrokYpw6CjRenMYt
address: 3PHZ1gnc3ZEFpy3T3eVqYqqAKEVEwSjut3b
Denied request:
HID => 80040157148000002c80579bfc800000008000000080000001
HID <= 9100
User denied signing request on Ledger Nano S device.
A big message should be chunked by 128 bytes
hex message for the first part
80 02 00 00 7b 8000 002c...
80 02 [not last command message: 1 byte: 00 hex] [unused: 1 byte: 00 hex] [payload size byte: 7b hex: 123 bytes] [bip32 path bytes: 20 bytes: ...] [amount decimals: 1 byte] [fee decimals: 1 byte] [data type: 1 byte] [data version: 1 byte] [tx chunk bytes: 98 bytes]
hex message for next parts
80 02 [not last command message: 1 byte: 00 hex] [unused: 1 byte: 00 hex] [payload size byte: 7b hex: 123 bytes] [tx chunk bytes: 123 bytes]
hex message for last part
80 02 80 00 18 3ed87...
80 02 [last command message: 1 byte: 80 hex] [chain id: 1 byte: 00 hex] [payload size byte: 18 hex: 24 bytes] [last 24 tx bytes]
For signing order add byte 252
as data type (and 0
for data version), for some data - 253
, for request - 254
, for a message - 255
. For different transactions set data type and version equals to tx type and version. This byte will not be signed, it tells the device what type of message it is sent to display in the user interface. Nothing needs to be transferred for transactions, the first byte of the tx body data is the transaction type and it will be signed as expected.
HID => 800200577b8000002c80579bfc8000000080000000800000010808040204023897f7c45e11ef1e2ef9a6d70f378053c6a0e0a7b2f4cbb8d7eecebd585d237e0181121cb46877fbc5c8059919e2a9cf03dcf2fbb112020ec38b7d868b7dd742810000000163692c9e25000000000000000100000000000186a00157da1ca8737e
HID <= 9000
HID => 800280571b159b763ed87810231ea189c0bce5352d630abc0006707269766574
HID <= 823a32d95430e6c9884c99b96369a66e5bd119fc6d85254942512d8c2d75f372c003c888e773c8996a41ce6b209a270366ca80d9d1fb389340a5ee7abd940d0a9000
signature 3c1idAPkLtX3TUoXuMhLxFUHSLEq8AFY6y2SRjDxFZt99reXKkHHVJiGmfrBn5NXKSSxh5Ux1k7UHP3nS826qx3j
HID => 800200577b8000002c80579bfc8000000080000000800000010808040204023897f7c45e11ef1e2ef9a6d70f378053c6a0e0a7b2f4cbb8d7eecebd585d237e0181121cb46877fbc5c8059919e2a9cf03dcf2fbb112020ec38b7d868b7dd742810000000163692c9e25000000000000000100000000000186a00157da1ca8737e
HID <= 9000
HID => 800280571b159b763ed87810231ea189c0bce5352d630abc0006707269766574
HID <= 9100
User denied signing request on Ledger Nano S device.
hex message for the first part
80 02 [not last command message: 1 byte: 00 hex] [chain id: 1 byte: 00 hex] [payload size byte: 7b hex: 123 bytes] [bip32 path bytes: 20 bytes: ...] [amount decimals: 1 byte] [fee decimals: 1 byte] [data type: 1 byte] [data version: 1 byte] [tx data size: 4 byte] [tx chunk bytes: 94 bytes] [tx chunk bytes: 94 bytes]
In short, there are only 3 changes:
- chain id should be specified in the first message (can be specified in each)
- an int data size field is added before the data itself
- tx data for signature is transmitted twice
These changes are necessary to support data signing of any size - up to 2^256 bytes (limit is the only data size type). Data is sent twice to calculate two sha512 hashes when calculating the signature ed25519. For the details take a look at stream_eddsa_sign.c
.
HID => 800200577b8000002c80579bfc800000008000000080000001080804020000007e04023897f7c45e11ef1e2ef9a6d70f378053c6a0e0a7b2f4cbb8d7eecebd585d237e0181121cb46877fbc5c8059919e2a9cf03dcf2fbb112020ec38b7d868b7dd742810000000163692c9e25000000000000000100000000000186a00157da
HID <= 9000
HID => 800200577b1ca8737e159b763ed87810231ea189c0bce5352d630abc000670726976657404023897f7c45e11ef1e2ef9a6d70f378053c6a0e0a7b2f4cbb8d7eecebd585d237e0181121cb46877fbc5c8059919e2a9cf03dcf2fbb112020ec38b7d868b7dd742810000000163692c9e25000000000000000100000000000186a0
HID <= 9000
HID => 80028057220157da1ca8737e159b763ed87810231ea189c0bce5352d630abc0006707269766574
HID <= beeb42ff67a668d161044141cbff88c8c660344a91c4f798eb7c389c9f5dee3e5a71663b4a12d9780bbbcf7c9f0cc3bb535c1bb4f61f2462def3b8568a9acf029000
signature 4pPfXjKsqq4ciENfobXDiSvebjFKR7y8vuw5MmQKVrxn4vbukE2vCyarWx5QYTTUv9cpcajMuAKAtvjTikTEtZFF
HID => 800200577b8000002c80579bfc800000008000000080000001080804020000007e04023897f7c45e11ef1e2ef9a6d70f378053c6a0e0a7b2f4cbb8d7eecebd585d237e0181121cb46877fbc5c8059919e2a9cf03dcf2fbb112020ec38b7d868b7dd742810000000163692c9e25000000000000000100000000000186a00157da
HID <= 9000
HID => 800200577b1ca8737e159b763ed87810231ea189c0bce5352d630abc000670726976657404023897f7c45e11ef1e2ef9a6d70f378053c6a0e0a7b2f4cbb8d7eecebd585d237e0181121cb46877fbc5c8059919e2a9cf03dcf2fbb112020ec38b7d868b7dd742810000000163692c9e25000000000000000100000000000186a0
HID <= 9000
HID => 80028057220157da1ca8737e159b763ed87810231ea189c0bce5352d630abc0006707269766574
HID <= 9100
User denied signing request on Ledger Nano S device.
hex message for the first part
80 02 [not last command message: 1 byte: 00 hex] [chain id: 1 byte: 00 hex] [payload size byte: 7b hex: 123 bytes] [bip32 path bytes: 20 bytes: ...] [amount decimals: 1 byte] [amount 2 decimals: 1 byte] [fee decimals: 1 byte] [data type: 1 byte] [data version: 1 byte] [tx data size: 4 byte] [tx chunk bytes: 93 bytes]
In short, there are only 2 changes:
- add protobuf support
- tx data for signature is transmitted four times
These changes are necessary to support protobuf transactions. First, the data is sent twice to calculate two sha512 hashes when calculating the signature ed25519. Second, the data is sending in a third and fourth time to parse data to view it on ledger screen
HID => 800200527b8000002c80579bfc80000000800000008000000104000404030000007c085212208d8fb28dc0757c0ac5462dba604600ec178b077b548092ba23d18a31686337741a0410a18d06208080babbc82e2803c206460a160a142789c985d35d67d685dc0e98ba2f216d86be8fbc122c0a207f19608a0fd0033f46967293
HID <= 9000
HID => 800200527bd6216cdb010b89401d3789a1a0f30a71a664ebb310ffffffffffffffff7f085212208d8fb28dc0757c0ac5462dba604600ec178b077b548092ba23d18a31686337741a0410a18d06208080babbc82e2803c206460a160a142789c985d35d67d685dc0e98ba2f216d86be8fbc122c0a207f19608a0fd0033f469672
HID <= 9000
HID => 800200527b93d6216cdb010b89401d3789a1a0f30a71a664ebb310ffffffffffffffff7f085212208d8fb28dc0757c0ac5462dba604600ec178b077b548092ba23d18a31686337741a0410a18d06208080babbc82e2803c206460a160a142789c985d35d67d685dc0e98ba2f216d86be8fbc122c0a207f19608a0fd0033f4696
HID <= 9000
HID => 800200527b7293d6216cdb010b89401d3789a1a0f30a71a664ebb310ffffffffffffffff7f085212208d8fb28dc0757c0ac5462dba604600ec178b077b548092ba23d18a31686337741a0410a18d06208080babbc82e2803c206460a160a142789c985d35d67d685dc0e98ba2f216d86be8fbc122c0a207f19608a0fd0033f46
HID <= 9000
HID => 8002805221967293d6216cdb010b89401d3789a1a0f30a71a664ebb310ffffffffffffffff7f
HID <= f0ed90a6fcdf10f097b7a19c8543dc5e0ff36b5fef30c6dfa4c6a30f8e69b2ec1067a5ea3fe19b85afe4646108327b52469229400b1d2a40ca651f9a1271d3099000
signature 5pP8KVEBeF5qJRFu6sre5jJLb2g8pNnNMSKNbc25vq5ATqfsjXrBMXUJet61RBZdfRQ6uSw1HpHSRmeRbXU1iLW4
HID => 800200527b8000002c80579bfc80000000800000008000000104000404030000007c085212208d8fb28dc0757c0ac5462dba604600ec178b077b548092ba23d18a31686337741a0410a18d06208080babbc82e2803c206460a160a142789c985d35d67d685dc0e98ba2f216d86be8fbc122c0a207f19608a0fd0033f46967293
HID <= 9000
HID => 800200527bd6216cdb010b89401d3789a1a0f30a71a664ebb310ffffffffffffffff7f085212208d8fb28dc0757c0ac5462dba604600ec178b077b548092ba23d18a31686337741a0410a18d06208080babbc82e2803c206460a160a142789c985d35d67d685dc0e98ba2f216d86be8fbc122c0a207f19608a0fd0033f469672
HID <= 9000
HID => 800200527b93d6216cdb010b89401d3789a1a0f30a71a664ebb310ffffffffffffffff7f085212208d8fb28dc0757c0ac5462dba604600ec178b077b548092ba23d18a31686337741a0410a18d06208080babbc82e2803c206460a160a142789c985d35d67d685dc0e98ba2f216d86be8fbc122c0a207f19608a0fd0033f4696
HID <= 9000
HID => 800200527b7293d6216cdb010b89401d3789a1a0f30a71a664ebb310ffffffffffffffff7f085212208d8fb28dc0757c0ac5462dba604600ec178b077b548092ba23d18a31686337741a0410a18d06208080babbc82e2803c206460a160a142789c985d35d67d685dc0e98ba2f216d86be8fbc122c0a207f19608a0fd0033f46
HID <= 9000
HID => 8002805221967293d6216cdb010b89401d3789a1a0f30a71a664ebb310ffffffffffffffff7f
HID <= 9100
User denied signing request on Ledger Nano S device.
SW_OK
(9000) after each chunk
[signature: 64 bytes] [service status: should be 9000 = SW_OK]
after last one
or
SW_USER_CANCELLED
(9100) if the user canceled the request
The error code will return in error cause.
SW_CONDITIONS_NOT_SATISFIED
(6985) if some required condition was failed
SW_BUFFER_OVERFLOW
(6990) if max transaction size was reached (650 bytes for now)
SW_DEVICE_IS_LOCKED
(6986) if the device is locked
SW_SIGN_DATA_NOT_MATCH
(9101) if sent data twice is different
SW_DEPRECATED_SIGN_PROTOCOL
(9102) if use 1.1.0+ ledger app version and do not use the new protocol (see protocol update above)
SW_INCORRECT_PRECISION_VALUE
(9103) if incorrect precision was sent for amount or fee
SW_INCORRECT_TRANSACTION_TYPE_VERSION
(9104) if incorrect transaction type or version was sent
SW_PROTOBUF_DECODING_FAILED
(9105) if decoding of protobuf message was failed
SW_BYTE_DECODING_FAILED
(9106) if decoding of byte tx data was failed
To get the app version you need to send 8006
to the device, then it will return 3 bytes: [major version][minor version][patch version].
You should pick one for your project language:
There is a test Python implementation of communication with ledger Waves app.