Ledger Application Code in C++

Ledger Application

Source Code Explained

All Ledger transports must be sent with a byte prefix that defined what the payload type is. This is used to deserialize and display on the ledger device.

Byte_PrefixEnumDescription
0x01SIGN_UTF8Sign UTF8 message for Mainnet
0x02SIGN_TRANSACTIONSign Transaction for Mainnet
0x03SIGN_DIGESTSign the exact bytes provided in payload. Must be exactly 32 bytes like a sha256 hash
0x0BSIGN_UTF8_TESTNETSign UTF8 message for Testnet
0x0CSIGN_TRANSACTION_TESTNETSign Transaction for Testnet

Please see for more information how Partisia Blockchain works:

Address Derived

Partisia HD addresses are derived as follows:

  • Path m/44'/3757'/0'/0/<idx>

    For Ledger idx will be 0

  • The Private Key is derived from the HD Path, and the uncompressed Public Key is derived from the Private Key
  • To keep compatibility we convert the 64 byte public key into 65 bytes by prefixing the public key with 0x04
  • A sha256 hash is generated from the 65 bytes Public Key
  • The first 20 bytes of the hash prepended by 0x00 to create a 21 byte Partisia Address

Transactions Explained

In Partisia blockchain a valid transaction signature is defined by the following steps:

  • A Chain Id is appended to the end of a transaction payload

    Chain Id for Testnet is fixed at: [0, 0, 0, 27, 80, 97, 114, 116, 105, 115, 105, 97, 32, 66, 108, 111, 99, 107, 99, 104, 97, 105, 110, 32, 84, 101, 115, 116, 110, 101, 116] Chain Id for Mainnet is fixed at: [0, 0, 0, 19, 80, 97, 114, 116, 105, 115, 105, 97, 32, 66, 108, 111, 99, 107, 99, 104, 97, 105, 110]

  • A sha256 hash is then generated from The transaction payload. This 32 byte hash is called the digest
  • The private key is used to generate a canonical signature from the digest
  • The Signature returned from the Ledger Device is in DER format. The ledger-mpc-app converts it into Partisia Signature format below.

Partisia Signatures

Partisia Signature are always 65 bytes and defined as follows:

Byte RangeValue
0..1Recovery Param
1..33R Value
33..65S Value

Deserializing

Depending on the byte prefix the device, the ledger is set to deserialize in the following ways

UTF8 Message

Byte prefix 0x01 (mainnet) or 0x0B (testnet)

The payload must contain valid UTF8 bytes form byte range [1..]

Digest Hash

Byte prefix 0x03

The payload must be 33 bytes exactly with the first byte being 0x03

Transaction Payload

Byte prefix 0x02 (mainnet) or 0x0C (testnet)

Transaction must be formatted as follows:

Inner

24 bytes following the transaction type prefix

Byte RangeValue
0..8nonce
8..16validTo (date transaction is no expires
16..24fee

25 bytes following the Inner

Byte RangeValue
0..21contract
21..25payload length

Transaction Payload

unknown bytes following the Header

Byte RangeValue
0..transaction payload

Transaction MPC Transfer

There is a special check to see if the user is making a MPC transfer. If they are a more custom deserialization occurs and a more detailed display on the Ledger device is provided

Transaction Contract

For all other transactions, simply the Contract, fee, and payload are displayed

ledger-mpc-app

Partisia has developed a JS application that will interface with the Ledger App here:

Running the App

To run the app and test all the functionality of the Ledger Device please do the following:

git clone git@gitlab.com:partisiablockchainapplications/ledger-mpc-app.git
cd ledger-mpc-app

# install dependencies
npm i

# add your MNEMONIC into a .env file
echo MNEMONIC="word1 word2 word3 ..." >> .env

# unlock and open ledger to Partisia App
npm run test

Example Interaction