Document your code
Every project on GitHub comes with a version-controlled wiki to give your documentation the high level of care it deserves. It’s easy to create well-maintained, Markdown or rich text documentation alongside your code.
Sign up for free See pricing for teams and enterprisesIntegration manual
Introduction
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.
Ledger Application
The source code for the application is contained in this repository. The build and install instructions is here.
Application protocol
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.
Cryptography protocol
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 installs 'sign' bit into the signature from the public key, so no any additional convertation for signature are needed (unlike the signature of libsodium).
Ledger app protocol
Service statuses:
SW_OK 0x9000
SW_USER_CANCELLED 0x9100
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
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
.
Getting a public key
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.
Answer
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 user canceled the request
The error code will returns in error cause.
SW_CONDITIONS_NOT_SATISFIED
(6985) if some required condition was failed
SW_DEVICE_IS_LOCKED
(6986) if device is locked
Example:
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.
Sign message
Big message should be chunked by 128 bytes
hex message for 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 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.
Answer
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 user canceled the request
The error code will returns 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 device is locked
Example:
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.
App version
To get app version you need to send 8006
to the device, then it will return 3 bytes: [major version][minor version][patch version].
Communication library
You should pick one for your project language:
There is a test Python implementation of communication with ledger Waves app.