1
0
mirror of https://github.com/trezor/trezor-firmware.git synced 2024-11-12 18:49:07 +00:00

add Lisk support (#351)

This commit is contained in:
alepop 2018-09-14 13:13:41 +03:00 committed by Pavol Rusnak
parent 34aad724f0
commit b0a7ea1f31
9 changed files with 651 additions and 3 deletions

View File

@ -29,6 +29,7 @@ OBJS += ethereum_tokens.o
OBJS += nem2.o
OBJS += nem_mosaics.o
OBJS += stellar.o
OBJS += lisk.o
OBJS += debug.o
@ -91,6 +92,7 @@ OBJS += protob/messages-ethereum.pb.o
OBJS += protob/messages-management.pb.o
OBJS += protob/messages-nem.pb.o
OBJS += protob/messages-stellar.pb.o
OBJS += protob/messages-lisk.pb.o
OPTFLAGS ?= -Os

View File

@ -55,8 +55,9 @@
#include "rfc6979.h"
#include "gettext.h"
#include "supervise.h"
#include "stellar.h"
#include "messages.pb.h"
#include "stellar.h"
#include "lisk.h"
// message methods
@ -248,4 +249,5 @@ static bool fsm_layoutAddress(const char *address, const char *desc, bool ignore
#include "fsm_msg_crypto.h"
#include "fsm_msg_nem.h"
#include "fsm_msg_stellar.h"
#include "fsm_msg_lisk.h"
#include "fsm_msg_debug.h"

View File

@ -27,6 +27,7 @@
#include "messages-management.pb.h"
#include "messages-nem.pb.h"
#include "messages-stellar.pb.h"
#include "messages-lisk.pb.h"
// message functions
@ -101,6 +102,13 @@ void fsm_msgStellarAccountMergeOp(StellarAccountMergeOp *msg);
void fsm_msgStellarManageDataOp(StellarManageDataOp *msg);
void fsm_msgStellarBumpSequenceOp(StellarBumpSequenceOp *msg);
// Lisk
void fsm_msgLiskGetAddress(LiskGetAddress *msg);
void fsm_msgLiskGetPublicKey(LiskGetPublicKey *msg);
void fsm_msgLiskSignMessage(LiskSignMessage *msg);
void fsm_msgLiskVerifyMessage(LiskVerifyMessage *msg);
void fsm_msgLiskSignTx(LiskSignTx *msg);
// debug message functions
#if DEBUG_LINK
//void fsm_msgDebugLinkDecision(DebugLinkDecision *msg);

127
firmware/fsm_msg_lisk.h Normal file
View File

@ -0,0 +1,127 @@
void fsm_msgLiskGetAddress(LiskGetAddress *msg)
{
CHECK_INITIALIZED
CHECK_PIN
RESP_INIT(LiskAddress);
HDNode *node = fsm_getDerivedNode(ED25519_NAME, msg->address_n, msg->address_n_count, NULL);
if (!node) return;
resp->has_address = true;
if (!hdnode_get_lisk_address(node, resp->address))
return;
if (msg->has_show_display && msg->show_display) {
char desc[16];
strlcpy(desc, "Address:", sizeof(desc));
if (!fsm_layoutAddress(resp->address, desc, true, 0, msg->address_n, msg->address_n_count)) {
return;
}
}
msg_write(MessageType_MessageType_LiskAddress, resp);
layoutHome();
}
void fsm_msgLiskGetPublicKey(LiskGetPublicKey *msg)
{
CHECK_INITIALIZED
CHECK_PIN
RESP_INIT(LiskPublicKey);
HDNode *node = fsm_getDerivedNode(ED25519_NAME, msg->address_n, msg->address_n_count, NULL);
if (!node) return;
hdnode_fill_public_key(node);
resp->has_public_key = true;
resp->public_key.size = 32;
if (msg->has_show_display && msg->show_display) {
layoutLiskPublicKey(&node->public_key[1]);
if (!protectButton(ButtonRequestType_ButtonRequest_PublicKey, true)) {
fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL);
layoutHome();
return;
}
}
memcpy(&resp->public_key.bytes, &node->public_key[1], sizeof(resp->public_key.bytes));
msg_write(MessageType_MessageType_LiskPublicKey, resp);
layoutHome();
}
void fsm_msgLiskSignMessage(LiskSignMessage *msg)
{
CHECK_INITIALIZED
CHECK_PIN
RESP_INIT(LiskMessageSignature);
HDNode *node = fsm_getDerivedNode(ED25519_NAME, msg->address_n, msg->address_n_count, NULL);
if (!node) return;
hdnode_fill_public_key(node);
lisk_sign_message(node, msg, resp);
msg_write(MessageType_MessageType_LiskMessageSignature, resp);
layoutHome();
}
void fsm_msgLiskVerifyMessage(LiskVerifyMessage *msg)
{
if (lisk_verify_message(msg)) {
char address[23];
lisk_get_address_from_public_key((const uint8_t*)&msg->public_key, address);
layoutLiskVerifyAddress(address);
if (!protectButton(ButtonRequestType_ButtonRequest_Other, false)) {
fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL);
layoutHome();
return;
}
layoutVerifyMessage(msg->message.bytes, msg->message.size);
if (!protectButton(ButtonRequestType_ButtonRequest_Other, false)) {
fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL);
layoutHome();
return;
}
fsm_sendSuccess(_("Message verified"));
} else {
fsm_sendFailure(FailureType_Failure_DataError, _("Invalid signature"));
}
layoutHome();
}
void fsm_msgLiskSignTx(LiskSignTx *msg)
{
CHECK_INITIALIZED
CHECK_PIN
RESP_INIT(LiskSignedTx);
HDNode *node = fsm_getDerivedNode(ED25519_NAME, msg->address_n, msg->address_n_count, NULL);
if (!node) return;
hdnode_fill_public_key(node);
lisk_sign_tx(node, msg, resp);
msg_write(MessageType_MessageType_LiskSignedTx, resp);
layoutHome();
}

