Skip to content

Commit

Permalink
Merge pull request #224 from Zondax/dev
Browse files Browse the repository at this point in the history
carlosala authored Oct 4, 2023
2 parents 2323a72 + 34ea581 commit c8d31ae
Showing 111 changed files with 356 additions and 328 deletions.
2 changes: 1 addition & 1 deletion app/Makefile.version
Original file line number Diff line number Diff line change
@@ -3,4 +3,4 @@ APPVERSION_M=2
# This is the minor version of this release
APPVERSION_N=4
# This is the patch version of this release
APPVERSION_P=7
APPVERSION_P=8
11 changes: 7 additions & 4 deletions app/src/candid/candid_parser.c
Original file line number Diff line number Diff line change
@@ -345,12 +345,11 @@ parser_error_t readCandidICRCTransfer(parser_tx_t *tx, const uint8_t *input, uin
// Read to (Account)
CHECK_PARSER_ERR(readCandidByte(&ctx, &icrc->account.has_owner))
if (icrc->account.has_owner) {
uint8_t ownerSize = 0;
CHECK_PARSER_ERR(readCandidByte(&ctx, &ownerSize))
if (ownerSize != DFINITY_PRINCIPAL_LEN) {
CHECK_PARSER_ERR(readCandidByte(&ctx, &icrc->account.owner.len))
if (icrc->account.owner.len > DFINITY_PRINCIPAL_LEN) {
return parser_unexpected_value;
}
CHECK_PARSER_ERR(readCandidBytes(&ctx, icrc->account.owner, ownerSize))
CHECK_PARSER_ERR(readCandidBytes(&ctx, icrc->account.owner.ptr, icrc->account.owner.len))
}

CHECK_PARSER_ERR(readCandidByte(&ctx, &icrc->account.has_subaccount))
@@ -369,6 +368,10 @@ parser_error_t readCandidICRCTransfer(parser_tx_t *tx, const uint8_t *input, uin
if (icrc->has_memo) {
uint8_t tmp = 0;
CHECK_PARSER_ERR(readCandidNat(&ctx, &icrc->memo.len))
// should not be bigger than uint64
if (icrc->memo.len > 8) {
return parser_unexpected_value;
}

icrc->memo.p = ctx.buffer + ctx.offset;
for (uint64_t i = 0; i < icrc->memo.len; i++) {
13 changes: 9 additions & 4 deletions app/src/candid/candid_types.h
Original file line number Diff line number Diff line change
@@ -220,9 +220,14 @@ typedef struct {
uint32_t dissolve_timestamp_seconds;
} candid_IncreaseDissolveDelay_t;

typedef struct {
uint8_t len;
uint8_t ptr[30];
} candid_Principal_t;

typedef struct {
uint8_t has_principal;
uint8_t principal[30];
candid_Principal_t principal;
} candid_AddRemoveHotkey_t;

typedef struct {
@@ -241,7 +246,7 @@ typedef struct {
uint32_t percentage_to_spawn;

uint8_t has_controller;
uint8_t new_controller[30];
candid_Principal_t new_controller;

uint8_t has_nonce;
uint64_t nonce;
@@ -298,12 +303,12 @@ typedef struct {
sns_NeuronPermissionList_t permissionList;

uint8_t has_principal;
uint8_t principal[30];
candid_Principal_t principal;
} sns_NeuronPermissions_t;

typedef struct {
uint8_t has_owner;
uint8_t owner[30];
candid_Principal_t owner;

uint8_t has_subaccount;
sizedBuffer_t subaccount;
14 changes: 6 additions & 8 deletions app/src/candid/nns_parser.c
Original file line number Diff line number Diff line change
@@ -144,11 +144,10 @@ __Z_INLINE parser_error_t readCommandSpawn(parser_context_t *ctx, candid_transac
CHECK_PARSER_ERR(readCandidByte(ctx, &val->command.spawn.has_controller))
if (val->command.spawn.has_controller) {
uint8_t has_principal = 0;
uint8_t principalSize = 0;
CHECK_PARSER_ERR(readCandidByte(ctx, &has_principal))
if(has_principal) {
CHECK_PARSER_ERR(readCandidByte(ctx, &principalSize))
CHECK_PARSER_ERR(readCandidBytes(ctx, val->command.spawn.new_controller, principalSize))
if (has_principal) {
CHECK_PARSER_ERR(readCandidByte(ctx, &val->command.spawn.new_controller.len))
CHECK_PARSER_ERR(readCandidBytes(ctx, val->command.spawn.new_controller.ptr, val->command.spawn.new_controller.len))
}
}

@@ -425,16 +424,15 @@ __Z_INLINE parser_error_t readOperationAddRemoveHotkey(parser_context_t *ctx, ca
return parser_unexpected_value;
}
uint8_t has_principal = 0;
uint8_t principalSize = 0;
CHECK_PARSER_ERR(readCandidByte(ctx, &has_principal))
if (!has_principal) {
return parser_unexpected_value;
}
CHECK_PARSER_ERR(readCandidByte(ctx, &principalSize))
if (principalSize != DFINITY_PRINCIPAL_LEN) {
CHECK_PARSER_ERR(readCandidByte(ctx, &operation->hotkey.principal.len))
if (operation->hotkey.principal.len > DFINITY_PRINCIPAL_LEN) {
return parser_unexpected_value;
}
CHECK_PARSER_ERR(readCandidBytes(ctx, operation->hotkey.principal, principalSize))
CHECK_PARSER_ERR(readCandidBytes(ctx, operation->hotkey.principal.ptr, operation->hotkey.principal.len))

return parser_ok;
}
16 changes: 7 additions & 9 deletions app/src/candid/sns_parser.c
Original file line number Diff line number Diff line change
@@ -91,14 +91,13 @@ __Z_INLINE parser_error_t readSNSCommandNeuronPermissions(parser_context_t *ctx,
CHECK_PARSER_ERR(readCandidByte(ctx, &val->has_principal))
if (val->has_principal) {
uint8_t has_principal = 0;
uint8_t principalSize = 0;
CHECK_PARSER_ERR(readCandidByte(ctx, &has_principal))
if(has_principal) {
CHECK_PARSER_ERR(readCandidByte(ctx, &principalSize))
if (principalSize != DFINITY_PRINCIPAL_LEN) {
if (has_principal) {
CHECK_PARSER_ERR(readCandidByte(ctx, &val->principal.len))
if (val->principal.len > DFINITY_PRINCIPAL_LEN) {
return parser_unexpected_value;
}
CHECK_PARSER_ERR(readCandidBytes(ctx, val->principal, principalSize))
CHECK_PARSER_ERR(readCandidBytes(ctx, val->principal.ptr, val->principal.len))
}
}

@@ -290,14 +289,13 @@ __Z_INLINE parser_error_t readSNSCommandNeuronDisburse(parser_context_t *ctx, ca
CHECK_PARSER_ERR(readCandidByte(ctx, &val->account.has_owner))
if (val->account.has_owner) {
uint8_t has_principal = 0;
uint8_t principalSize = 0;
CHECK_PARSER_ERR(readCandidByte(ctx, &has_principal))
if (has_principal) {
CHECK_PARSER_ERR(readCandidByte(ctx, &principalSize))
if (principalSize != DFINITY_PRINCIPAL_LEN) {
CHECK_PARSER_ERR(readCandidByte(ctx, &val->account.owner.len))
if (val->account.owner.len > DFINITY_PRINCIPAL_LEN) {
return parser_unexpected_value;
}
CHECK_PARSER_ERR(readCandidBytes(ctx, val->account.owner, principalSize))
CHECK_PARSER_ERR(readCandidBytes(ctx, val->account.owner.ptr, val->account.owner.len))
}
}

36 changes: 29 additions & 7 deletions app/src/crypto.c
Original file line number Diff line number Diff line change
@@ -459,11 +459,33 @@ uint64_t change_endianness(uint64_t value) {
return result;
}

zxerr_t crypto_computeStakeSubaccount(const uint8_t *principal, uint16_t principalLen,
const uint8_t *memo, uint16_t memoLen,
uint8_t *subaccount, uint16_t subaccountLen) {
if (principalLen > DFINITY_PRINCIPAL_LEN || subaccountLen < DFINITY_SUBACCOUNT_LEN ||
memoLen > sizeof(uint64_t)) {
return zxerr_invalid_crypto_settings;
}

uint8_t preHash[1 + STAKEACCOUNT_PREFIX_SIZE + DFINITY_PRINCIPAL_LEN + sizeof(uint64_t)] = {0};
uint16_t preHashLen = 0;
preHash[0] = 0x0C;
preHashLen++;
memmove(preHash + preHashLen, "neuron-stake", STAKEACCOUNT_PREFIX_SIZE);
preHashLen += STAKEACCOUNT_PREFIX_SIZE;
memmove(preHash + preHashLen, principal, principalLen);
preHashLen += principalLen;
memmove(preHash + preHashLen, memo, memoLen);
preHashLen += memoLen;

cx_hash_sha256((uint8_t *) preHash, preHashLen, subaccount, 32);
return zxerr_ok;
}

zxerr_t crypto_principalToStakeAccount(const uint8_t *principal, uint16_t principalLen,
const uint64_t neuron_creation_memo,
uint8_t *address, uint16_t maxoutLen) {
if (principalLen != DFINITY_PRINCIPAL_LEN ||
maxoutLen < DFINITY_ADDR_LEN) {
if (principalLen > DFINITY_PRINCIPAL_LEN || maxoutLen < DFINITY_ADDR_LEN) {
return zxerr_invalid_crypto_settings;
}
stake_account account;
@@ -472,7 +494,7 @@ zxerr_t crypto_principalToStakeAccount(const uint8_t *principal, uint16_t princi
stake_account_pre_hash *pre_hash = &account.hash_fields.pre_hash;
pre_hash->prefix_byte = 0x0C;
MEMCPY(pre_hash->prefix_string, (uint8_t *) "neuron-stake", STAKEACCOUNT_PREFIX_SIZE);
MEMCPY(pre_hash->principal, principal, DFINITY_PRINCIPAL_LEN);
MEMCPY(pre_hash->principal, principal, principalLen);
pre_hash->memo_be = change_endianness(neuron_creation_memo);

stake_account_hash *final_hash = &account.hash_fields.stake_hash;
@@ -525,19 +547,19 @@ zxerr_t crypto_computePrincipal(const uint8_t *pubKey, uint8_t *principal) {
zxerr_t crypto_principalToSubaccount(const uint8_t *principal, uint16_t principalLen,
const uint8_t *subAccount, uint16_t subaccountLen,
uint8_t *address, uint16_t maxoutLen) {
if (principalLen != DFINITY_PRINCIPAL_LEN || subaccountLen != DFINITY_SUBACCOUNT_LEN ||
if (principalLen > DFINITY_PRINCIPAL_LEN || subaccountLen != DFINITY_SUBACCOUNT_LEN ||
maxoutLen < DFINITY_ADDR_LEN) {
return zxerr_invalid_crypto_settings;
}
uint8_t hashinput[SUBACCOUNT_PREFIX_SIZE + DFINITY_PRINCIPAL_LEN + DFINITY_SUBACCOUNT_LEN];
MEMZERO(hashinput, sizeof(hashinput));
hashinput[0] = 0x0a;
MEMCPY(&hashinput[1], (uint8_t *) "account-id", SUBACCOUNT_PREFIX_SIZE - 1);
MEMCPY(hashinput + SUBACCOUNT_PREFIX_SIZE, principal, DFINITY_PRINCIPAL_LEN);
MEMCPY(hashinput + SUBACCOUNT_PREFIX_SIZE + DFINITY_PRINCIPAL_LEN, subAccount, DFINITY_SUBACCOUNT_LEN);
MEMCPY(hashinput + SUBACCOUNT_PREFIX_SIZE, principal, principalLen);
MEMCPY(hashinput + SUBACCOUNT_PREFIX_SIZE + principalLen, subAccount, DFINITY_SUBACCOUNT_LEN);

CHECK_ZXERR(
hash_sha224(hashinput, SUBACCOUNT_PREFIX_SIZE + DFINITY_PRINCIPAL_LEN + DFINITY_SUBACCOUNT_LEN, address + 4,
hash_sha224(hashinput, SUBACCOUNT_PREFIX_SIZE + principalLen + DFINITY_SUBACCOUNT_LEN, address + 4,
(maxoutLen - 4)));

uint32_t crc = 0;
4 changes: 4 additions & 0 deletions app/src/crypto.h
Original file line number Diff line number Diff line change
@@ -63,6 +63,10 @@ zxerr_t crypto_sign_combined(uint8_t *signatureBuffer,

zxerr_t crypto_getDigest(uint8_t *digest, txtype_e txtype);

zxerr_t crypto_computeStakeSubaccount(const uint8_t *principal, uint16_t principalLen,
const uint8_t *memo, uint16_t memoLen,
uint8_t *subaccount, uint16_t subaccountLen);

zxerr_t crypto_principalToStakeAccount(const uint8_t *principal, uint16_t principalLen,
const uint64_t neuron_creation_memo,
uint8_t *address, uint16_t maxoutLen);
62 changes: 42 additions & 20 deletions app/src/parser_impl.c
Original file line number Diff line number Diff line change
@@ -15,6 +15,7 @@
********************************************************************************/

#include <zxmacros.h>
#include "crypto.h"
#include "parser_impl.h"
#include "parser_txdef.h"
#include "cbor.h"
@@ -286,10 +287,8 @@ parser_error_t getManageNeuronType(const parser_tx_t *v, manageNeuron_e *mn_type
case Spawn:
case Follow:
case RegisterVote:
case MergeMaturity: {
*mn_type = command;
return parser_ok;
}

default: {
return parser_unexpected_type;
@@ -702,23 +701,45 @@ parser_error_t _validateTx(__Z_UNUSED const parser_context_t *c, const parser_tx
#endif

if (v->txtype == call && parser_tx_obj.special_transfer_type == neuron_stake_transaction) {
const bool is_candid = v->tx_fields.call.method_type == candid_transfer;
uint8_t to_hash[32] = {0};
uint64_t memo = is_candid ? v->tx_fields.call.data.candid_transfer.memo
: v->tx_fields.call.data.SendRequest.memo.memo;


PARSER_ASSERT_OR_ERROR(
zxerr_ok == crypto_principalToStakeAccount(sender, DFINITY_PRINCIPAL_LEN,
memo, to_hash, sizeof(to_hash)),
parser_unexpected_error);

const uint8_t *to = is_candid ? v->tx_fields.call.data.candid_transfer.to
: v->tx_fields.call.data.SendRequest.to.hash;

if (memcmp(to_hash, to, DFINITY_ADDR_LEN) != 0) {
zemu_log_stack("wrong data");
return parser_invalid_address;
if (v->tx_fields.call.method_type == candid_icrc_transfer) {
const icrc_transfer_t *fields = &v->tx_fields.call.data.icrcTransfer;
if (fields->icp_canister == 0 || fields->account.has_owner == 0 ||
fields->account.has_subaccount == 0 ||
fields->account.subaccount.len != DFINITY_SUBACCOUNT_LEN ||
fields->has_memo == 0 || fields->memo.len == 0) {
return parser_invalid_address;
}
// stands for rrkah-fqaaa-aaaaa-aaaaq-cai principal
uint8_t governanceCanister[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01};
if (fields->account.owner.len != sizeof(governanceCanister) ||
memcmp(governanceCanister, fields->account.owner.ptr, 10) != 0) {
zemu_log_stack("wrong principal");
return parser_invalid_address;
}
PARSER_ASSERT_OR_ERROR(
zxerr_ok == crypto_computeStakeSubaccount(sender, v->tx_fields.call.sender.len,
fields->memo.p, fields->memo.len,
to_hash, sizeof(to_hash)),
parser_unexpected_error);
if (memcmp(to_hash, fields->account.subaccount.p, DFINITY_SUBACCOUNT_LEN) != 0) {
zemu_log_stack("wrong data");
return parser_invalid_address;
}
} else {
const bool is_candid = v->tx_fields.call.method_type == candid_transfer;
uint64_t memo = is_candid ? v->tx_fields.call.data.candid_transfer.memo
: v->tx_fields.call.data.SendRequest.memo.memo;
const uint8_t *to = is_candid ? v->tx_fields.call.data.candid_transfer.to
: v->tx_fields.call.data.SendRequest.to.hash;
PARSER_ASSERT_OR_ERROR(
zxerr_ok == crypto_principalToStakeAccount(sender, DFINITY_PRINCIPAL_LEN,
memo, to_hash, sizeof(to_hash)),
parser_unexpected_error);
if (memcmp(to_hash, to, DFINITY_ADDR_LEN) != 0) {
zemu_log_stack("wrong data");
return parser_invalid_address;
}
}
}
return parser_ok;
@@ -746,7 +767,6 @@ uint8_t getNumItemsManageNeurons(__Z_UNUSED const parser_context_t *c, const par
case Configure_AddHotKey :
case Configure_RemoveHotkeyCandid:
case Configure_AddHotkeyCandid:
case MergeMaturity :
case Configure_IncreaseDissolveDelay:
case Configure_IncreaseDissolveDelayCandid:
case Configure_ChangeAutoStakeMaturity:
@@ -841,10 +861,12 @@ uint8_t _getNumItems(__Z_UNUSED const parser_context_t *c, const parser_tx_t *v)
case candid_icrc_transfer: {
const call_t *call = &v->tx_fields.call;
const bool icp_canisterId = call->data.icrcTransfer.icp_canister;
const bool is_stake_tx = parser_tx_obj.special_transfer_type == neuron_stake_transaction;

// Canister ID will be display only when different to ICP
// Fee will be display if available or default if Canister ID is ICP
return 5 + (icp_canisterId ? 0 : 1) + ((call->data.icrcTransfer.has_fee || icp_canisterId) ? 1 : 0);
// To account is only shown if tx is not stake
return 4 + (icp_canisterId ? 0 : 1) + ((call->data.icrcTransfer.has_fee || icp_canisterId) ? 1 : 0) + (is_stake_tx ? 0 : 1);
}

default:
Loading

0 comments on commit c8d31ae

Please sign in to comment.