428
firmware/lisk.c Normal file
View File

@ -0,0 +1,428 @@
/*
* This file is part of the TREZOR project, https://trezor.io/
*
* Copyright (C) 2017 Saleem Rashid <trezor@saleemrashid.com>
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdio.h>
#include "lisk.h"
#include "curves.h"
#include "layout2.h"
#include "bitmaps.h"
#include "util.h"
#include "gettext.h"
#include "crypto.h"
#include "protect.h"
#include "messages.pb.h"
int hdnode_get_lisk_address(HDNode *node, char *address) {
if (node->curve != get_curve_by_name(ED25519_NAME)) {
return 0;
}
hdnode_fill_public_key(node);
lisk_get_address_from_public_key(&node->public_key[1], address);
return 1;
}
void lisk_get_address_from_public_key(const uint8_t* public_key, char *address) {
uint8_t digest[32];
uint8_t address_bytes[8];
sha256_Raw(public_key, 32, digest);
uint8_t i;
for (i = 0; i < 8; i++) {
address_bytes[i] = digest[ 7 - i];
}
uint64_t encodedAddress = 0;
for (i = 0; i < 8; i++ ) {
encodedAddress = encodedAddress << 8;
encodedAddress += address_bytes[i];
}
bn_format_uint64(encodedAddress, NULL, "L", 0, 0, false, address, 23);
}
void lisk_message_hash(const uint8_t *message, size_t message_len, uint8_t hash[32]) {
SHA256_CTX ctx;
sha256_Init(&ctx);
sha256_Update(&ctx, (const uint8_t *)"\x15" "Lisk Signed Message:\n", 22);
uint8_t varint[5];
uint32_t l = ser_length(message_len, varint);
sha256_Update(&ctx, varint, l);
sha256_Update(&ctx, message, message_len);
sha256_Final(&ctx, hash);
sha256_Raw(hash, 32, hash);
}
void lisk_sign_message(HDNode *node, LiskSignMessage *msg, LiskMessageSignature *resp)
{
layoutSignMessage(msg->message.bytes, msg->message.size);
if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) {
fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL);
layoutHome();
return;
}
layoutProgressSwipe(_("Signing"), 0);
uint8_t signature[64];
uint8_t hash[32];
lisk_message_hash(msg->message.bytes, msg->message.size, hash);
ed25519_sign(hash, 32, node->private_key, &node->public_key[1], signature);
memcpy(resp->signature.bytes, signature, sizeof(signature));
memcpy(resp->public_key.bytes, &node->public_key[1], 32);
resp->has_signature = true;
resp->signature.size = 64;
resp->has_public_key = true;
resp->public_key.size = 32;
}
bool lisk_verify_message(LiskVerifyMessage *msg)
{
uint8_t hash[32];
lisk_message_hash(msg->message.bytes, msg->message.size, hash);
return ed25519_sign_open(
hash,
32,
msg->public_key.bytes,
msg->signature.bytes
) == 0;
}
void lisk_update_raw_tx(HDNode *node, LiskSignTx *msg)
{
if(!msg->transaction.has_sender_public_key) {
memcpy(msg->transaction.sender_public_key.bytes, &node->public_key[1], 32);
}
// For CastVotes transactions, recipientId should be equal to transaction creator address.
if(msg->transaction.type == LiskTransactionType_CastVotes && !msg->transaction.has_recipient_id) {
char address[23];
lisk_get_address_from_public_key(&node->public_key[1], address);
memcpy(msg->transaction.recipient_id, address, sizeof(address));
msg->transaction.has_recipient_id = true;
}
}
void lisk_hashupdate_uint32(SHA256_CTX* ctx, uint32_t value)
{
uint8_t data[4];
write_le(data, value);
sha256_Update(ctx, data, sizeof(data));
}
void lisk_hashupdate_uint64(SHA256_CTX* ctx, uint64_t value, bool i)
{
uint8_t data[8];
// i = true ? big-endian : little-endian
data[i ? 0 : 7] = (value >> 56);
data[i ? 1 : 6] = (value >> 48);
data[i ? 2 : 5] = (value >> 40);
data[i ? 3 : 4] = (value >> 32);
data[i ? 4 : 3] = (value >> 24);
data[i ? 5 : 2] = (value >> 16);
data[i ? 6 : 1] = (value >> 8);
data[i ? 7 : 0] = value;
sha256_Update(ctx, data, sizeof(data));
}
void lisk_hashupdate_asset(SHA256_CTX* ctx, LiskTransactionType type, LiskTransactionAsset *asset)
{
switch (type) {
case LiskTransactionType_Transfer:
if (asset->has_data) {
sha256_Update(ctx, (const uint8_t *)asset->data, strlen(asset->data));
}
break;
case LiskTransactionType_RegisterDelegate:
if (asset->has_delegate && asset->delegate.has_username) {
sha256_Update(ctx, (const uint8_t *)asset->delegate.username, strlen(asset->delegate.username));
}
break;
case LiskTransactionType_CastVotes: {
char str[asset->votes_count * 66];
strlcpy(str, asset->votes[0], sizeof(str));
for (int i = 1; i < asset->votes_count; i++) {
strlcat(str, asset->votes[i], sizeof(str));
};
sha256_Update(ctx, (const uint8_t *)str, strlen(str));
break;
}
case LiskTransactionType_RegisterSecondPassphrase:
if (asset->has_signature && asset->signature.has_public_key) {
sha256_Update(ctx, asset->signature.public_key.bytes, asset->signature.public_key.size);
}
break;
case LiskTransactionType_RegisterMultisignatureAccount: {
if (asset->has_multisignature) {
char str[asset->multisignature.keys_group_count * 66 + 4 + 4];
uint8_t min[4];
uint8_t life_time[4];
// convert uint32_t to uint8_t
write_le(min, asset->multisignature.min);
write_le(life_time, asset->multisignature.life_time);
// calculate sha from min + life_time + keys_group
strlcpy(str, (const char *)min, sizeof(str));
strlcat(str, (const char *)life_time, sizeof(str));
for (int i = 0; i < asset->multisignature.keys_group_count; i++) {
strlcat(str, asset->multisignature.keys_group[i], sizeof(str));
};
sha256_Update(ctx, (const uint8_t *)str, strlen(str));
}
break;
}
default:
fsm_sendFailure(FailureType_Failure_DataError, _("Invalid transaction type"));
break;
}
}
void lisk_format_value(uint64_t value, char *formated_value)
{
bn_format_uint64(value, NULL, " LSK", 8, 0, false, formated_value, 20);
}
void liks_get_vote_txt(char *prefix, int num, char *txt, size_t size)
{
char buffer[4];
sprintf(buffer, "%d", num);
strlcpy(txt, prefix, size);
strlcat(txt, buffer, size);
strlcat(txt, (num != 1) ? " votes" : " vote", size);
}
void lisk_sign_tx(HDNode *node, LiskSignTx *msg, LiskSignedTx *resp)
{
lisk_update_raw_tx(node, msg);
if(msg->has_transaction) {
SHA256_CTX ctx;
sha256_Init(&ctx);
switch (msg->transaction.type) {
case LiskTransactionType_Transfer:
layoutRequireConfirmTx(msg->transaction.recipient_id, msg->transaction.amount);
break;
case LiskTransactionType_RegisterDelegate:
layoutRequireConfirmDelegateRegistration(&msg->transaction.asset);
break;
case LiskTransactionType_CastVotes:
layoutRequireConfirmCastVotes(&msg->transaction.asset);
break;
case LiskTransactionType_RegisterSecondPassphrase:
layoutLiskPublicKey(msg->transaction.asset.signature.public_key.bytes );
break;
case LiskTransactionType_RegisterMultisignatureAccount:
layoutRequireConfirmMultisig(&msg->transaction.asset);
break;
default:
fsm_sendFailure(FailureType_Failure_DataError, _("Invalid transaction type"));
layoutHome();
break;
}
if (!protectButton((
msg->transaction.type == LiskTransactionType_RegisterSecondPassphrase ?
ButtonRequestType_ButtonRequest_PublicKey :
ButtonRequestType_ButtonRequest_SignTx),
false)) {
fsm_sendFailure(FailureType_Failure_ActionCancelled, "Signing Canceled");
layoutHome();
return;
}
layoutRequireConfirmFee(msg->transaction.fee, msg->transaction.amount);
if (!protectButton(ButtonRequestType_ButtonRequest_ConfirmOutput, false)) {
fsm_sendFailure(FailureType_Failure_ActionCancelled, "Signing Canceled");
layoutHome();
return;
}
layoutProgressSwipe(_("Signing transaction"), 0);
sha256_Update(&ctx, (const uint8_t *)&msg->transaction.type, 1);
lisk_hashupdate_uint32(&ctx, msg->transaction.timestamp);
sha256_Update(&ctx, msg->transaction.sender_public_key.bytes, 32);
if (msg->transaction.has_requester_public_key) {
sha256_Update(&ctx, msg->transaction.requester_public_key.bytes, msg->transaction.requester_public_key.size);
}
uint64_t recipient_id = 0;
if (msg->transaction.has_recipient_id) {
// parse integer from lisk address (string -> number)
sscanf(msg->transaction.recipient_id, "%llu", (long long unsigned int *)&recipient_id );
}
lisk_hashupdate_uint64(&ctx, recipient_id, true);
lisk_hashupdate_uint64(&ctx, msg->transaction.amount, false);
lisk_hashupdate_asset(&ctx, msg->transaction.type, &msg->transaction.asset);
// if signature exist calculate second signature
if (msg->transaction.has_signature) {
sha256_Update(&ctx, msg->transaction.signature.bytes, msg->transaction.signature.size);
}
uint8_t signature[64];
uint8_t hash[32];
sha256_Final(&ctx, hash);
ed25519_sign(hash, 32, node->private_key, &node->public_key[1], signature);
memcpy(resp->signature.bytes, signature, sizeof(signature));
resp->has_signature = true;
resp->signature.size = 64;
}
}
// Layouts
void layoutLiskPublicKey(const uint8_t *pubkey)
{
char hex[32 * 2 + 1], desc[13];
strlcpy(desc, "Public Key:", sizeof(desc));
data2hex(pubkey, 32, hex);
const char **str = split_message((const uint8_t *)hex, 32 * 2, 16);
layoutDialogSwipe(&bmp_icon_question, NULL, _("Continue"), NULL,
desc, str[0], str[1], str[2], str[3], NULL);
}
void layoutLiskVerifyAddress(const char *address)
{
const char **str = split_message((const uint8_t *)address, strlen(address), 10);
layoutDialogSwipe(&bmp_icon_info, _("Cancel"), _("Confirm"),
_("Confirm address?"),
_("Message signed by:"),
str[0], str[1], NULL, NULL, NULL);
}
void layoutRequireConfirmTx(char *recipient_id, uint64_t amount)
{
char formated_amount[20];
const char **str = split_message((const uint8_t *)recipient_id, strlen(recipient_id), 16);
lisk_format_value(amount, formated_amount);
layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"),
NULL,
_("Confirm sending"),
formated_amount,
_("to:"),
str[0],
str[1],
NULL
);
}
void layoutRequireConfirmFee(uint64_t fee, uint64_t amount)
{
char formated_amount[20];
char formated_fee[20];
lisk_format_value(amount, formated_amount);
lisk_format_value(fee, formated_fee);
layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"),
NULL,
_("Confirm transaction"),
formated_amount,
_("fee:"),
formated_fee,
NULL,
NULL
);
}
void layoutRequireConfirmDelegateRegistration(LiskTransactionAsset *asset)
{
if (asset->has_delegate && asset->delegate.has_username) {
const char **str = split_message((const uint8_t *)asset->delegate.username, strlen(asset->delegate.username), 20);
layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"),
NULL,
_("Confirm transaction"),
_("Do you really want to"),
_("register a delegate?"),
str[0],
str[1],
NULL
);
}
}
void layoutRequireConfirmCastVotes(LiskTransactionAsset *asset)
{
uint8_t plus = 0;
uint8_t minus = 0;
char add_votes_txt[13];
char remove_votes_txt[16];
for (int i = 0; i < asset->votes_count; i++) {
if (strncmp(asset->votes[i], "+", 1) == 0) {
plus += 1;
} else {
minus += 1;
}
}
liks_get_vote_txt("Add ", plus, add_votes_txt, sizeof(add_votes_txt));
liks_get_vote_txt("Remove ", minus, remove_votes_txt, sizeof(remove_votes_txt));
layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"),
NULL,
_("Confirm transaction"),
add_votes_txt,
remove_votes_txt,
NULL,
NULL,
NULL
);
}
void layoutRequireConfirmMultisig(LiskTransactionAsset *asset)
{
char keys_group_str[22];
char life_time_str[14];
char min_str[8];
char buffer[8];
strlcpy(keys_group_str, "Keys group length: ", sizeof(keys_group_str));
strlcpy(life_time_str, "Life time: ", sizeof(life_time_str));
strlcpy(min_str, "Min: ", sizeof(min_str));
sprintf(buffer, "%u", (unsigned int)asset->multisignature.keys_group_count);
strlcat(keys_group_str, buffer, sizeof(keys_group_str));
sprintf(buffer, "%u", (unsigned int)asset->multisignature.life_time);
strlcat(life_time_str, buffer, sizeof(life_time_str));
sprintf(buffer, "%u", (unsigned int)asset->multisignature.min);
strlcat(min_str, buffer, sizeof(min_str));
layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"),
NULL,
_("Confirm transaction"),
keys_group_str,
life_time_str,
min_str,
NULL,
NULL
);
}

50
firmware/lisk.h Normal file
View File

@ -0,0 +1,50 @@
/*
* This file is part of the TREZOR project.
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __LISK_H__
#define __LISK_H__
#include <stdbool.h>
#include "bip32.h"
#include "fsm.h"
#include "messages-lisk.pb.h"
// Main
int hdnode_get_lisk_address(HDNode *node, char *address);
void lisk_sign_message(HDNode *node, LiskSignMessage *msg, LiskMessageSignature *resp);
bool lisk_verify_message(LiskVerifyMessage *msg);
void lisk_sign_tx(HDNode *node, LiskSignTx *msg, LiskSignedTx *resp);
// Helpers
void lisk_get_address_from_public_key(const uint8_t *public_key, char *address);
void lisk_format_value(uint64_t value, char *formated_value);
void lisk_update_raw_tx(HDNode *node, LiskSignTx *msg);
void lisk_hashupdate_uint64(SHA256_CTX* ctx, uint64_t value, bool i);
void lisk_hashupdate_uint32(SHA256_CTX* ctx, uint32_t value);
void lisk_hashupdate_asset(SHA256_CTX* ctx, LiskTransactionType type, LiskTransactionAsset *asset);
// Layout
void layoutLiskPublicKey(const uint8_t *pubkey);
void layoutLiskVerifyAddress(const char *address);
void layoutRequireConfirmTx(char *recipient_id, uint64_t amount);
void layoutRequireConfirmDelegateRegistration(LiskTransactionAsset *asset);
void layoutRequireConfirmCastVotes(LiskTransactionAsset *asset);
void layoutRequireConfirmMultisig(LiskTransactionAsset *asset);
void layoutRequireConfirmFee(uint64_t fee, uint64_t amount);
#endif

View File

@ -2,7 +2,7 @@ ifneq ($(V),1)
Q := @
endif
all: messages_map.h messages-bitcoin.pb.c messages-common.pb.c messages-crypto.pb.c messages-debug.pb.c messages-ethereum.pb.c messages-management.pb.c messages-nem.pb.c messages.pb.c messages-stellar.pb.c messages_nem_pb2.py
all: messages_map.h messages-bitcoin.pb.c messages-common.pb.c messages-crypto.pb.c messages-debug.pb.c messages-ethereum.pb.c messages-management.pb.c messages-nem.pb.c messages.pb.c messages-stellar.pb.c messages-lisk.pb.c messages_nem_pb2.py
PYTHON ?= python
@ -26,7 +26,7 @@ messages_%_pb2.py: messages-%.proto
$(Q)protoc -I/usr/include -I. $< --python_out=.
messages_map.h: messages_map.py messages_pb2.py
$(Q)$(PYTHON) $< | grep -v -e MessageType_Cardano -e MessageType_Lisk -e MessageType_Tezos -e MessageType_Ripple -e MessageType_Monero -e MessageType_DebugMonero -e MessageType_Ontology > $@
$(Q)$(PYTHON) $< | grep -v -e MessageType_Cardano -e MessageType_Tezos -e MessageType_Ripple -e MessageType_Monero -e MessageType_DebugMonero -e MessageType_Ontology > $@
clean:
rm -f *.pb *.o *.d *.pb.c *.pb.h *_pb2.py messages_map.h

View File

@ -0,0 +1,30 @@
LiskGetAddress.address_n max_count:8
LiskAddress.address max_size:23
LiskGetPublicKey.address_n max_count:8
LiskPublicKey.public_key max_size:32
LiskSignMessage.address_n max_count:8
LiskSignMessage.message max_size:1024
LiskMessageSignature.public_key max_size:32
LiskMessageSignature.signature max_size:64
LiskVerifyMessage.public_key max_size:33
LiskVerifyMessage.message max_size:1024
LiskVerifyMessage.signature max_size:65
LiskSignTx.address_n max_count:8
LiskSignedTx.signature max_size:64
LiskTransactionCommon.recipient_id max_size:23
LiskTransactionCommon.sender_public_key max_size:32
LiskTransactionCommon.requester_public_key max_size:32
LiskTransactionCommon.signature max_size:64
LiskTransactionAsset.data max_size:64
LiskTransactionAsset.votes max_count:33 max_size:66
LiskSignatureType.public_key max_size:32
LiskDelegateType.username max_size:20
LiskMultisignatureType.keys_group max_count:10 max_size:66

View File

@ -0,0 +1 @@
../../vendor/trezor-common/protob/messages-lisk.proto