Merge pull request #117 from LedgerHQ/format-and-basic-CI

Add clang-format and basic CI
This commit is contained in:
Jean P
2020-12-03 15:24:14 +01:00
committed by GitHub
83 changed files with 8934 additions and 5091 deletions

20
.clang-format Normal file
View File

@@ -0,0 +1,20 @@
---
BasedOnStyle: Google
IndentWidth: 4
---
Language: Cpp
ColumnLimit: 100
PointerAlignment: Right
AlignAfterOpenBracket: Align
AlignConsecutiveMacros: true
AllowAllParametersOfDeclarationOnNextLine: false
SortIncludes: false
SpaceAfterCStyleCast: true
AllowShortCaseLabelsOnASingleLine: false
AllowAllArgumentsOnNextLine: false
AllowAllParametersOfDeclarationOnNextLine: false
AllowShortBlocksOnASingleLine: Never
AllowShortFunctionsOnASingleLine: None
BinPackArguments: false
BinPackParameters: false
---

36
.github/workflows/ci-workflow.yml vendored Normal file
View File

@@ -0,0 +1,36 @@
name: Compilation & tests
on: [push, pull_request]
jobs:
job_build_debug:
name: Build debug
runs-on: ubuntu-latest
container:
image: docker://ledgerhq/ledger-app-builder:1.6.1-2
steps:
- name: Clone
uses: actions/checkout@v2
- name: Build an altcoin
run: |
make DEBUG=1 CHAIN=ethereum_classic
- name: Upload altcoin binary
uses: actions/upload-artifact@v2
with:
name: ethereum-classic-app-debug
path: bin
- name: Build Ethereum
run: |
make clean
make DEBUG=1
- name: Upload app binary
uses: actions/upload-artifact@v2
with:
name: ethereum-app-debug
path: bin

19
.github/workflows/lint-workflow.yml vendored Normal file
View File

@@ -0,0 +1,19 @@
name: Code style check
on: [push, pull_request]
jobs:
job_lint:
name: Lint
runs-on: ubuntu-latest
steps:
- name: Clone
uses: actions/checkout@v2
- name: Lint
uses: DoozyX/clang-format-lint-action@v0.11
with:
source: "./"
extensions: "h,c"
clangFormatVersion: 10

View File

@@ -1,76 +1,135 @@
#include "shared_context.h" #include "shared_context.h"
#define APP_FLAG_DATA_ALLOWED 0x01 #define APP_FLAG_DATA_ALLOWED 0x01
#define APP_FLAG_EXTERNAL_TOKEN_NEEDED 0x02 #define APP_FLAG_EXTERNAL_TOKEN_NEEDED 0x02
#define APP_FLAG_STARKWARE 0x04 #define APP_FLAG_STARKWARE 0x04
#define APP_FLAG_STARKWARE_V2 0x08 #define APP_FLAG_STARKWARE_V2 0x08
#define CLA 0xE0 #define CLA 0xE0
#define INS_GET_PUBLIC_KEY 0x02 #define INS_GET_PUBLIC_KEY 0x02
#define INS_SIGN 0x04 #define INS_SIGN 0x04
#define INS_GET_APP_CONFIGURATION 0x06 #define INS_GET_APP_CONFIGURATION 0x06
#define INS_SIGN_PERSONAL_MESSAGE 0x08 #define INS_SIGN_PERSONAL_MESSAGE 0x08
#define INS_PROVIDE_ERC20_TOKEN_INFORMATION 0x0A #define INS_PROVIDE_ERC20_TOKEN_INFORMATION 0x0A
#define INS_SIGN_EIP_712_MESSAGE 0x0C #define INS_SIGN_EIP_712_MESSAGE 0x0C
#define INS_GET_ETH2_PUBLIC_KEY 0x0E #define INS_GET_ETH2_PUBLIC_KEY 0x0E
#define INS_SET_ETH2_WITHDRAWAL_INDEX 0x10 #define INS_SET_ETH2_WITHDRAWAL_INDEX 0x10
#define P1_CONFIRM 0x01 #define P1_CONFIRM 0x01
#define P1_NON_CONFIRM 0x00 #define P1_NON_CONFIRM 0x00
#define P2_NO_CHAINCODE 0x00 #define P2_NO_CHAINCODE 0x00
#define P2_CHAINCODE 0x01 #define P2_CHAINCODE 0x01
#define P1_FIRST 0x00 #define P1_FIRST 0x00
#define P1_MORE 0x80 #define P1_MORE 0x80
#define COMMON_CLA 0xB0 #define COMMON_CLA 0xB0
#define COMMON_INS_GET_WALLET_ID 0x04 #define COMMON_INS_GET_WALLET_ID 0x04
#ifdef HAVE_STARKWARE #ifdef HAVE_STARKWARE
#define STARKWARE_CLA 0xF0 #define STARKWARE_CLA 0xF0
#define STARKWARE_INS_GET_PUBLIC_KEY 0x02 #define STARKWARE_INS_GET_PUBLIC_KEY 0x02
#define STARKWARE_INS_SIGN_MESSAGE 0x04 #define STARKWARE_INS_SIGN_MESSAGE 0x04
#define STARKWARE_INS_PROVIDE_QUANTUM 0x08 #define STARKWARE_INS_PROVIDE_QUANTUM 0x08
#define STARKWARE_INS_UNSAFE_SIGN 0x0A #define STARKWARE_INS_UNSAFE_SIGN 0x0A
#define P1_STARK_ORDER 0x01 #define P1_STARK_ORDER 0x01
#define P1_STARK_TRANSFER 0x02 #define P1_STARK_TRANSFER 0x02
#define P1_STARK_ORDER_V2 0x03 #define P1_STARK_ORDER_V2 0x03
#define P1_STARK_TRANSFER_V2 0x04 #define P1_STARK_TRANSFER_V2 0x04
#define P1_STARK_CONDITIONAL_TRANSFER 0x05 #define P1_STARK_CONDITIONAL_TRANSFER 0x05
#define STARK_ORDER_TYPE 0 #define STARK_ORDER_TYPE 0
#define STARK_TRANSFER_TYPE 1 #define STARK_TRANSFER_TYPE 1
#define STARK_CONDITIONAL_TRANSFER_TYPE 2 #define STARK_CONDITIONAL_TRANSFER_TYPE 2
#endif #endif
#define OFFSET_CLA 0 #define OFFSET_CLA 0
#define OFFSET_INS 1 #define OFFSET_INS 1
#define OFFSET_P1 2 #define OFFSET_P1 2
#define OFFSET_P2 3 #define OFFSET_P2 3
#define OFFSET_LC 4 #define OFFSET_LC 4
#define OFFSET_CDATA 5 #define OFFSET_CDATA 5
void handleGetPublicKey(uint8_t p1, uint8_t p2, uint8_t *dataBuffer, uint16_t dataLength, unsigned int *flags, unsigned int *tx); void handleGetPublicKey(uint8_t p1,
void handleProvideErc20TokenInformation(uint8_t p1, uint8_t p2, uint8_t *dataBuffer, uint16_t dataLength, unsigned int *flags, unsigned int *tx); uint8_t p2,
void handleSign(uint8_t p1, uint8_t p2, uint8_t *dataBuffer, uint16_t dataLength, unsigned int *flags, unsigned int *tx); uint8_t *dataBuffer,
void handleGetAppConfiguration(uint8_t p1, uint8_t p2, uint8_t *dataBuffer, uint16_t dataLength, unsigned int *flags, unsigned int *tx); uint16_t dataLength,
void handleSignPersonalMessage(uint8_t p1, uint8_t p2, uint8_t *dataBuffer, uint16_t dataLength, unsigned int *flags, unsigned int *tx); unsigned int *flags,
void handleSignEIP712Message(uint8_t p1, uint8_t p2, uint8_t *dataBuffer, uint16_t dataLength, unsigned int *flags, unsigned int *tx); unsigned int *tx);
void handleProvideErc20TokenInformation(uint8_t p1,
uint8_t p2,
uint8_t *dataBuffer,
uint16_t dataLength,
unsigned int *flags,
unsigned int *tx);
void handleSign(uint8_t p1,
uint8_t p2,
uint8_t *dataBuffer,
uint16_t dataLength,
unsigned int *flags,
unsigned int *tx);
void handleGetAppConfiguration(uint8_t p1,
uint8_t p2,
uint8_t *dataBuffer,
uint16_t dataLength,
unsigned int *flags,
unsigned int *tx);
void handleSignPersonalMessage(uint8_t p1,
uint8_t p2,
uint8_t *dataBuffer,
uint16_t dataLength,
unsigned int *flags,
unsigned int *tx);
void handleSignEIP712Message(uint8_t p1,
uint8_t p2,
uint8_t *dataBuffer,
uint16_t dataLength,
unsigned int *flags,
unsigned int *tx);
#ifdef HAVE_ETH2 #ifdef HAVE_ETH2
void handleGetEth2PublicKey(uint8_t p1, uint8_t p2, uint8_t *dataBuffer, uint16_t dataLength, unsigned int *flags, unsigned int *tx); void handleGetEth2PublicKey(uint8_t p1,
void handleSetEth2WinthdrawalIndex(uint8_t p1, uint8_t p2, uint8_t *dataBuffer, uint16_t dataLength, unsigned int *flags, unsigned int *tx); uint8_t p2,
uint8_t *dataBuffer,
uint16_t dataLength,
unsigned int *flags,
unsigned int *tx);
void handleSetEth2WinthdrawalIndex(uint8_t p1,
uint8_t p2,
uint8_t *dataBuffer,
uint16_t dataLength,
unsigned int *flags,
unsigned int *tx);
#endif #endif
#ifdef HAVE_STARKWARE #ifdef HAVE_STARKWARE
void handleStarkwareGetPublicKey(uint8_t p1, uint8_t p2, uint8_t *dataBuffer, uint16_t dataLength, unsigned int *flags, unsigned int *tx); void handleStarkwareGetPublicKey(uint8_t p1,
void handleStarkwareSignMessage(uint8_t p1, uint8_t p2, uint8_t *dataBuffer, uint16_t dataLength, unsigned int *flags, unsigned int *tx); uint8_t p2,
void handleStarkwareProvideQuantum(uint8_t p1, uint8_t p2, uint8_t *dataBuffer, uint16_t dataLength, unsigned int *flags, unsigned int *tx); uint8_t *dataBuffer,
void handleStarkwareUnsafeSign(uint8_t p1, uint8_t p2, uint8_t *dataBuffer, uint16_t dataLength, unsigned int *flags, unsigned int *tx); uint16_t dataLength,
unsigned int *flags,
unsigned int *tx);
void handleStarkwareSignMessage(uint8_t p1,
uint8_t p2,
uint8_t *dataBuffer,
uint16_t dataLength,
unsigned int *flags,
unsigned int *tx);
void handleStarkwareProvideQuantum(uint8_t p1,
uint8_t p2,
uint8_t *dataBuffer,
uint16_t dataLength,
unsigned int *flags,
unsigned int *tx);
void handleStarkwareUnsafeSign(uint8_t p1,
uint8_t p2,
uint8_t *dataBuffer,
uint16_t dataLength,
unsigned int *flags,
unsigned int *tx);
#endif #endif

View File

@@ -172,41 +172,34 @@ int Base64decode(char *bufplain, const char *bufcoded)
#endif #endif
static const char basis_64[] = static const char basis_64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
int Base64encode_len(int len) int Base64encode_len(int len) {
{
return ((len + 2) / 3 * 4) + 1; return ((len + 2) / 3 * 4) + 1;
} }
int Base64encode(char *encoded, const char *string, int len) int Base64encode(char *encoded, const char *string, int len) {
{
int i; int i;
char *p; char *p;
p = encoded; p = encoded;
for (i = 0; i < len - 2; i += 3) { for (i = 0; i < len - 2; i += 3) {
*p++ = basis_64[(string[i] >> 2) & 0x3F]; *p++ = basis_64[(string[i] >> 2) & 0x3F];
*p++ = basis_64[((string[i] & 0x3) << 4) | *p++ = basis_64[((string[i] & 0x3) << 4) | ((int) (string[i + 1] & 0xF0) >> 4)];
((int) (string[i + 1] & 0xF0) >> 4)]; *p++ = basis_64[((string[i + 1] & 0xF) << 2) | ((int) (string[i + 2] & 0xC0) >> 6)];
*p++ = basis_64[((string[i + 1] & 0xF) << 2) | *p++ = basis_64[string[i + 2] & 0x3F];
((int) (string[i + 2] & 0xC0) >> 6)];
*p++ = basis_64[string[i + 2] & 0x3F];
} }
if (i < len) { if (i < len) {
*p++ = basis_64[(string[i] >> 2) & 0x3F]; *p++ = basis_64[(string[i] >> 2) & 0x3F];
if (i == (len - 1)) { if (i == (len - 1)) {
*p++ = basis_64[((string[i] & 0x3) << 4)]; *p++ = basis_64[((string[i] & 0x3) << 4)];
*p++ = '=';
} else {
*p++ = basis_64[((string[i] & 0x3) << 4) | ((int) (string[i + 1] & 0xF0) >> 4)];
*p++ = basis_64[((string[i + 1] & 0xF) << 2)];
}
*p++ = '='; *p++ = '=';
} }
else {
*p++ = basis_64[((string[i] & 0x3) << 4) |
((int) (string[i + 1] & 0xF0) >> 4)];
*p++ = basis_64[((string[i + 1] & 0xF) << 2)];
}
*p++ = '=';
}
*p++ = '\0'; *p++ = '\0';
return p - encoded; return p - encoded;

View File

@@ -79,8 +79,6 @@
* *
*/ */
#ifndef _BASE64_H_ #ifndef _BASE64_H_
#define _BASE64_H_ #define _BASE64_H_
@@ -89,7 +87,7 @@ extern "C" {
#endif #endif
int Base64encode_len(int len); int Base64encode_len(int len);
int Base64encode(char * coded_dst, const char *plain_src,int len_plain_src); int Base64encode(char *coded_dst, const char *plain_src, int len_plain_src);
#if 0 #if 0
@@ -102,4 +100,4 @@ int Base64decode(char * plain_dst, const char *coded_src);
} }
#endif #endif
#endif //_BASE64_H_ #endif //_BASE64_H_

View File

@@ -1,19 +1,19 @@
/******************************************************************************* /*******************************************************************************
* Ledger Ethereum App * Ledger Ethereum App
* (c) 2016-2019 Ledger * (c) 2016-2019 Ledger
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
********************************************************************************/ ********************************************************************************/
#ifndef _CHAIN_CONFIG_H_ #ifndef _CHAIN_CONFIG_H_
#define _CHAIN_CONFIG_H_ #define _CHAIN_CONFIG_H_
@@ -23,42 +23,42 @@
#include "os.h" #include "os.h"
typedef enum chain_kind_e { typedef enum chain_kind_e {
CHAIN_KIND_ETHEREUM, CHAIN_KIND_ETHEREUM,
CHAIN_KIND_ETHEREUM_CLASSIC, CHAIN_KIND_ETHEREUM_CLASSIC,
CHAIN_KIND_EXPANSE, CHAIN_KIND_EXPANSE,
CHAIN_KIND_POA, CHAIN_KIND_POA,
CHAIN_KIND_RSK, CHAIN_KIND_RSK,
CHAIN_KIND_UBIQ, CHAIN_KIND_UBIQ,
CHAIN_KIND_WANCHAIN, CHAIN_KIND_WANCHAIN,
CHAIN_KIND_KUSD, CHAIN_KIND_KUSD,
CHAIN_KIND_PIRL, CHAIN_KIND_PIRL,
CHAIN_KIND_AKROMA, CHAIN_KIND_AKROMA,
CHAIN_KIND_MUSICOIN, CHAIN_KIND_MUSICOIN,
CHAIN_KIND_CALLISTO, CHAIN_KIND_CALLISTO,
CHAIN_KIND_ETHERSOCIAL, CHAIN_KIND_ETHERSOCIAL,
CHAIN_KIND_ELLAISM, CHAIN_KIND_ELLAISM,
CHAIN_KIND_ETHER1, CHAIN_KIND_ETHER1,
CHAIN_KIND_ETHERGEM, CHAIN_KIND_ETHERGEM,
CHAIN_KIND_ATHEIOS, CHAIN_KIND_ATHEIOS,
CHAIN_KIND_GOCHAIN, CHAIN_KIND_GOCHAIN,
CHAIN_KIND_MIX, CHAIN_KIND_MIX,
CHAIN_KIND_REOSC, CHAIN_KIND_REOSC,
CHAIN_KIND_HPB, CHAIN_KIND_HPB,
CHAIN_KIND_TOMOCHAIN, CHAIN_KIND_TOMOCHAIN,
CHAIN_KIND_TOBALABA, CHAIN_KIND_TOBALABA,
CHAIN_KIND_DEXON, CHAIN_KIND_DEXON,
CHAIN_KIND_VOLTA, CHAIN_KIND_VOLTA,
CHAIN_KIND_EWC, CHAIN_KIND_EWC,
CHAIN_KIND_ARTIS_SIGMA1, CHAIN_KIND_ARTIS_SIGMA1,
CHAIN_KIND_ARTIS_TAU1, CHAIN_KIND_ARTIS_TAU1,
CHAIN_KIND_WEBCHAIN, CHAIN_KIND_WEBCHAIN,
CHAIN_KIND_THUNDERCORE CHAIN_KIND_THUNDERCORE
} chain_kind_t; } chain_kind_t;
typedef struct chain_config_s { typedef struct chain_config_s {
char coinName[10]; // ticker char coinName[10]; // ticker
uint32_t chainId; uint32_t chainId;
chain_kind_t kind; chain_kind_t kind;
} chain_config_t; } chain_config_t;
#endif /* _CHAIN_CONFIG_H_ */ #endif /* _CHAIN_CONFIG_H_ */

View File

@@ -5,248 +5,267 @@
#include "base64.h" #include "base64.h"
void eth_plugin_prepare_init(ethPluginInitContract_t *init, uint8_t *selector, uint32_t dataSize) { void eth_plugin_prepare_init(ethPluginInitContract_t *init, uint8_t *selector, uint32_t dataSize) {
memset((uint8_t*)init, 0, sizeof(ethPluginInitContract_t)); memset((uint8_t *) init, 0, sizeof(ethPluginInitContract_t));
init->selector = selector; init->selector = selector;
init->dataSize = dataSize; init->dataSize = dataSize;
} }
void eth_plugin_prepare_provide_parameter(ethPluginProvideParameter_t *provideParameter, uint8_t *parameter, uint32_t parameterOffset) { void eth_plugin_prepare_provide_parameter(ethPluginProvideParameter_t *provideParameter,
memset((uint8_t*)provideParameter, 0, sizeof(ethPluginProvideParameter_t)); uint8_t *parameter,
provideParameter->parameter = parameter; uint32_t parameterOffset) {
provideParameter->parameterOffset = parameterOffset; memset((uint8_t *) provideParameter, 0, sizeof(ethPluginProvideParameter_t));
provideParameter->parameter = parameter;
provideParameter->parameterOffset = parameterOffset;
} }
void eth_plugin_prepare_finalize(ethPluginFinalize_t *finalize) { void eth_plugin_prepare_finalize(ethPluginFinalize_t *finalize) {
memset((uint8_t*)finalize, 0, sizeof(ethPluginFinalize_t)); memset((uint8_t *) finalize, 0, sizeof(ethPluginFinalize_t));
} }
void eth_plugin_prepare_provide_token(ethPluginProvideToken_t *provideToken, tokenDefinition_t *token1, tokenDefinition_t *token2) { void eth_plugin_prepare_provide_token(ethPluginProvideToken_t *provideToken,
memset((uint8_t*)provideToken, 0, sizeof(ethPluginProvideToken_t)); tokenDefinition_t *token1,
provideToken->token1 = token1; tokenDefinition_t *token2) {
provideToken->token2 = token2; memset((uint8_t *) provideToken, 0, sizeof(ethPluginProvideToken_t));
provideToken->token1 = token1;
provideToken->token2 = token2;
} }
void eth_plugin_prepare_query_contract_ID(ethQueryContractID_t *queryContractID, char *name, uint32_t nameLength, char *version, uint32_t versionLength) { void eth_plugin_prepare_query_contract_ID(ethQueryContractID_t *queryContractID,
memset((uint8_t*)queryContractID, 0, sizeof(ethQueryContractID_t)); char *name,
queryContractID->name = name; uint32_t nameLength,
queryContractID->nameLength = nameLength; char *version,
queryContractID->version = version; uint32_t versionLength) {
queryContractID->versionLength = versionLength; memset((uint8_t *) queryContractID, 0, sizeof(ethQueryContractID_t));
queryContractID->name = name;
queryContractID->nameLength = nameLength;
queryContractID->version = version;
queryContractID->versionLength = versionLength;
} }
void eth_plugin_prepare_query_contract_UI(ethQueryContractUI_t *queryContractUI, uint8_t screenIndex, char *title, uint32_t titleLength, char *msg, uint32_t msgLength) { void eth_plugin_prepare_query_contract_UI(ethQueryContractUI_t *queryContractUI,
memset((uint8_t*)queryContractUI, 0, sizeof(ethQueryContractUI_t)); uint8_t screenIndex,
queryContractUI->screenIndex = screenIndex; char *title,
queryContractUI->title = title; uint32_t titleLength,
queryContractUI->titleLength = titleLength; char *msg,
queryContractUI->msg = msg; uint32_t msgLength) {
queryContractUI->msgLength = msgLength; memset((uint8_t *) queryContractUI, 0, sizeof(ethQueryContractUI_t));
queryContractUI->screenIndex = screenIndex;
queryContractUI->title = title;
queryContractUI->titleLength = titleLength;
queryContractUI->msg = msg;
queryContractUI->msgLength = msgLength;
} }
int eth_plugin_perform_init(uint8_t *contractAddress, ethPluginInitContract_t *init) { int eth_plugin_perform_init(uint8_t *contractAddress, ethPluginInitContract_t *init) {
uint8_t i; uint8_t i;
const uint8_t **selectors; const uint8_t **selectors;
dataContext.tokenContext.pluginAvailable = 0; dataContext.tokenContext.pluginAvailable = 0;
// Handle hardcoded plugin list // Handle hardcoded plugin list
PRINTF("Selector %.*H\n", 4, init->selector); PRINTF("Selector %.*H\n", 4, init->selector);
for (i=0;; i++) { for (i = 0;; i++) {
uint8_t j; uint8_t j;
selectors = PIC(INTERNAL_ETH_PLUGINS[i].selectors); selectors = PIC(INTERNAL_ETH_PLUGINS[i].selectors);
if (selectors == NULL) { if (selectors == NULL) {
break; break;
} }
for (j=0; ((j<INTERNAL_ETH_PLUGINS[i].num_selectors) && (contractAddress != NULL)); j++) { for (j = 0; ((j < INTERNAL_ETH_PLUGINS[i].num_selectors) && (contractAddress != NULL));
if (memcmp(init->selector, PIC(selectors[j]), SELECTOR_SIZE) == 0) { j++) {
if ((INTERNAL_ETH_PLUGINS[i].availableCheck == NULL) || if (memcmp(init->selector, PIC(selectors[j]), SELECTOR_SIZE) == 0) {
((PluginAvailableCheck)PIC(INTERNAL_ETH_PLUGINS[i].availableCheck))()) { if ((INTERNAL_ETH_PLUGINS[i].availableCheck == NULL) ||
strcpy(dataContext.tokenContext.pluginName, INTERNAL_ETH_PLUGINS[i].alias); ((PluginAvailableCheck) PIC(INTERNAL_ETH_PLUGINS[i].availableCheck))()) {
dataContext.tokenContext.pluginAvailable = 1; strcpy(dataContext.tokenContext.pluginName, INTERNAL_ETH_PLUGINS[i].alias);
contractAddress = NULL; dataContext.tokenContext.pluginAvailable = 1;
break; contractAddress = NULL;
} break;
} }
} }
} }
}
// Do not handle a plugin if running in swap mode // Do not handle a plugin if running in swap mode
if (called_from_swap && (contractAddress != NULL)) { if (called_from_swap && (contractAddress != NULL)) {
PRINTF("eth_plug_init aborted in swap mode\n"); PRINTF("eth_plug_init aborted in swap mode\n");
return 0; return 0;
} }
for (;;) { for (;;) {
PRINTF("eth_plugin_init\n"); PRINTF("eth_plugin_init\n");
if (contractAddress != NULL) { if (contractAddress != NULL) {
PRINTF("Trying address %.*H\n", 20, contractAddress); PRINTF("Trying address %.*H\n", 20, contractAddress);
} } else {
else { PRINTF("Trying alias %s\n", dataContext.tokenContext.pluginName);
PRINTF("Trying alias %s\n", dataContext.tokenContext.pluginName); }
} int status = eth_plugin_call(contractAddress, ETH_PLUGIN_INIT_CONTRACT, (void *) init);
int status = eth_plugin_call(contractAddress, ETH_PLUGIN_INIT_CONTRACT, (void*)init); if (!status) {
if (!status) { return 0;
return 0; }
} if (status == ETH_PLUGIN_RESULT_OK) {
if (status == ETH_PLUGIN_RESULT_OK) { break;
break; }
} if (status == ETH_PLUGIN_RESULT_OK_ALIAS) {
if (status == ETH_PLUGIN_RESULT_OK_ALIAS) { contractAddress = NULL;
contractAddress = NULL; }
} }
} PRINTF("eth_plugin_init ok %s\n", dataContext.tokenContext.pluginName);
PRINTF("eth_plugin_init ok %s\n", dataContext.tokenContext.pluginName); dataContext.tokenContext.pluginAvailable = 1;
dataContext.tokenContext.pluginAvailable = 1; return 1;
return 1;
} }
int eth_plugin_call(uint8_t *contractAddress, int method, void *parameter) { int eth_plugin_call(uint8_t *contractAddress, int method, void *parameter) {
ethPluginSharedRW_t pluginRW; ethPluginSharedRW_t pluginRW;
ethPluginSharedRO_t pluginRO; ethPluginSharedRO_t pluginRO;
char tmp[PLUGIN_ID_LENGTH]; char tmp[PLUGIN_ID_LENGTH];
char *alias; char *alias;
uint8_t i; uint8_t i;
uint8_t internalPlugin = 0; uint8_t internalPlugin = 0;
pluginRW.sha3 = &global_sha3; pluginRW.sha3 = &global_sha3;
pluginRO.txContent = &tmpContent.txContent; pluginRO.txContent = &tmpContent.txContent;
if (contractAddress == NULL) { if (contractAddress == NULL) {
if (!dataContext.tokenContext.pluginAvailable) { if (!dataContext.tokenContext.pluginAvailable) {
PRINTF("Cached plugin call but no plugin available\n"); PRINTF("Cached plugin call but no plugin available\n");
return 0; return 0;
} }
alias = dataContext.tokenContext.pluginName; alias = dataContext.tokenContext.pluginName;
} } else {
else { Base64encode(tmp, (char *) contractAddress, 20);
Base64encode(tmp, (char*)contractAddress, 20); alias = tmp;
alias = tmp; }
}
// Prepare the call // Prepare the call
switch(method) { switch (method) {
case ETH_PLUGIN_INIT_CONTRACT: case ETH_PLUGIN_INIT_CONTRACT:
((ethPluginInitContract_t*)parameter)->pluginSharedRW = &pluginRW; ((ethPluginInitContract_t *) parameter)->pluginSharedRW = &pluginRW;
((ethPluginInitContract_t*)parameter)->pluginSharedRO = &pluginRO; ((ethPluginInitContract_t *) parameter)->pluginSharedRO = &pluginRO;
((ethPluginInitContract_t*)parameter)->pluginContext = (uint8_t*)&dataContext.tokenContext.pluginContext; ((ethPluginInitContract_t *) parameter)->pluginContext =
((ethPluginInitContract_t*)parameter)->pluginContextLength = sizeof(dataContext.tokenContext.pluginContext); (uint8_t *) &dataContext.tokenContext.pluginContext;
((ethPluginInitContract_t*)parameter)->alias = dataContext.tokenContext.pluginName; ((ethPluginInitContract_t *) parameter)->pluginContextLength =
break; sizeof(dataContext.tokenContext.pluginContext);
case ETH_PLUGIN_PROVIDE_PARAMETER: ((ethPluginInitContract_t *) parameter)->alias = dataContext.tokenContext.pluginName;
((ethPluginProvideParameter_t*)parameter)->pluginSharedRW = &pluginRW; break;
((ethPluginProvideParameter_t*)parameter)->pluginSharedRO = &pluginRO; case ETH_PLUGIN_PROVIDE_PARAMETER:
((ethPluginProvideParameter_t*)parameter)->pluginContext = (uint8_t*)&dataContext.tokenContext.pluginContext; ((ethPluginProvideParameter_t *) parameter)->pluginSharedRW = &pluginRW;
break; ((ethPluginProvideParameter_t *) parameter)->pluginSharedRO = &pluginRO;
case ETH_PLUGIN_FINALIZE: ((ethPluginProvideParameter_t *) parameter)->pluginContext =
((ethPluginFinalize_t*)parameter)->pluginSharedRW = &pluginRW; (uint8_t *) &dataContext.tokenContext.pluginContext;
((ethPluginFinalize_t*)parameter)->pluginSharedRO = &pluginRO; break;
((ethPluginFinalize_t*)parameter)->pluginContext = (uint8_t*)&dataContext.tokenContext.pluginContext; case ETH_PLUGIN_FINALIZE:
break; ((ethPluginFinalize_t *) parameter)->pluginSharedRW = &pluginRW;
case ETH_PLUGIN_PROVIDE_TOKEN: ((ethPluginFinalize_t *) parameter)->pluginSharedRO = &pluginRO;
((ethPluginProvideToken_t*)parameter)->pluginSharedRW = &pluginRW; ((ethPluginFinalize_t *) parameter)->pluginContext =
((ethPluginProvideToken_t*)parameter)->pluginSharedRO = &pluginRO; (uint8_t *) &dataContext.tokenContext.pluginContext;
((ethPluginProvideToken_t*)parameter)->pluginContext = (uint8_t*)&dataContext.tokenContext.pluginContext; break;
break; case ETH_PLUGIN_PROVIDE_TOKEN:
case ETH_PLUGIN_QUERY_CONTRACT_ID: ((ethPluginProvideToken_t *) parameter)->pluginSharedRW = &pluginRW;
((ethQueryContractID_t*)parameter)->pluginSharedRW = &pluginRW; ((ethPluginProvideToken_t *) parameter)->pluginSharedRO = &pluginRO;
((ethQueryContractID_t*)parameter)->pluginSharedRO = &pluginRO; ((ethPluginProvideToken_t *) parameter)->pluginContext =
((ethQueryContractID_t*)parameter)->pluginContext = (uint8_t*)&dataContext.tokenContext.pluginContext; (uint8_t *) &dataContext.tokenContext.pluginContext;
break; break;
case ETH_PLUGIN_QUERY_CONTRACT_UI: case ETH_PLUGIN_QUERY_CONTRACT_ID:
((ethQueryContractUI_t*)parameter)->pluginSharedRW = &pluginRW; ((ethQueryContractID_t *) parameter)->pluginSharedRW = &pluginRW;
((ethQueryContractUI_t*)parameter)->pluginSharedRO = &pluginRO; ((ethQueryContractID_t *) parameter)->pluginSharedRO = &pluginRO;
((ethQueryContractUI_t*)parameter)->pluginContext = (uint8_t*)&dataContext.tokenContext.pluginContext; ((ethQueryContractID_t *) parameter)->pluginContext =
break; (uint8_t *) &dataContext.tokenContext.pluginContext;
default: break;
PRINTF("Unknown plugin method %d\n", method); case ETH_PLUGIN_QUERY_CONTRACT_UI:
return 0; ((ethQueryContractUI_t *) parameter)->pluginSharedRW = &pluginRW;
} ((ethQueryContractUI_t *) parameter)->pluginSharedRO = &pluginRO;
((ethQueryContractUI_t *) parameter)->pluginContext =
(uint8_t *) &dataContext.tokenContext.pluginContext;
break;
default:
PRINTF("Unknown plugin method %d\n", method);
return 0;
}
// Perform the call // Perform the call
for (i=0;; i++) { for (i = 0;; i++) {
if (INTERNAL_ETH_PLUGINS[i].alias[0] == 0) { if (INTERNAL_ETH_PLUGINS[i].alias[0] == 0) {
break; break;
} }
if (strcmp(alias, INTERNAL_ETH_PLUGINS[i].alias) == 0) { if (strcmp(alias, INTERNAL_ETH_PLUGINS[i].alias) == 0) {
internalPlugin = 1; internalPlugin = 1;
((PluginCall)PIC(INTERNAL_ETH_PLUGINS[i].impl))(method, parameter); ((PluginCall) PIC(INTERNAL_ETH_PLUGINS[i].impl))(method, parameter);
break; break;
} }
} }
if (!internalPlugin) { if (!internalPlugin) {
uint32_t params[3]; uint32_t params[3];
params[0] = (uint32_t)alias; params[0] = (uint32_t) alias;
params[1] = method; params[1] = method;
params[2] = (uint32_t)parameter; params[2] = (uint32_t) parameter;
BEGIN_TRY { BEGIN_TRY {
TRY { TRY {
os_lib_call(params); os_lib_call(params);
} }
CATCH_OTHER(e) { CATCH_OTHER(e) {
PRINTF("Plugin call exception for %s\n", alias); PRINTF("Plugin call exception for %s\n", alias);
} }
FINALLY { FINALLY {
} }
} }
END_TRY; END_TRY;
} }
// Check the call result // Check the call result
switch(method) { switch (method) {
case ETH_PLUGIN_INIT_CONTRACT: case ETH_PLUGIN_INIT_CONTRACT:
switch (((ethPluginInitContract_t*)parameter)->result) { switch (((ethPluginInitContract_t *) parameter)->result) {
case ETH_PLUGIN_RESULT_OK: case ETH_PLUGIN_RESULT_OK:
if (contractAddress != NULL) { if (contractAddress != NULL) {
strcpy(dataContext.tokenContext.pluginName, alias); strcpy(dataContext.tokenContext.pluginName, alias);
} }
break; break;
case ETH_PLUGIN_RESULT_OK_ALIAS: case ETH_PLUGIN_RESULT_OK_ALIAS:
break; break;
default: default:
return 0; return 0;
} }
break; break;
case ETH_PLUGIN_PROVIDE_PARAMETER: case ETH_PLUGIN_PROVIDE_PARAMETER:
switch (((ethPluginProvideParameter_t*)parameter)->result) { switch (((ethPluginProvideParameter_t *) parameter)->result) {
case ETH_PLUGIN_RESULT_OK: case ETH_PLUGIN_RESULT_OK:
case ETH_PLUGIN_RESULT_FALLBACK: case ETH_PLUGIN_RESULT_FALLBACK:
break; break;
default: default:
return 0; return 0;
} }
break; break;
case ETH_PLUGIN_FINALIZE: case ETH_PLUGIN_FINALIZE:
switch (((ethPluginFinalize_t*)parameter)->result) { switch (((ethPluginFinalize_t *) parameter)->result) {
case ETH_PLUGIN_RESULT_OK: case ETH_PLUGIN_RESULT_OK:
case ETH_PLUGIN_RESULT_FALLBACK: case ETH_PLUGIN_RESULT_FALLBACK:
break; break;
default: default:
return 0; return 0;
} }
break; break;
case ETH_PLUGIN_PROVIDE_TOKEN: case ETH_PLUGIN_PROVIDE_TOKEN:
switch (((ethPluginProvideToken_t*)parameter)->result) { switch (((ethPluginProvideToken_t *) parameter)->result) {
case ETH_PLUGIN_RESULT_OK: case ETH_PLUGIN_RESULT_OK:
case ETH_PLUGIN_RESULT_FALLBACK: case ETH_PLUGIN_RESULT_FALLBACK:
break; break;
default: default:
return 0; return 0;
} }
break; break;
case ETH_PLUGIN_QUERY_CONTRACT_ID: case ETH_PLUGIN_QUERY_CONTRACT_ID:
if (((ethQueryContractID_t*)parameter)->result != ETH_PLUGIN_RESULT_OK) { if (((ethQueryContractID_t *) parameter)->result != ETH_PLUGIN_RESULT_OK) {
return 0; return 0;
} }
break; break;
case ETH_PLUGIN_QUERY_CONTRACT_UI: case ETH_PLUGIN_QUERY_CONTRACT_UI:
if (((ethQueryContractUI_t*)parameter)->result != ETH_PLUGIN_RESULT_OK) { if (((ethQueryContractUI_t *) parameter)->result != ETH_PLUGIN_RESULT_OK) {
return 0; return 0;
} }
break; break;
default: default:
return 0; return 0;
} }
return 1; return 1;
} }

View File

@@ -3,11 +3,24 @@
#include "eth_plugin_interface.h" #include "eth_plugin_interface.h"
void eth_plugin_prepare_init(ethPluginInitContract_t *init, uint8_t *selector, uint32_t dataSize); void eth_plugin_prepare_init(ethPluginInitContract_t *init, uint8_t *selector, uint32_t dataSize);
void eth_plugin_prepare_provide_parameter(ethPluginProvideParameter_t *provideParameter, uint8_t *parameter, uint32_t parameterOffset); void eth_plugin_prepare_provide_parameter(ethPluginProvideParameter_t *provideParameter,
uint8_t *parameter,
uint32_t parameterOffset);
void eth_plugin_prepare_finalize(ethPluginFinalize_t *finalize); void eth_plugin_prepare_finalize(ethPluginFinalize_t *finalize);
void eth_plugin_prepare_provide_token(ethPluginProvideToken_t *provideToken, tokenDefinition_t *token1, tokenDefinition_t *token2); void eth_plugin_prepare_provide_token(ethPluginProvideToken_t *provideToken,
void eth_plugin_prepare_query_contract_ID(ethQueryContractID_t *queryContractID, char *name, uint32_t nameLength, char *version, uint32_t versionLength); tokenDefinition_t *token1,
void eth_plugin_prepare_query_contract_UI(ethQueryContractUI_t *queryContractUI, uint8_t screenIndex, char *title, uint32_t titleLength, char *msg, uint32_t msgLength); tokenDefinition_t *token2);
void eth_plugin_prepare_query_contract_ID(ethQueryContractID_t *queryContractID,
char *name,
uint32_t nameLength,
char *version,
uint32_t versionLength);
void eth_plugin_prepare_query_contract_UI(ethQueryContractUI_t *queryContractUI,
uint8_t screenIndex,
char *title,
uint32_t titleLength,
char *msg,
uint32_t msgLength);
int eth_plugin_perform_init(uint8_t *contractAddress, ethPluginInitContract_t *init); int eth_plugin_perform_init(uint8_t *contractAddress, ethPluginInitContract_t *init);
// NULL for cached address, or base contract address // NULL for cached address, or base contract address
@@ -17,4 +30,3 @@ int compound_plugin_call(uint8_t *contractAddress, int method, void *parameter);
void plugin_ui_start(void); void plugin_ui_start(void);
#endif #endif

View File

@@ -11,100 +11,94 @@
typedef enum { typedef enum {
ETH_PLUGIN_INIT_CONTRACT = 0x0101, ETH_PLUGIN_INIT_CONTRACT = 0x0101,
ETH_PLUGIN_PROVIDE_PARAMETER = 0x0102, ETH_PLUGIN_PROVIDE_PARAMETER = 0x0102,
ETH_PLUGIN_FINALIZE = 0x0103, ETH_PLUGIN_FINALIZE = 0x0103,
ETH_PLUGIN_PROVIDE_TOKEN = 0x0104, ETH_PLUGIN_PROVIDE_TOKEN = 0x0104,
ETH_PLUGIN_QUERY_CONTRACT_ID = 0x0105, ETH_PLUGIN_QUERY_CONTRACT_ID = 0x0105,
ETH_PLUGIN_QUERY_CONTRACT_UI = 0x0106 ETH_PLUGIN_QUERY_CONTRACT_UI = 0x0106
} eth_plugin_msg_t; } eth_plugin_msg_t;
typedef enum { typedef enum {
ETH_PLUGIN_RESULT_ERROR = 0x00, ETH_PLUGIN_RESULT_ERROR = 0x00,
ETH_PLUGIN_RESULT_OK = 0x01, ETH_PLUGIN_RESULT_OK = 0x01,
ETH_PLUGIN_RESULT_OK_ALIAS = 0x02, ETH_PLUGIN_RESULT_OK_ALIAS = 0x02,
ETH_PLUGIN_RESULT_FALLBACK = 0x03 ETH_PLUGIN_RESULT_FALLBACK = 0x03
} eth_plugin_result_t; } eth_plugin_result_t;
typedef enum { typedef enum {
ETH_UI_TYPE_AMOUNT_ADDRESS = 0x01, ETH_UI_TYPE_AMOUNT_ADDRESS = 0x01,
ETH_UI_TYPE_GENERIC = 0x02 ETH_UI_TYPE_GENERIC = 0x02
} eth_ui_type_t; } eth_ui_type_t;
typedef void (*PluginCall)(int, void*); typedef void (*PluginCall)(int, void *);
// Shared objects, read-write // Shared objects, read-write
typedef struct ethPluginSharedRW_t { typedef struct ethPluginSharedRW_t {
cx_sha3_t *sha3;
cx_sha3_t *sha3;
} ethPluginSharedRW_t; } ethPluginSharedRW_t;
// Shared objects, read-only // Shared objects, read-only
typedef struct ethPluginSharedRO_t { typedef struct ethPluginSharedRO_t {
txContent_t *txContent;
txContent_t *txContent;
} ethPluginSharedRO_t; } ethPluginSharedRO_t;
// Init Contract // Init Contract
typedef struct ethPluginInitContract_t { typedef struct ethPluginInitContract_t {
// in
// in ethPluginSharedRW_t *pluginSharedRW;
ethPluginSharedRO_t *pluginSharedRO;
uint8_t *pluginContext;
uint32_t pluginContextLength;
uint8_t *selector; // 4 bytes selector
uint32_t dataSize;
ethPluginSharedRW_t *pluginSharedRW; char *alias; // 29 bytes alias if ETH_PLUGIN_RESULT_OK_ALIAS set
ethPluginSharedRO_t *pluginSharedRO;
uint8_t *pluginContext;
uint32_t pluginContextLength;
uint8_t *selector; // 4 bytes selector
uint32_t dataSize;
char *alias; // 29 bytes alias if ETH_PLUGIN_RESULT_OK_ALIAS set uint8_t result;
uint8_t result;
} ethPluginInitContract_t; } ethPluginInitContract_t;
// Provide parameter // Provide parameter
typedef struct ethPluginProvideParameter_t { typedef struct ethPluginProvideParameter_t {
ethPluginSharedRW_t *pluginSharedRW;
ethPluginSharedRO_t *pluginSharedRO;
uint8_t *pluginContext;
uint8_t *parameter; // 32 bytes parameter
uint32_t parameterOffset;
ethPluginSharedRW_t *pluginSharedRW; uint8_t result;
ethPluginSharedRO_t *pluginSharedRO;
uint8_t *pluginContext;
uint8_t *parameter; // 32 bytes parameter
uint32_t parameterOffset;
uint8_t result;
} ethPluginProvideParameter_t; } ethPluginProvideParameter_t;
// Finalize // Finalize
typedef struct ethPluginFinalize_t { typedef struct ethPluginFinalize_t {
ethPluginSharedRW_t *pluginSharedRW;
ethPluginSharedRO_t *pluginSharedRO;
uint8_t *pluginContext;
ethPluginSharedRW_t *pluginSharedRW; uint8_t *tokenLookup1; // set by the plugin if a token should be looked up
ethPluginSharedRO_t *pluginSharedRO; uint8_t *tokenLookup2;
uint8_t *pluginContext;
uint8_t *tokenLookup1; // set by the plugin if a token should be looked up uint8_t *amount; // set an uint256 pointer if uiType is UI_AMOUNT_ADDRESS
uint8_t *tokenLookup2; uint8_t *address; // set to a 20 bytes address pointer if uiType is UI_AMOUNT_ADDRESS
uint8_t *amount; // set an uint256 pointer if uiType is UI_AMOUNT_ADDRESS uint8_t uiType;
uint8_t *address; // set to a 20 bytes address pointer if uiType is UI_AMOUNT_ADDRESS uint8_t numScreens; // ignored if uiType is UI_AMOUNT_ADDRESS
uint8_t result;
uint8_t uiType;
uint8_t numScreens; // ignored if uiType is UI_AMOUNT_ADDRESS
uint8_t result;
} ethPluginFinalize_t; } ethPluginFinalize_t;
@@ -113,21 +107,20 @@ typedef struct ethPluginFinalize_t {
// if uiType is UI_TYPE_GENERIC, the ETH application provides tokens if requested then prompts // if uiType is UI_TYPE_GENERIC, the ETH application provides tokens if requested then prompts
// for each UI field // for each UI field
// The first field is forced by the ETH app to be the name + version of the plugin handling the request // The first field is forced by the ETH app to be the name + version of the plugin handling the
// The last field is the fee amount // request The last field is the fee amount
// Provide token // Provide token
typedef struct ethPluginProvideToken_t { typedef struct ethPluginProvideToken_t {
ethPluginSharedRW_t *pluginSharedRW;
ethPluginSharedRO_t *pluginSharedRO;
uint8_t *pluginContext;
ethPluginSharedRW_t *pluginSharedRW; tokenDefinition_t *token1; // set by the ETH application, to be saved by the plugin
ethPluginSharedRO_t *pluginSharedRO; tokenDefinition_t *token2;
uint8_t *pluginContext;
tokenDefinition_t *token1; // set by the ETH application, to be saved by the plugin uint8_t result;
tokenDefinition_t *token2;
uint8_t result;
} ethPluginProvideToken_t; } ethPluginProvideToken_t;
@@ -136,36 +129,33 @@ typedef struct ethPluginProvideToken_t {
// This is always called on the non aliased contract // This is always called on the non aliased contract
typedef struct ethQueryContractID_t { typedef struct ethQueryContractID_t {
ethPluginSharedRW_t *pluginSharedRW;
ethPluginSharedRO_t *pluginSharedRO;
uint8_t *pluginContext;
ethPluginSharedRW_t *pluginSharedRW; char *name;
ethPluginSharedRO_t *pluginSharedRO; uint32_t nameLength;
uint8_t *pluginContext; char *version;
uint32_t versionLength;
char *name; uint8_t result;
uint32_t nameLength;
char *version;
uint32_t versionLength;
uint8_t result;
} ethQueryContractID_t; } ethQueryContractID_t;
// Query Contract UI // Query Contract UI
typedef struct ethQueryContractUI_t { typedef struct ethQueryContractUI_t {
ethPluginSharedRW_t *pluginSharedRW;
ethPluginSharedRO_t *pluginSharedRO;
uint8_t *pluginContext;
uint8_t screenIndex;
char *title;
uint32_t titleLength;
char *msg;
uint32_t msgLength;
ethPluginSharedRW_t *pluginSharedRW; uint8_t result;
ethPluginSharedRO_t *pluginSharedRO;
uint8_t *pluginContext;
uint8_t screenIndex;
char *title;
uint32_t titleLength;
char *msg;
uint32_t msgLength;
uint8_t result;
} ethQueryContractUI_t; } ethQueryContractUI_t;
#endif #endif

View File

@@ -3,138 +3,118 @@
bool erc20_plugin_available_check(void); bool erc20_plugin_available_check(void);
bool erc721_plugin_available_check(void); bool erc721_plugin_available_check(void);
void erc20_plugin_call(int message, void *parameters); void erc20_plugin_call(int message, void* parameters);
void erc721_plugin_call(int message, void *parameters); void erc721_plugin_call(int message, void* parameters);
void compound_plugin_call(int message, void *parameters); void compound_plugin_call(int message, void* parameters);
#ifdef HAVE_STARKWARE #ifdef HAVE_STARKWARE
void starkware_plugin_call(int message, void *parameters); void starkware_plugin_call(int message, void* parameters);
#endif #endif
#ifdef HAVE_ETH2 #ifdef HAVE_ETH2
void eth2_plugin_call(int message, void *parameters); void eth2_plugin_call(int message, void* parameters);
#endif #endif
static const uint8_t const ERC20_TRANSFER_SELECTOR[SELECTOR_SIZE] = { 0xa9, 0x05, 0x9c, 0xbb }; static const uint8_t const ERC20_TRANSFER_SELECTOR[SELECTOR_SIZE] = {0xa9, 0x05, 0x9c, 0xbb};
static const uint8_t const ERC20_APPROVE_SELECTOR[SELECTOR_SIZE] = { 0x09, 0x5e, 0xa7, 0xb3 }; static const uint8_t const ERC20_APPROVE_SELECTOR[SELECTOR_SIZE] = {0x09, 0x5e, 0xa7, 0xb3};
const uint8_t* const ERC20_SELECTORS[NUM_ERC20_SELECTORS] = { const uint8_t* const ERC20_SELECTORS[NUM_ERC20_SELECTORS] = {ERC20_TRANSFER_SELECTOR,
ERC20_TRANSFER_SELECTOR, ERC20_APPROVE_SELECTOR ERC20_APPROVE_SELECTOR};
};
static const uint8_t const ERC721_APPROVE_SELECTOR[SELECTOR_SIZE] = {0x09, 0x5e, 0xa7, 0xb3};
static const uint8_t const ERC721_APPROVE_SELECTOR[SELECTOR_SIZE] = { 0x09, 0x5e, 0xa7, 0xb3 }; const uint8_t* const ERC721_SELECTORS[NUM_ERC721_SELECTORS] = {ERC721_APPROVE_SELECTOR};
const uint8_t* const ERC721_SELECTORS[NUM_ERC721_SELECTORS] = { static const uint8_t const COMPOUND_REDEEM_UNDERLYING_SELECTOR[SELECTOR_SIZE] = {0x85,
ERC721_APPROVE_SELECTOR 0x2a,
}; 0x12,
0xe3};
static const uint8_t const COMPOUND_REDEEM_UNDERLYING_SELECTOR[SELECTOR_SIZE] = { 0x85, 0x2a, 0x12, 0xe3 }; static const uint8_t const COMPOUND_REDEEM_SELECTOR[SELECTOR_SIZE] = {0xdb, 0x00, 0x6a, 0x75};
static const uint8_t const COMPOUND_REDEEM_SELECTOR[SELECTOR_SIZE] = { 0xdb, 0x00, 0x6a, 0x75 }; static const uint8_t const COMPOUND_MINT_SELECTOR[SELECTOR_SIZE] = {0xa0, 0x71, 0x2d, 0x68};
static const uint8_t const COMPOUND_MINT_SELECTOR[SELECTOR_SIZE] = { 0xa0, 0x71, 0x2d, 0x68 }; static const uint8_t const CETH_MINT_SELECTOR[SELECTOR_SIZE] = {0x12, 0x49, 0xc5, 0x8b};
static const uint8_t const CETH_MINT_SELECTOR[SELECTOR_SIZE] = { 0x12, 0x49, 0xc5, 0x8b };
const uint8_t* const COMPOUND_SELECTORS[NUM_COMPOUND_SELECTORS] = { const uint8_t* const COMPOUND_SELECTORS[NUM_COMPOUND_SELECTORS] = {
COMPOUND_REDEEM_UNDERLYING_SELECTOR, COMPOUND_REDEEM_SELECTOR, COMPOUND_REDEEM_UNDERLYING_SELECTOR,
COMPOUND_MINT_SELECTOR, CETH_MINT_SELECTOR COMPOUND_REDEEM_SELECTOR,
}; COMPOUND_MINT_SELECTOR,
CETH_MINT_SELECTOR};
#ifdef HAVE_ETH2 #ifdef HAVE_ETH2
static const uint8_t const ETH2_DEPOSIT_SELECTOR[SELECTOR_SIZE] = { 0x22, 0x89, 0x51, 0x18 }; static const uint8_t const ETH2_DEPOSIT_SELECTOR[SELECTOR_SIZE] = {0x22, 0x89, 0x51, 0x18};
const uint8_t* const ETH2_SELECTORS[NUM_ETH2_SELECTORS] = { const uint8_t* const ETH2_SELECTORS[NUM_ETH2_SELECTORS] = {ETH2_DEPOSIT_SELECTOR};
ETH2_DEPOSIT_SELECTOR
};
#endif #endif
#ifdef HAVE_STARKWARE #ifdef HAVE_STARKWARE
static const uint8_t const STARKWARE_REGISTER_ID[SELECTOR_SIZE] = { 0xdd, 0x24, 0x14, 0xd4 }; static const uint8_t const STARKWARE_REGISTER_ID[SELECTOR_SIZE] = {0xdd, 0x24, 0x14, 0xd4};
static const uint8_t const STARKWARE_DEPOSIT_TOKEN_ID[SELECTOR_SIZE] = { 0x25, 0x05, 0xc3, 0xd9 }; static const uint8_t const STARKWARE_DEPOSIT_TOKEN_ID[SELECTOR_SIZE] = {0x25, 0x05, 0xc3, 0xd9};
static const uint8_t const STARKWARE_DEPOSIT_ETH_ID[SELECTOR_SIZE] = { 0x00, 0xae, 0xef, 0x8a }; static const uint8_t const STARKWARE_DEPOSIT_ETH_ID[SELECTOR_SIZE] = {0x00, 0xae, 0xef, 0x8a};
static const uint8_t const STARKWARE_DEPOSIT_CANCEL_ID[SELECTOR_SIZE] = { 0x7d, 0xf7, 0xdc, 0x04 }; static const uint8_t const STARKWARE_DEPOSIT_CANCEL_ID[SELECTOR_SIZE] = {0x7d, 0xf7, 0xdc, 0x04};
static const uint8_t const STARKWARE_DEPOSIT_RECLAIM_ID[SELECTOR_SIZE] = { 0xae, 0x87, 0x38, 0x16 }; static const uint8_t const STARKWARE_DEPOSIT_RECLAIM_ID[SELECTOR_SIZE] = {0xae, 0x87, 0x38, 0x16};
static const uint8_t const STARKWARE_WITHDRAW_ID[SELECTOR_SIZE] = { 0x44, 0x1a, 0x3e, 0x70 }; static const uint8_t const STARKWARE_WITHDRAW_ID[SELECTOR_SIZE] = {0x44, 0x1a, 0x3e, 0x70};
static const uint8_t const STARKWARE_FULL_WITHDRAWAL_ID[SELECTOR_SIZE] = { 0xa9, 0x33, 0x10, 0xc4 }; static const uint8_t const STARKWARE_FULL_WITHDRAWAL_ID[SELECTOR_SIZE] = {0xa9, 0x33, 0x10, 0xc4};
static const uint8_t const STARKWARE_FREEZE_ID[SELECTOR_SIZE] = { 0x93, 0xc1, 0xe4, 0x66 }; static const uint8_t const STARKWARE_FREEZE_ID[SELECTOR_SIZE] = {0x93, 0xc1, 0xe4, 0x66};
static const uint8_t const STARKWARE_ESCAPE_ID[SELECTOR_SIZE] = { 0x9e, 0x3a, 0xda, 0xc4 }; static const uint8_t const STARKWARE_ESCAPE_ID[SELECTOR_SIZE] = {0x9e, 0x3a, 0xda, 0xc4};
static const uint8_t const STARKWARE_VERIFY_ESCAPE_ID[SELECTOR_SIZE] = { 0x2d, 0xd5, 0x30, 0x06 }; static const uint8_t const STARKWARE_VERIFY_ESCAPE_ID[SELECTOR_SIZE] = {0x2d, 0xd5, 0x30, 0x06};
static const uint8_t const STARKWARE_WITHDRAW_TO_ID[SELECTOR_SIZE] = { 0x14, 0xcd, 0x70, 0xe4 };
static const uint8_t const STARKWARE_DEPOSIT_NFT_ID[SELECTOR_SIZE] = { 0xae, 0x1c, 0xdd, 0xe6 };
static const uint8_t const STARKWARE_DEPOSIT_NFT_RECLAIM_ID[SELECTOR_SIZE] = { 0xfc, 0xb0, 0x58, 0x22 };
static const uint8_t const STARKWARE_WITHDRAW_AND_MINT_ID[SELECTOR_SIZE] = { 0xd9, 0x14, 0x43, 0xb7 };
static const uint8_t const STARKWARE_WITHDRAW_NFT_ID[SELECTOR_SIZE] = { 0x01, 0x9b, 0x41, 0x7a };
static const uint8_t const STARKWARE_WITHDRAW_NFT_TO_ID[SELECTOR_SIZE] = { 0xeb, 0xef, 0x0f, 0xd0 };
static const uint8_t const STARKWARE_WITHDRAW_TO_ID[SELECTOR_SIZE] = {0x14, 0xcd, 0x70, 0xe4};
static const uint8_t const STARKWARE_DEPOSIT_NFT_ID[SELECTOR_SIZE] = {0xae, 0x1c, 0xdd, 0xe6};
static const uint8_t const STARKWARE_DEPOSIT_NFT_RECLAIM_ID[SELECTOR_SIZE] = {0xfc,
0xb0,
0x58,
0x22};
static const uint8_t const STARKWARE_WITHDRAW_AND_MINT_ID[SELECTOR_SIZE] = {0xd9, 0x14, 0x43, 0xb7};
static const uint8_t const STARKWARE_WITHDRAW_NFT_ID[SELECTOR_SIZE] = {0x01, 0x9b, 0x41, 0x7a};
static const uint8_t const STARKWARE_WITHDRAW_NFT_TO_ID[SELECTOR_SIZE] = {0xeb, 0xef, 0x0f, 0xd0};
const uint8_t* const STARKWARE_SELECTORS[NUM_STARKWARE_SELECTORS] = { const uint8_t* const STARKWARE_SELECTORS[NUM_STARKWARE_SELECTORS] = {
STARKWARE_REGISTER_ID, STARKWARE_DEPOSIT_TOKEN_ID, STARKWARE_DEPOSIT_ETH_ID, STARKWARE_REGISTER_ID,
STARKWARE_DEPOSIT_CANCEL_ID, STARKWARE_DEPOSIT_RECLAIM_ID, STARKWARE_WITHDRAW_ID, STARKWARE_DEPOSIT_TOKEN_ID,
STARKWARE_FULL_WITHDRAWAL_ID, STARKWARE_FREEZE_ID, STARKWARE_ESCAPE_ID, STARKWARE_DEPOSIT_ETH_ID,
STARKWARE_VERIFY_ESCAPE_ID, STARKWARE_WITHDRAW_TO_ID, STARKWARE_DEPOSIT_NFT_ID, STARKWARE_DEPOSIT_CANCEL_ID,
STARKWARE_DEPOSIT_NFT_RECLAIM_ID, STARKWARE_WITHDRAW_AND_MINT_ID, STARKWARE_WITHDRAW_NFT_ID, STARKWARE_DEPOSIT_RECLAIM_ID,
STARKWARE_WITHDRAW_NFT_TO_ID STARKWARE_WITHDRAW_ID,
}; STARKWARE_FULL_WITHDRAWAL_ID,
STARKWARE_FREEZE_ID,
STARKWARE_ESCAPE_ID,
STARKWARE_VERIFY_ESCAPE_ID,
STARKWARE_WITHDRAW_TO_ID,
STARKWARE_DEPOSIT_NFT_ID,
STARKWARE_DEPOSIT_NFT_RECLAIM_ID,
STARKWARE_WITHDRAW_AND_MINT_ID,
STARKWARE_WITHDRAW_NFT_ID,
STARKWARE_WITHDRAW_NFT_TO_ID};
#endif #endif
// All internal alias names start with 'minus' // All internal alias names start with 'minus'
const internalEthPlugin_t const INTERNAL_ETH_PLUGINS[] = { const internalEthPlugin_t const INTERNAL_ETH_PLUGINS[] = {
{ {erc20_plugin_available_check,
erc20_plugin_available_check, ERC20_SELECTORS,
ERC20_SELECTORS, NUM_ERC20_SELECTORS,
NUM_ERC20_SELECTORS, "-erc20",
"-erc20", erc20_plugin_call},
erc20_plugin_call
},
{ {erc721_plugin_available_check,
erc721_plugin_available_check, ERC721_SELECTORS,
ERC721_SELECTORS, NUM_ERC721_SELECTORS,
NUM_ERC721_SELECTORS, "-er721",
"-er721", erc721_plugin_call},
erc721_plugin_call
},
{ {NULL, COMPOUND_SELECTORS, NUM_COMPOUND_SELECTORS, "-cmpd", compound_plugin_call},
NULL,
COMPOUND_SELECTORS,
NUM_COMPOUND_SELECTORS,
"-cmpd",
compound_plugin_call
},
#ifdef HAVE_ETH2 #ifdef HAVE_ETH2
{ {NULL, ETH2_SELECTORS, NUM_ETH2_SELECTORS, "-eth2", eth2_plugin_call},
NULL,
ETH2_SELECTORS,
NUM_ETH2_SELECTORS,
"-eth2",
eth2_plugin_call
},
#endif #endif
#ifdef HAVE_STARKWARE #ifdef HAVE_STARKWARE
{ {NULL, STARKWARE_SELECTORS, 10, "-strk", starkware_plugin_call},
NULL,
STARKWARE_SELECTORS,
10,
"-strk",
starkware_plugin_call
},
#endif #endif
{ {NULL, NULL, 0, "", NULL}};
NULL,
NULL,
0,
"",
NULL
}
};

View File

@@ -7,11 +7,11 @@
typedef bool (*PluginAvailableCheck)(void); typedef bool (*PluginAvailableCheck)(void);
typedef struct internalEthPlugin_t { typedef struct internalEthPlugin_t {
PluginAvailableCheck availableCheck; PluginAvailableCheck availableCheck;
const uint8_t **selectors; const uint8_t** selectors;
uint8_t num_selectors; uint8_t num_selectors;
char alias[7]; char alias[7];
PluginCall impl; PluginCall impl;
} internalEthPlugin_t; } internalEthPlugin_t;
#define NUM_ERC20_SELECTORS 2 #define NUM_ERC20_SELECTORS 2

View File

@@ -7,86 +7,94 @@
typedef enum { typedef enum {
PLUGIN_UI_INSIDE = 0, PLUGIN_UI_INSIDE = 0,
PLUGIN_UI_OUTSIDE PLUGIN_UI_OUTSIDE
} plugin_ui_state_t; } plugin_ui_state_t;
void computeFees(char *displayBuffer, uint32_t displayBufferSize); void computeFees(char *displayBuffer, uint32_t displayBufferSize);
void plugin_ui_get_id() { void plugin_ui_get_id() {
ethQueryContractID_t pluginQueryContractID; ethQueryContractID_t pluginQueryContractID;
eth_plugin_prepare_query_contract_ID(&pluginQueryContractID, strings.tmp.tmp, sizeof(strings.tmp.tmp), strings.tmp.tmp2, sizeof(strings.tmp.tmp2)); eth_plugin_prepare_query_contract_ID(&pluginQueryContractID,
// Query the original contract for ID if it's not an internal alias strings.tmp.tmp,
if (!eth_plugin_call( sizeof(strings.tmp.tmp),
(dataContext.tokenContext.pluginName[0] == '-' ? NULL : tmpContent.txContent.destination), strings.tmp.tmp2,
ETH_PLUGIN_QUERY_CONTRACT_ID, (void*)&pluginQueryContractID)) { sizeof(strings.tmp.tmp2));
PRINTF("Plugin query contract ID call failed\n"); // Query the original contract for ID if it's not an internal alias
io_seproxyhal_touch_tx_cancel(NULL); if (!eth_plugin_call(
} (dataContext.tokenContext.pluginName[0] == '-' ? NULL
: tmpContent.txContent.destination),
ETH_PLUGIN_QUERY_CONTRACT_ID,
(void *) &pluginQueryContractID)) {
PRINTF("Plugin query contract ID call failed\n");
io_seproxyhal_touch_tx_cancel(NULL);
}
} }
void plugin_ui_get_item() { void plugin_ui_get_item() {
ethQueryContractUI_t pluginQueryContractUI; ethQueryContractUI_t pluginQueryContractUI;
eth_plugin_prepare_query_contract_UI(&pluginQueryContractUI, dataContext.tokenContext.pluginUiCurrentItem, strings.tmp.tmp, sizeof(strings.tmp.tmp), strings.tmp.tmp2, sizeof(strings.tmp.tmp2)); eth_plugin_prepare_query_contract_UI(&pluginQueryContractUI,
if (!eth_plugin_call(NULL, ETH_PLUGIN_QUERY_CONTRACT_UI, (void*)&pluginQueryContractUI)) { dataContext.tokenContext.pluginUiCurrentItem,
PRINTF("Plugin query contract UI call failed\n"); strings.tmp.tmp,
io_seproxyhal_touch_tx_cancel(NULL); sizeof(strings.tmp.tmp),
} strings.tmp.tmp2,
sizeof(strings.tmp.tmp2));
if (!eth_plugin_call(NULL, ETH_PLUGIN_QUERY_CONTRACT_UI, (void *) &pluginQueryContractUI)) {
PRINTF("Plugin query contract UI call failed\n");
io_seproxyhal_touch_tx_cancel(NULL);
}
} }
void display_next_plugin_item(bool entering) { void display_next_plugin_item(bool entering) {
if (entering) { if (entering) {
if (dataContext.tokenContext.pluginUiState == PLUGIN_UI_OUTSIDE) { if (dataContext.tokenContext.pluginUiState == PLUGIN_UI_OUTSIDE) {
dataContext.tokenContext.pluginUiState = PLUGIN_UI_INSIDE; dataContext.tokenContext.pluginUiState = PLUGIN_UI_INSIDE;
dataContext.tokenContext.pluginUiCurrentItem = 0; dataContext.tokenContext.pluginUiCurrentItem = 0;
plugin_ui_get_item(); plugin_ui_get_item();
ux_flow_next(); ux_flow_next();
} else {
if (dataContext.tokenContext.pluginUiCurrentItem > 0) {
dataContext.tokenContext.pluginUiCurrentItem--;
plugin_ui_get_item();
ux_flow_next();
} else {
dataContext.tokenContext.pluginUiState = PLUGIN_UI_OUTSIDE;
dataContext.tokenContext.pluginUiCurrentItem = 0;
ux_flow_prev();
}
}
} else {
if (dataContext.tokenContext.pluginUiState == PLUGIN_UI_OUTSIDE) {
dataContext.tokenContext.pluginUiState = PLUGIN_UI_INSIDE;
plugin_ui_get_item();
ux_flow_prev();
} else {
if (dataContext.tokenContext.pluginUiCurrentItem <
dataContext.tokenContext.pluginUiMaxItems - 1) {
dataContext.tokenContext.pluginUiCurrentItem++;
plugin_ui_get_item();
ux_flow_prev();
// Reset multi page layout to the first page
G_ux.layout_paging.current = 0;
#ifdef TARGET_NANOS
ux_layout_paging_redisplay(G_ux.stack_count - 1);
#else
ux_layout_bnnn_paging_redisplay(0);
#endif
} else {
dataContext.tokenContext.pluginUiState = PLUGIN_UI_OUTSIDE;
ux_flow_next();
}
}
} }
else {
if (dataContext.tokenContext.pluginUiCurrentItem > 0) {
dataContext.tokenContext.pluginUiCurrentItem--;
plugin_ui_get_item();
ux_flow_next();
}
else {
dataContext.tokenContext.pluginUiState = PLUGIN_UI_OUTSIDE;
dataContext.tokenContext.pluginUiCurrentItem = 0;
ux_flow_prev();
}
}
}
else {
if (dataContext.tokenContext.pluginUiState == PLUGIN_UI_OUTSIDE) {
dataContext.tokenContext.pluginUiState = PLUGIN_UI_INSIDE;
plugin_ui_get_item();
ux_flow_prev();
}
else {
if (dataContext.tokenContext.pluginUiCurrentItem < dataContext.tokenContext.pluginUiMaxItems - 1) {
dataContext.tokenContext.pluginUiCurrentItem++;
plugin_ui_get_item();
ux_flow_prev();
// Reset multi page layout to the first page
G_ux.layout_paging.current = 0;
#ifdef TARGET_NANOS
ux_layout_paging_redisplay(G_ux.stack_count-1);
#else
ux_layout_bnnn_paging_redisplay(0);
#endif
}
else {
dataContext.tokenContext.pluginUiState = PLUGIN_UI_OUTSIDE;
ux_flow_next();
}
}
}
} }
void plugin_ui_compute_fees() { void plugin_ui_compute_fees() {
computeFees(strings.common.maxFee, sizeof(strings.common.maxFee)); computeFees(strings.common.maxFee, sizeof(strings.common.maxFee));
} }
// clang-format off
UX_FLOW_DEF_NOCB( UX_FLOW_DEF_NOCB(
ux_plugin_approval_intro_step, ux_plugin_approval_intro_step,
pnn, pnn,
@@ -155,21 +163,20 @@ UX_FLOW_DEF_VALID(
&C_icon_crossmark, &C_icon_crossmark,
"Reject", "Reject",
}); });
// clang-format on
UX_FLOW( UX_FLOW(ux_plugin_approval_flow,
ux_plugin_approval_flow, &ux_plugin_approval_intro_step,
&ux_plugin_approval_intro_step, &ux_plugin_approval_id_step,
&ux_plugin_approval_id_step, &ux_plugin_approval_before_step,
&ux_plugin_approval_before_step, &ux_plugin_approval_display_step,
&ux_plugin_approval_display_step, &ux_plugin_approval_after_step,
&ux_plugin_approval_after_step, &ux_plugin_approval_fees_step,
&ux_plugin_approval_fees_step, &ux_plugin_approval_ok_step,
&ux_plugin_approval_ok_step, &ux_plugin_approval_cancel_step);
&ux_plugin_approval_cancel_step
);
void plugin_ui_start() { void plugin_ui_start() {
dataContext.tokenContext.pluginUiState = PLUGIN_UI_OUTSIDE; dataContext.tokenContext.pluginUiState = PLUGIN_UI_OUTSIDE;
dataContext.tokenContext.pluginUiCurrentItem = 0; dataContext.tokenContext.pluginUiCurrentItem = 0;
ux_flow_init(0, ux_plugin_approval_flow, NULL); ux_flow_init(0, ux_plugin_approval_flow, NULL);
} }

View File

@@ -7,8 +7,8 @@
#define ZERO(x) memset(x, 0, sizeof(x)) #define ZERO(x) memset(x, 0, sizeof(x))
void handle_check_address(check_address_parameters_t* params, chain_config_t* chain_config) { void handle_check_address(check_address_parameters_t* params, chain_config_t* chain_config) {
PRINTF("Params on the address %d\n",(unsigned int)params); PRINTF("Params on the address %d\n", (unsigned int) params);
PRINTF("Address to check %s\n",params->address_to_check); PRINTF("Address to check %s\n", params->address_to_check);
PRINTF("Inside handle_check_address\n"); PRINTF("Inside handle_check_address\n");
params->result = 0; params->result = 0;
if (params->address_to_check == 0) { if (params->address_to_check == 0) {
@@ -17,27 +17,23 @@ void handle_check_address(check_address_parameters_t* params, chain_config_t* ch
} }
uint8_t i; uint8_t i;
uint8_t *bip32_path_ptr = params->address_parameters; uint8_t* bip32_path_ptr = params->address_parameters;
uint8_t bip32PathLength = *(bip32_path_ptr++); uint8_t bip32PathLength = *(bip32_path_ptr++);
cx_sha3_t local_sha3; cx_sha3_t local_sha3;
// Common memory is used for locals that are not used concurrently // Common memory is used for locals that are not used concurrently
union group1 union group1 {
{
uint32_t bip32Path[MAX_BIP32_PATH]; uint32_t bip32Path[MAX_BIP32_PATH];
cx_ecfp_private_key_t privateKey; cx_ecfp_private_key_t privateKey;
char address[51]; char address[51];
} locals_union1; } locals_union1;
union group2 union group2 {
{
uint8_t privateKeyData[32]; uint8_t privateKeyData[32];
cx_ecfp_public_key_t publicKey; cx_ecfp_public_key_t publicKey;
} locals_union2; } locals_union2;
if ((bip32PathLength < 0x01) || (bip32PathLength > MAX_BIP32_PATH) ||
if ((bip32PathLength < 0x01) || (bip32PathLength * 4 != params->address_parameters_length - 1)) {
(bip32PathLength > MAX_BIP32_PATH) ||
(bip32PathLength*4 != params->address_parameters_length - 1)) {
PRINTF("Invalid path\n"); PRINTF("Invalid path\n");
return; return;
} }
@@ -45,22 +41,34 @@ void handle_check_address(check_address_parameters_t* params, chain_config_t* ch
locals_union1.bip32Path[i] = U4BE(bip32_path_ptr, 0); locals_union1.bip32Path[i] = U4BE(bip32_path_ptr, 0);
bip32_path_ptr += 4; bip32_path_ptr += 4;
} }
os_perso_derive_node_bip32(CX_CURVE_256K1, locals_union1.bip32Path, bip32PathLength, locals_union2.privateKeyData, NULL); os_perso_derive_node_bip32(CX_CURVE_256K1,
locals_union1.bip32Path,
bip32PathLength,
locals_union2.privateKeyData,
NULL);
ZERO(&locals_union1); ZERO(&locals_union1);
cx_ecfp_init_private_key(CX_CURVE_256K1, locals_union2.privateKeyData, 32, &locals_union1.privateKey); cx_ecfp_init_private_key(CX_CURVE_256K1,
locals_union2.privateKeyData,
32,
&locals_union1.privateKey);
ZERO(&locals_union2); ZERO(&locals_union2);
cx_ecfp_generate_pair(CX_CURVE_256K1, &locals_union2.publicKey, &locals_union1.privateKey, 1); cx_ecfp_generate_pair(CX_CURVE_256K1, &locals_union2.publicKey, &locals_union1.privateKey, 1);
ZERO(&locals_union1); ZERO(&locals_union1);
getEthAddressStringFromKey(&locals_union2.publicKey, (uint8_t*)locals_union1.address, &local_sha3, chain_config); getEthAddressStringFromKey(&locals_union2.publicKey,
(uint8_t*) locals_union1.address,
&local_sha3,
chain_config);
ZERO(&locals_union2); ZERO(&locals_union2);
uint8_t offset_0x = 0; uint8_t offset_0x = 0;
if(memcmp(params->address_to_check, "0x", 2) == 0){ if (memcmp(params->address_to_check, "0x", 2) == 0) {
offset_0x = 2; offset_0x = 2;
} }
if ((strlen(locals_union1.address) != strlen(params->address_to_check + offset_0x)) || if ((strlen(locals_union1.address) != strlen(params->address_to_check + offset_0x)) ||
memcmp(locals_union1.address, params->address_to_check + offset_0x, strlen(locals_union1.address)) != 0) { memcmp(locals_union1.address,
params->address_to_check + offset_0x,
strlen(locals_union1.address)) != 0) {
PRINTF("Addresses doesn't match\n"); PRINTF("Addresses doesn't match\n");
return; return;
} }

View File

@@ -4,6 +4,7 @@
#include "swap_lib_calls.h" #include "swap_lib_calls.h"
#include "chainConfig.h" #include "chainConfig.h"
void handle_check_address(check_address_parameters_t* check_address_params, chain_config_t* chain_config); void handle_check_address(check_address_parameters_t* check_address_params,
chain_config_t* chain_config);
#endif // _HANDLE_CHECK_ADDRESS_H_ #endif // _HANDLE_CHECK_ADDRESS_H_

View File

@@ -6,8 +6,8 @@
#include "string.h" #include "string.h"
#include <stdint.h> #include <stdint.h>
void handle_get_printable_amount(get_printable_amount_parameters_t* params,
void handle_get_printable_amount( get_printable_amount_parameters_t* params, chain_config_t *config) { chain_config_t* config) {
uint8_t decimals; uint8_t decimals;
char ticker[MAX_TICKER_LEN]; char ticker[MAX_TICKER_LEN];
memset(params->printable_amount, 0, sizeof(params->printable_amount)); memset(params->printable_amount, 0, sizeof(params->printable_amount));
@@ -15,19 +15,27 @@ void handle_get_printable_amount( get_printable_amount_parameters_t* params, cha
PRINTF("Amount is too big, 32 bytes max but buffer has %u bytes", params->amount_length); PRINTF("Amount is too big, 32 bytes max but buffer has %u bytes", params->amount_length);
os_lib_end(); os_lib_end();
} }
if(!parse_swap_config(params->coin_configuration, params->coin_configuration_length, ticker, &decimals)){ if (!parse_swap_config(params->coin_configuration,
params->coin_configuration_length,
ticker,
&decimals)) {
PRINTF("Error while parsing config\n"); PRINTF("Error while parsing config\n");
os_lib_end(); os_lib_end();
} }
// If the amount is a fee, its value is nominated in ETH even if we're doing an ERC20 swap // If the amount is a fee, its value is nominated in ETH even if we're doing an ERC20 swap
if(params->is_fee){ if (params->is_fee) {
uint8_t ticker_len = strnlen(config->coinName, sizeof(config->coinName)); uint8_t ticker_len = strnlen(config->coinName, sizeof(config->coinName));
memcpy(ticker, config->coinName, ticker_len); memcpy(ticker, config->coinName, ticker_len);
ticker[ticker_len] = ' '; ticker[ticker_len] = ' ';
ticker[ticker_len+1] = '\0'; ticker[ticker_len + 1] = '\0';
decimals = WEI_TO_ETHER; decimals = WEI_TO_ETHER;
} }
amountToString(params->amount, params->amount_length, decimals, ticker, params->printable_amount, sizeof(params->printable_amount)); amountToString(params->amount,
params->amount_length,
decimals,
ticker,
params->printable_amount,
sizeof(params->printable_amount));
} }

View File

@@ -4,6 +4,7 @@
#include "swap_lib_calls.h" #include "swap_lib_calls.h"
#include "chainConfig.h" #include "chainConfig.h"
void handle_get_printable_amount(get_printable_amount_parameters_t* get_printable_amount_params, chain_config_t *config); void handle_get_printable_amount(get_printable_amount_parameters_t* get_printable_amount_params,
chain_config_t* config);
#endif // _HANDLE_GET_PRINTABLE_AMOUNT_H_ #endif // _HANDLE_GET_PRINTABLE_AMOUNT_H_

View File

@@ -4,13 +4,15 @@
#include "shared_context.h" #include "shared_context.h"
#include "utils.h" #include "utils.h"
void copy_transaction_parameters(create_transaction_parameters_t* sign_transaction_params,
void copy_transaction_parameters(create_transaction_parameters_t* sign_transaction_params, chain_config_t *config) { chain_config_t* config) {
// first copy parameters to stack, and then to global data. // first copy parameters to stack, and then to global data.
// We need this "trick" as the input data position can overlap with app-ethereum globals // We need this "trick" as the input data position can overlap with app-ethereum globals
txStringProperties_t stack_data; txStringProperties_t stack_data;
memset(&stack_data, 0, sizeof(stack_data)); memset(&stack_data, 0, sizeof(stack_data));
strncpy(stack_data.fullAddress, sign_transaction_params->destination_address, sizeof(stack_data.fullAddress)); strncpy(stack_data.fullAddress,
sign_transaction_params->destination_address,
sizeof(stack_data.fullAddress));
if ((stack_data.fullAddress[sizeof(stack_data.fullAddress) - 1] != '\0') || if ((stack_data.fullAddress[sizeof(stack_data.fullAddress) - 1] != '\0') ||
(sign_transaction_params->amount_length > 32) || (sign_transaction_params->amount_length > 32) ||
(sign_transaction_params->fee_amount_length > 8)) { (sign_transaction_params->fee_amount_length > 8)) {
@@ -19,21 +21,35 @@ void copy_transaction_parameters(create_transaction_parameters_t* sign_transacti
uint8_t decimals; uint8_t decimals;
char ticker[MAX_TICKER_LEN]; char ticker[MAX_TICKER_LEN];
if(!parse_swap_config(sign_transaction_params->coin_configuration, sign_transaction_params->coin_configuration_length, ticker, &decimals)){ if (!parse_swap_config(sign_transaction_params->coin_configuration,
sign_transaction_params->coin_configuration_length,
ticker,
&decimals)) {
PRINTF("Error while parsing config\n"); PRINTF("Error while parsing config\n");
os_lib_end(); os_lib_end();
} }
amountToString(sign_transaction_params->amount, sign_transaction_params->amount_length, decimals, ticker, stack_data.fullAmount, sizeof(stack_data.fullAmount)); amountToString(sign_transaction_params->amount,
sign_transaction_params->amount_length,
decimals,
ticker,
stack_data.fullAmount,
sizeof(stack_data.fullAmount));
// If the amount is a fee, its value is nominated in ETH even if we're doing an ERC20 swap // If the amount is a fee, its value is nominated in ETH even if we're doing an ERC20 swap
strcpy(ticker, config->coinName); strcpy(ticker, config->coinName);
decimals = WEI_TO_ETHER; decimals = WEI_TO_ETHER;
amountToString(sign_transaction_params->fee_amount, sign_transaction_params->fee_amount_length, decimals, ticker, stack_data.maxFee, sizeof(stack_data.maxFee)); amountToString(sign_transaction_params->fee_amount,
sign_transaction_params->fee_amount_length,
decimals,
ticker,
stack_data.maxFee,
sizeof(stack_data.maxFee));
memcpy(&strings.common, &stack_data, sizeof(stack_data)); memcpy(&strings.common, &stack_data, sizeof(stack_data));
} }
void handle_swap_sign_transaction(create_transaction_parameters_t* sign_transaction_params, chain_config_t *config) { void handle_swap_sign_transaction(create_transaction_parameters_t* sign_transaction_params,
chain_config_t* config) {
copy_transaction_parameters(sign_transaction_params, config); copy_transaction_parameters(sign_transaction_params, config);
chainConfig = config; chainConfig = config;
reset_app_context(); reset_app_context();
@@ -41,25 +57,25 @@ void handle_swap_sign_transaction(create_transaction_parameters_t* sign_transact
io_seproxyhal_init(); io_seproxyhal_init();
if (N_storage.initialized != 0x01) { if (N_storage.initialized != 0x01) {
internalStorage_t storage; internalStorage_t storage;
storage.dataAllowed = 0x00; storage.dataAllowed = 0x00;
storage.contractDetails = 0x00; storage.contractDetails = 0x00;
storage.initialized = 0x01; storage.initialized = 0x01;
nvm_write((void*)&N_storage, (void*)&storage, sizeof(internalStorage_t)); nvm_write((void*) &N_storage, (void*) &storage, sizeof(internalStorage_t));
} }
UX_INIT(); UX_INIT();
USB_power(0); USB_power(0);
USB_power(1); USB_power(1);
//ui_idle(); // ui_idle();
PRINTF("USB power ON/OFF\n"); PRINTF("USB power ON/OFF\n");
#ifdef TARGET_NANOX #ifdef TARGET_NANOX
// grab the current plane mode setting // grab the current plane mode setting
G_io_app.plane_mode = os_setting_get(OS_SETTING_PLANEMODE, NULL, 0); G_io_app.plane_mode = os_setting_get(OS_SETTING_PLANEMODE, NULL, 0);
#endif // TARGET_NANOX #endif // TARGET_NANOX
#ifdef HAVE_BLE #ifdef HAVE_BLE
BLE_power(0, NULL); BLE_power(0, NULL);
BLE_power(1, "Nano X"); BLE_power(1, "Nano X");
#endif // HAVE_BLE #endif // HAVE_BLE
app_main(); app_main();
} }

View File

@@ -4,6 +4,7 @@
#include "swap_lib_calls.h" #include "swap_lib_calls.h"
#include "chainConfig.h" #include "chainConfig.h"
void handle_swap_sign_transaction(create_transaction_parameters_t* get_printable_amount_params, chain_config_t *config); void handle_swap_sign_transaction(create_transaction_parameters_t* get_printable_amount_params,
chain_config_t* config);
#endif // _HANDLE_SWAP_SIGN_TRANSACTION_H_ #endif // _HANDLE_SWAP_SIGN_TRANSACTION_H_

View File

@@ -1,19 +1,19 @@
/******************************************************************************* /*******************************************************************************
* Ledger Ethereum App * Ledger Ethereum App
* (c) 2016-2019 Ledger * (c) 2016-2019 Ledger
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
********************************************************************************/ ********************************************************************************/
#include "shared_context.h" #include "shared_context.h"
#include "apdu_constants.h" #include "apdu_constants.h"
@@ -67,23 +67,23 @@ const internalStorage_t N_storage_real;
chain_config_t *chainConfig; chain_config_t *chainConfig;
void reset_app_context() { void reset_app_context() {
//PRINTF("!!RESET_APP_CONTEXT\n"); // PRINTF("!!RESET_APP_CONTEXT\n");
appState = APP_STATE_IDLE; appState = APP_STATE_IDLE;
memset(tmpCtx.transactionContext.tokenSet, 0, MAX_TOKEN); memset(tmpCtx.transactionContext.tokenSet, 0, MAX_TOKEN);
called_from_swap = false; called_from_swap = false;
#ifdef HAVE_STARKWARE #ifdef HAVE_STARKWARE
quantumSet = false; quantumSet = false;
#endif #endif
#ifdef HAVE_ETH2 #ifdef HAVE_ETH2
eth2WithdrawalIndex = 0; eth2WithdrawalIndex = 0;
#endif #endif
memset((uint8_t*)&txContext, 0, sizeof(txContext)); memset((uint8_t *) &txContext, 0, sizeof(txContext));
memset((uint8_t*)&tmpContent, 0, sizeof(tmpContent)); memset((uint8_t *) &tmpContent, 0, sizeof(tmpContent));
} }
void ui_idle(void) { void ui_idle(void) {
// reserve a display stack slot if none yet // reserve a display stack slot if none yet
if(G_ux.stack_count == 0) { if (G_ux.stack_count == 0) {
ux_stack_push(); ux_stack_push();
} }
ux_flow_init(0, ux_idle_flow, NULL); ux_flow_init(0, ux_idle_flow, NULL);
@@ -92,24 +92,24 @@ void ui_idle(void) {
unsigned int io_seproxyhal_touch_exit(const bagl_element_t *e) { unsigned int io_seproxyhal_touch_exit(const bagl_element_t *e) {
// Go back to the dashboard // Go back to the dashboard
os_sched_exit(0); os_sched_exit(0);
return 0; // do not redraw the widget return 0; // do not redraw the widget
} }
#if defined(TARGET_NANOS) #if defined(TARGET_NANOS)
unsigned int ui_address_nanos_button(unsigned int button_mask, unsigned int button_mask_counter) { unsigned int ui_address_nanos_button(unsigned int button_mask, unsigned int button_mask_counter) {
switch(button_mask) { switch (button_mask) {
case BUTTON_EVT_RELEASED|BUTTON_LEFT: // CANCEL case BUTTON_EVT_RELEASED | BUTTON_LEFT: // CANCEL
io_seproxyhal_touch_address_cancel(NULL); io_seproxyhal_touch_address_cancel(NULL);
break; break;
case BUTTON_EVT_RELEASED|BUTTON_RIGHT: { // OK case BUTTON_EVT_RELEASED | BUTTON_RIGHT: { // OK
io_seproxyhal_touch_address_ok(NULL); io_seproxyhal_touch_address_ok(NULL);
break; break;
} }
} }
return 0; return 0;
} }
#endif // #if defined(TARGET_NANOS) #endif // #if defined(TARGET_NANOS)
void io_seproxyhal_send_status(uint32_t sw) { void io_seproxyhal_send_status(uint32_t sw) {
G_io_apdu_buffer[0] = ((sw >> 8) & 0xff); G_io_apdu_buffer[0] = ((sw >> 8) & 0xff);
@@ -117,60 +117,59 @@ void io_seproxyhal_send_status(uint32_t sw) {
io_exchange(CHANNEL_APDU | IO_RETURN_AFTER_TX, 2); io_exchange(CHANNEL_APDU | IO_RETURN_AFTER_TX, 2);
} }
void format_signature_out(const uint8_t* signature) { void format_signature_out(const uint8_t *signature) {
memset(G_io_apdu_buffer + 1, 0x00, 64); memset(G_io_apdu_buffer + 1, 0x00, 64);
uint8_t offset = 1; uint8_t offset = 1;
uint8_t xoffset = 4; //point to r value uint8_t xoffset = 4; // point to r value
//copy r // copy r
uint8_t xlength = signature[xoffset-1]; uint8_t xlength = signature[xoffset - 1];
if (xlength == 33) { if (xlength == 33) {
xlength = 32; xlength = 32;
xoffset ++; xoffset++;
} }
memmove(G_io_apdu_buffer+offset+32-xlength, signature+xoffset, xlength); memmove(G_io_apdu_buffer + offset + 32 - xlength, signature + xoffset, xlength);
offset += 32; offset += 32;
xoffset += xlength +2; //move over rvalue and TagLEn xoffset += xlength + 2; // move over rvalue and TagLEn
//copy s value // copy s value
xlength = signature[xoffset-1]; xlength = signature[xoffset - 1];
if (xlength == 33) { if (xlength == 33) {
xlength = 32; xlength = 32;
xoffset ++; xoffset++;
} }
memmove(G_io_apdu_buffer+offset+32-xlength, signature+xoffset, xlength); memmove(G_io_apdu_buffer + offset + 32 - xlength, signature + xoffset, xlength);
} }
unsigned short io_exchange_al(unsigned char channel, unsigned short tx_len) { unsigned short io_exchange_al(unsigned char channel, unsigned short tx_len) {
switch (channel & ~(IO_FLAGS)) { switch (channel & ~(IO_FLAGS)) {
case CHANNEL_KEYBOARD: case CHANNEL_KEYBOARD:
break; break;
// multiplexed io exchange over a SPI channel and TLV encapsulated protocol // multiplexed io exchange over a SPI channel and TLV encapsulated protocol
case CHANNEL_SPI: case CHANNEL_SPI:
if (tx_len) { if (tx_len) {
io_seproxyhal_spi_send(G_io_apdu_buffer, tx_len); io_seproxyhal_spi_send(G_io_apdu_buffer, tx_len);
if (channel & IO_RESET_AFTER_REPLIED) { if (channel & IO_RESET_AFTER_REPLIED) {
reset(); reset();
}
return 0; // nothing received from the master so far (it's a tx
// transaction)
} else {
return io_seproxyhal_spi_recv(G_io_apdu_buffer, sizeof(G_io_apdu_buffer), 0);
} }
return 0; // nothing received from the master so far (it's a tx
// transaction)
} else {
return io_seproxyhal_spi_recv(G_io_apdu_buffer,
sizeof(G_io_apdu_buffer), 0);
}
default: default:
THROW(INVALID_PARAMETER); THROW(INVALID_PARAMETER);
} }
return 0; return 0;
} }
tokenDefinition_t* getKnownToken(uint8_t *contractAddress) { tokenDefinition_t *getKnownToken(uint8_t *contractAddress) {
tokenDefinition_t *currentToken = NULL; tokenDefinition_t *currentToken = NULL;
#ifdef HAVE_TOKENS_LIST #ifdef HAVE_TOKENS_LIST
uint32_t numTokens = 0; uint32_t numTokens = 0;
uint32_t i; uint32_t i;
switch(chainConfig->kind) { switch (chainConfig->kind) {
case CHAIN_KIND_AKROMA: case CHAIN_KIND_AKROMA:
numTokens = NUM_TOKENS_AKROMA; numTokens = NUM_TOKENS_AKROMA;
break; break;
@@ -262,97 +261,97 @@ tokenDefinition_t* getKnownToken(uint8_t *contractAddress) {
numTokens = NUM_TOKENS_THUNDERCORE; numTokens = NUM_TOKENS_THUNDERCORE;
break; break;
} }
for (i=0; i<numTokens; i++) { for (i = 0; i < numTokens; i++) {
switch(chainConfig->kind) { switch (chainConfig->kind) {
case CHAIN_KIND_AKROMA: case CHAIN_KIND_AKROMA:
currentToken = (tokenDefinition_t *)PIC(&TOKENS_AKROMA[i]); currentToken = (tokenDefinition_t *) PIC(&TOKENS_AKROMA[i]);
break; break;
case CHAIN_KIND_ETHEREUM: case CHAIN_KIND_ETHEREUM:
currentToken = (tokenDefinition_t *)PIC(&TOKENS_ETHEREUM[i]); currentToken = (tokenDefinition_t *) PIC(&TOKENS_ETHEREUM[i]);
break; break;
case CHAIN_KIND_ETHEREUM_CLASSIC: case CHAIN_KIND_ETHEREUM_CLASSIC:
currentToken = (tokenDefinition_t *)PIC(&TOKENS_ETHEREUM_CLASSIC[i]); currentToken = (tokenDefinition_t *) PIC(&TOKENS_ETHEREUM_CLASSIC[i]);
break; break;
case CHAIN_KIND_PIRL: case CHAIN_KIND_PIRL:
currentToken = (tokenDefinition_t *)PIC(&TOKENS_PIRL[i]); currentToken = (tokenDefinition_t *) PIC(&TOKENS_PIRL[i]);
break; break;
case CHAIN_KIND_POA: case CHAIN_KIND_POA:
currentToken = (tokenDefinition_t *)PIC(&TOKENS_POA[i]); currentToken = (tokenDefinition_t *) PIC(&TOKENS_POA[i]);
break; break;
case CHAIN_KIND_ARTIS_SIGMA1: case CHAIN_KIND_ARTIS_SIGMA1:
currentToken = (tokenDefinition_t *)PIC(&TOKENS_ARTIS_SIGMA1[i]); currentToken = (tokenDefinition_t *) PIC(&TOKENS_ARTIS_SIGMA1[i]);
break; break;
case CHAIN_KIND_ARTIS_TAU1: case CHAIN_KIND_ARTIS_TAU1:
currentToken = (tokenDefinition_t *)PIC(&TOKENS_ARTIS_TAU1[i]); currentToken = (tokenDefinition_t *) PIC(&TOKENS_ARTIS_TAU1[i]);
break; break;
case CHAIN_KIND_RSK: case CHAIN_KIND_RSK:
currentToken = (tokenDefinition_t *)PIC(&TOKENS_RSK[i]); currentToken = (tokenDefinition_t *) PIC(&TOKENS_RSK[i]);
break; break;
case CHAIN_KIND_EXPANSE: case CHAIN_KIND_EXPANSE:
currentToken = (tokenDefinition_t *)PIC(&TOKENS_EXPANSE[i]); currentToken = (tokenDefinition_t *) PIC(&TOKENS_EXPANSE[i]);
break; break;
case CHAIN_KIND_UBIQ: case CHAIN_KIND_UBIQ:
currentToken = (tokenDefinition_t *)PIC(&TOKENS_UBIQ[i]); currentToken = (tokenDefinition_t *) PIC(&TOKENS_UBIQ[i]);
break; break;
case CHAIN_KIND_WANCHAIN: case CHAIN_KIND_WANCHAIN:
currentToken = (tokenDefinition_t *)PIC(&TOKENS_WANCHAIN[i]); currentToken = (tokenDefinition_t *) PIC(&TOKENS_WANCHAIN[i]);
break; break;
case CHAIN_KIND_KUSD: case CHAIN_KIND_KUSD:
currentToken = (tokenDefinition_t *)PIC(&TOKENS_KUSD[i]); currentToken = (tokenDefinition_t *) PIC(&TOKENS_KUSD[i]);
break; break;
case CHAIN_KIND_MUSICOIN: case CHAIN_KIND_MUSICOIN:
currentToken = (tokenDefinition_t *)PIC(&TOKENS_MUSICOIN[i]); currentToken = (tokenDefinition_t *) PIC(&TOKENS_MUSICOIN[i]);
break; break;
case CHAIN_KIND_CALLISTO: case CHAIN_KIND_CALLISTO:
currentToken = (tokenDefinition_t *)PIC(&TOKENS_CALLISTO[i]); currentToken = (tokenDefinition_t *) PIC(&TOKENS_CALLISTO[i]);
break; break;
case CHAIN_KIND_ETHERSOCIAL: case CHAIN_KIND_ETHERSOCIAL:
currentToken = (tokenDefinition_t *)PIC(&TOKENS_ETHERSOCIAL[i]); currentToken = (tokenDefinition_t *) PIC(&TOKENS_ETHERSOCIAL[i]);
break; break;
case CHAIN_KIND_ELLAISM: case CHAIN_KIND_ELLAISM:
currentToken = (tokenDefinition_t *)PIC(&TOKENS_ELLAISM[i]); currentToken = (tokenDefinition_t *) PIC(&TOKENS_ELLAISM[i]);
break; break;
case CHAIN_KIND_ETHER1: case CHAIN_KIND_ETHER1:
currentToken = (tokenDefinition_t *)PIC(&TOKENS_ETHER1[i]); currentToken = (tokenDefinition_t *) PIC(&TOKENS_ETHER1[i]);
break; break;
case CHAIN_KIND_ETHERGEM: case CHAIN_KIND_ETHERGEM:
currentToken = (tokenDefinition_t *)PIC(&TOKENS_ETHERGEM[i]); currentToken = (tokenDefinition_t *) PIC(&TOKENS_ETHERGEM[i]);
break; break;
case CHAIN_KIND_ATHEIOS: case CHAIN_KIND_ATHEIOS:
currentToken = (tokenDefinition_t *)PIC(&TOKENS_ATHEIOS[i]); currentToken = (tokenDefinition_t *) PIC(&TOKENS_ATHEIOS[i]);
break; break;
case CHAIN_KIND_GOCHAIN: case CHAIN_KIND_GOCHAIN:
currentToken = (tokenDefinition_t *)PIC(&TOKENS_GOCHAIN[i]); currentToken = (tokenDefinition_t *) PIC(&TOKENS_GOCHAIN[i]);
break; break;
case CHAIN_KIND_MIX: case CHAIN_KIND_MIX:
currentToken = (tokenDefinition_t *)PIC(&TOKENS_MIX[i]); currentToken = (tokenDefinition_t *) PIC(&TOKENS_MIX[i]);
break; break;
case CHAIN_KIND_REOSC: case CHAIN_KIND_REOSC:
currentToken = (tokenDefinition_t *)PIC(&TOKENS_REOSC[i]); currentToken = (tokenDefinition_t *) PIC(&TOKENS_REOSC[i]);
break; break;
case CHAIN_KIND_HPB: case CHAIN_KIND_HPB:
currentToken = (tokenDefinition_t *)PIC(&TOKENS_HPB[i]); currentToken = (tokenDefinition_t *) PIC(&TOKENS_HPB[i]);
break; break;
case CHAIN_KIND_TOMOCHAIN: case CHAIN_KIND_TOMOCHAIN:
currentToken = (tokenDefinition_t *)PIC(&TOKENS_TOMOCHAIN[i]); currentToken = (tokenDefinition_t *) PIC(&TOKENS_TOMOCHAIN[i]);
break; break;
case CHAIN_KIND_TOBALABA: case CHAIN_KIND_TOBALABA:
currentToken = (tokenDefinition_t *)PIC(&TOKENS_TOBALABA[i]); currentToken = (tokenDefinition_t *) PIC(&TOKENS_TOBALABA[i]);
break; break;
case CHAIN_KIND_DEXON: case CHAIN_KIND_DEXON:
currentToken = (tokenDefinition_t *)PIC(&TOKENS_DEXON[i]); currentToken = (tokenDefinition_t *) PIC(&TOKENS_DEXON[i]);
break; break;
case CHAIN_KIND_VOLTA: case CHAIN_KIND_VOLTA:
currentToken = (tokenDefinition_t *)PIC(&TOKENS_VOLTA[i]); currentToken = (tokenDefinition_t *) PIC(&TOKENS_VOLTA[i]);
break; break;
case CHAIN_KIND_EWC: case CHAIN_KIND_EWC:
currentToken = (tokenDefinition_t *)PIC(&TOKENS_EWC[i]); currentToken = (tokenDefinition_t *) PIC(&TOKENS_EWC[i]);
break; break;
case CHAIN_KIND_WEBCHAIN: case CHAIN_KIND_WEBCHAIN:
currentToken = (tokenDefinition_t *)PIC(&TOKENS_WEBCHAIN[i]); currentToken = (tokenDefinition_t *) PIC(&TOKENS_WEBCHAIN[i]);
break; break;
case CHAIN_KIND_THUNDERCORE: case CHAIN_KIND_THUNDERCORE:
currentToken = (tokenDefinition_t *)PIC(&TOKENS_THUNDERCORE[i]); currentToken = (tokenDefinition_t *) PIC(&TOKENS_THUNDERCORE[i]);
break break
} }
if (memcmp(currentToken->address, tmpContent.txContent.destination, 20) == 0) { if (memcmp(currentToken->address, tmpContent.txContent.destination, 20) == 0) {
@@ -360,91 +359,151 @@ tokenDefinition_t* getKnownToken(uint8_t *contractAddress) {
} }
} }
#endif #endif
for(size_t i=0; i<MAX_TOKEN; i++){ for (size_t i = 0; i < MAX_TOKEN; i++) {
currentToken = &tmpCtx.transactionContext.tokens[i]; currentToken = &tmpCtx.transactionContext.tokens[i];
if (tmpCtx.transactionContext.tokenSet[i] && (memcmp(currentToken->address, contractAddress, 20) == 0)) { if (tmpCtx.transactionContext.tokenSet[i] &&
PRINTF("Token found at index %d\n", i); (memcmp(currentToken->address, contractAddress, 20) == 0)) {
return currentToken; PRINTF("Token found at index %d\n", i);
} return currentToken;
}
} }
return NULL; return NULL;
} }
void handleApdu(unsigned int *flags, unsigned int *tx) { void handleApdu(unsigned int *flags, unsigned int *tx) {
unsigned short sw = 0; unsigned short sw = 0;
BEGIN_TRY {
TRY {
BEGIN_TRY {
TRY {
#ifdef HAVE_STARKWARE #ifdef HAVE_STARKWARE
if (G_io_apdu_buffer[OFFSET_CLA] == STARKWARE_CLA) { if (G_io_apdu_buffer[OFFSET_CLA] == STARKWARE_CLA) {
switch(G_io_apdu_buffer[OFFSET_INS]) { switch (G_io_apdu_buffer[OFFSET_INS]) {
case STARKWARE_INS_GET_PUBLIC_KEY: case STARKWARE_INS_GET_PUBLIC_KEY:
handleStarkwareGetPublicKey(G_io_apdu_buffer[OFFSET_P1], G_io_apdu_buffer[OFFSET_P2], G_io_apdu_buffer + OFFSET_CDATA, G_io_apdu_buffer[OFFSET_LC], flags, tx); handleStarkwareGetPublicKey(G_io_apdu_buffer[OFFSET_P1],
break; G_io_apdu_buffer[OFFSET_P2],
case STARKWARE_INS_SIGN_MESSAGE: G_io_apdu_buffer + OFFSET_CDATA,
handleStarkwareSignMessage(G_io_apdu_buffer[OFFSET_P1], G_io_apdu_buffer[OFFSET_P2], G_io_apdu_buffer + OFFSET_CDATA, G_io_apdu_buffer[OFFSET_LC], flags, tx); G_io_apdu_buffer[OFFSET_LC],
break; flags,
case STARKWARE_INS_PROVIDE_QUANTUM: tx);
handleStarkwareProvideQuantum(G_io_apdu_buffer[OFFSET_P1], G_io_apdu_buffer[OFFSET_P2], G_io_apdu_buffer + OFFSET_CDATA, G_io_apdu_buffer[OFFSET_LC], flags, tx); break;
break; case STARKWARE_INS_SIGN_MESSAGE:
case STARKWARE_INS_UNSAFE_SIGN: handleStarkwareSignMessage(G_io_apdu_buffer[OFFSET_P1],
handleStarkwareUnsafeSign(G_io_apdu_buffer[OFFSET_P1], G_io_apdu_buffer[OFFSET_P2], G_io_apdu_buffer + OFFSET_CDATA, G_io_apdu_buffer[OFFSET_LC], flags, tx); G_io_apdu_buffer[OFFSET_P2],
break; G_io_apdu_buffer + OFFSET_CDATA,
default: G_io_apdu_buffer[OFFSET_LC],
THROW(0x6D00); flags,
break; tx);
} break;
CLOSE_TRY; case STARKWARE_INS_PROVIDE_QUANTUM:
return; handleStarkwareProvideQuantum(G_io_apdu_buffer[OFFSET_P1],
} G_io_apdu_buffer[OFFSET_P2],
G_io_apdu_buffer + OFFSET_CDATA,
G_io_apdu_buffer[OFFSET_LC],
flags,
tx);
break;
case STARKWARE_INS_UNSAFE_SIGN:
handleStarkwareUnsafeSign(G_io_apdu_buffer[OFFSET_P1],
G_io_apdu_buffer[OFFSET_P2],
G_io_apdu_buffer + OFFSET_CDATA,
G_io_apdu_buffer[OFFSET_LC],
flags,
tx);
break;
default:
THROW(0x6D00);
break;
}
CLOSE_TRY;
return;
}
#endif #endif
if (G_io_apdu_buffer[OFFSET_CLA] != CLA) { if (G_io_apdu_buffer[OFFSET_CLA] != CLA) {
THROW(0x6E00); THROW(0x6E00);
} }
switch (G_io_apdu_buffer[OFFSET_INS]) { switch (G_io_apdu_buffer[OFFSET_INS]) {
case INS_GET_PUBLIC_KEY: case INS_GET_PUBLIC_KEY:
memset(tmpCtx.transactionContext.tokenSet, 0, MAX_TOKEN); memset(tmpCtx.transactionContext.tokenSet, 0, MAX_TOKEN);
handleGetPublicKey(G_io_apdu_buffer[OFFSET_P1], G_io_apdu_buffer[OFFSET_P2], G_io_apdu_buffer + OFFSET_CDATA, G_io_apdu_buffer[OFFSET_LC], flags, tx); handleGetPublicKey(G_io_apdu_buffer[OFFSET_P1],
break; G_io_apdu_buffer[OFFSET_P2],
G_io_apdu_buffer + OFFSET_CDATA,
G_io_apdu_buffer[OFFSET_LC],
flags,
tx);
break;
case INS_PROVIDE_ERC20_TOKEN_INFORMATION: case INS_PROVIDE_ERC20_TOKEN_INFORMATION:
handleProvideErc20TokenInformation(G_io_apdu_buffer[OFFSET_P1], G_io_apdu_buffer[OFFSET_P2], G_io_apdu_buffer + OFFSET_CDATA, G_io_apdu_buffer[OFFSET_LC], flags, tx); handleProvideErc20TokenInformation(G_io_apdu_buffer[OFFSET_P1],
break; G_io_apdu_buffer[OFFSET_P2],
G_io_apdu_buffer + OFFSET_CDATA,
G_io_apdu_buffer[OFFSET_LC],
flags,
tx);
break;
case INS_SIGN: case INS_SIGN:
handleSign(G_io_apdu_buffer[OFFSET_P1], G_io_apdu_buffer[OFFSET_P2], G_io_apdu_buffer + OFFSET_CDATA, G_io_apdu_buffer[OFFSET_LC], flags, tx); handleSign(G_io_apdu_buffer[OFFSET_P1],
break; G_io_apdu_buffer[OFFSET_P2],
G_io_apdu_buffer + OFFSET_CDATA,
G_io_apdu_buffer[OFFSET_LC],
flags,
tx);
break;
case INS_GET_APP_CONFIGURATION: case INS_GET_APP_CONFIGURATION:
handleGetAppConfiguration(G_io_apdu_buffer[OFFSET_P1], G_io_apdu_buffer[OFFSET_P2], G_io_apdu_buffer + OFFSET_CDATA, G_io_apdu_buffer[OFFSET_LC], flags, tx); handleGetAppConfiguration(G_io_apdu_buffer[OFFSET_P1],
break; G_io_apdu_buffer[OFFSET_P2],
G_io_apdu_buffer + OFFSET_CDATA,
G_io_apdu_buffer[OFFSET_LC],
flags,
tx);
break;
case INS_SIGN_PERSONAL_MESSAGE: case INS_SIGN_PERSONAL_MESSAGE:
memset(tmpCtx.transactionContext.tokenSet, 0, MAX_TOKEN); memset(tmpCtx.transactionContext.tokenSet, 0, MAX_TOKEN);
handleSignPersonalMessage(G_io_apdu_buffer[OFFSET_P1], G_io_apdu_buffer[OFFSET_P2], G_io_apdu_buffer + OFFSET_CDATA, G_io_apdu_buffer[OFFSET_LC], flags, tx); handleSignPersonalMessage(G_io_apdu_buffer[OFFSET_P1],
break; G_io_apdu_buffer[OFFSET_P2],
G_io_apdu_buffer + OFFSET_CDATA,
G_io_apdu_buffer[OFFSET_LC],
flags,
tx);
break;
case INS_SIGN_EIP_712_MESSAGE: case INS_SIGN_EIP_712_MESSAGE:
memset(tmpCtx.transactionContext.tokenSet, 0, MAX_TOKEN); memset(tmpCtx.transactionContext.tokenSet, 0, MAX_TOKEN);
handleSignEIP712Message(G_io_apdu_buffer[OFFSET_P1], G_io_apdu_buffer[OFFSET_P2], G_io_apdu_buffer + OFFSET_CDATA, G_io_apdu_buffer[OFFSET_LC], flags, tx); handleSignEIP712Message(G_io_apdu_buffer[OFFSET_P1],
break; G_io_apdu_buffer[OFFSET_P2],
G_io_apdu_buffer + OFFSET_CDATA,
G_io_apdu_buffer[OFFSET_LC],
flags,
tx);
break;
#ifdef HAVE_ETH2 #ifdef HAVE_ETH2
case INS_GET_ETH2_PUBLIC_KEY: case INS_GET_ETH2_PUBLIC_KEY:
memset(tmpCtx.transactionContext.tokenSet, 0, MAX_TOKEN); memset(tmpCtx.transactionContext.tokenSet, 0, MAX_TOKEN);
handleGetEth2PublicKey(G_io_apdu_buffer[OFFSET_P1], G_io_apdu_buffer[OFFSET_P2], G_io_apdu_buffer + OFFSET_CDATA, G_io_apdu_buffer[OFFSET_LC], flags, tx); handleGetEth2PublicKey(G_io_apdu_buffer[OFFSET_P1],
break; G_io_apdu_buffer[OFFSET_P2],
G_io_apdu_buffer + OFFSET_CDATA,
G_io_apdu_buffer[OFFSET_LC],
flags,
tx);
break;
case INS_SET_ETH2_WITHDRAWAL_INDEX: case INS_SET_ETH2_WITHDRAWAL_INDEX:
handleSetEth2WithdrawalIndex(G_io_apdu_buffer[OFFSET_P1], G_io_apdu_buffer[OFFSET_P2], G_io_apdu_buffer + OFFSET_CDATA, G_io_apdu_buffer[OFFSET_LC], flags, tx); handleSetEth2WithdrawalIndex(G_io_apdu_buffer[OFFSET_P1],
break; G_io_apdu_buffer[OFFSET_P2],
G_io_apdu_buffer + OFFSET_CDATA,
G_io_apdu_buffer[OFFSET_LC],
flags,
tx);
break;
#endif #endif
@@ -453,40 +512,40 @@ void handleApdu(unsigned int *flags, unsigned int *tx) {
goto return_to_dashboard; goto return_to_dashboard;
#endif #endif
default: default:
THROW(0x6D00); THROW(0x6D00);
break; break;
} }
}
CATCH(EXCEPTION_IO_RESET) {
THROW(EXCEPTION_IO_RESET);
}
CATCH_OTHER(e) {
switch (e & 0xF000) {
case 0x6000:
// Wipe the transaction context and report the exception
sw = e;
reset_app_context();
break;
case 0x9000:
// All is well
sw = e;
break;
default:
// Internal error
sw = 0x6800 | (e & 0x7FF);
reset_app_context();
break;
} }
// Unexpected exception => report CATCH(EXCEPTION_IO_RESET) {
G_io_apdu_buffer[*tx] = sw >> 8; THROW(EXCEPTION_IO_RESET);
G_io_apdu_buffer[*tx + 1] = sw; }
*tx += 2; CATCH_OTHER(e) {
} switch (e & 0xF000) {
FINALLY { case 0x6000:
} // Wipe the transaction context and report the exception
} sw = e;
END_TRY; reset_app_context();
break;
case 0x9000:
// All is well
sw = e;
break;
default:
// Internal error
sw = 0x6800 | (e & 0x7FF);
reset_app_context();
break;
}
// Unexpected exception => report
G_io_apdu_buffer[*tx] = sw >> 8;
G_io_apdu_buffer[*tx + 1] = sw;
*tx += 2;
}
FINALLY {
}
}
END_TRY;
} }
void app_main(void) { void app_main(void) {
@@ -506,8 +565,8 @@ void app_main(void) {
BEGIN_TRY { BEGIN_TRY {
TRY { TRY {
rx = tx; rx = tx;
tx = 0; // ensure no race in catch_other if io_exchange throws tx = 0; // ensure no race in catch_other if io_exchange throws
// an error // an error
rx = io_exchange(CHANNEL_APDU | flags, rx); rx = io_exchange(CHANNEL_APDU | flags, rx);
flags = 0; flags = 0;
@@ -525,20 +584,20 @@ void app_main(void) {
} }
CATCH_OTHER(e) { CATCH_OTHER(e) {
switch (e & 0xF000) { switch (e & 0xF000) {
case 0x6000: case 0x6000:
// Wipe the transaction context and report the exception // Wipe the transaction context and report the exception
sw = e; sw = e;
reset_app_context(); reset_app_context();
break; break;
case 0x9000: case 0x9000:
// All is well // All is well
sw = e; sw = e;
break; break;
default: default:
// Internal error // Internal error
sw = 0x6800 | (e & 0x7FF); sw = 0x6800 | (e & 0x7FF);
reset_app_context(); reset_app_context();
break; break;
} }
if (e != 0x9000) { if (e != 0x9000) {
flags &= ~IO_ASYNCH_REPLY; flags &= ~IO_ASYNCH_REPLY;
@@ -554,13 +613,13 @@ void app_main(void) {
END_TRY; END_TRY;
} }
//return_to_dashboard: // return_to_dashboard:
return; return;
} }
// override point, but nothing more to do // override point, but nothing more to do
void io_seproxyhal_display(const bagl_element_t *element) { void io_seproxyhal_display(const bagl_element_t *element) {
io_seproxyhal_display_default((bagl_element_t *)element); io_seproxyhal_display_default((bagl_element_t *) element);
} }
unsigned char io_event(unsigned char channel) { unsigned char io_event(unsigned char channel) {
@@ -569,26 +628,28 @@ unsigned char io_event(unsigned char channel) {
// can't have more than one tag in the reply, not supported yet. // can't have more than one tag in the reply, not supported yet.
switch (G_io_seproxyhal_spi_buffer[0]) { switch (G_io_seproxyhal_spi_buffer[0]) {
case SEPROXYHAL_TAG_FINGER_EVENT: case SEPROXYHAL_TAG_FINGER_EVENT:
UX_FINGER_EVENT(G_io_seproxyhal_spi_buffer); UX_FINGER_EVENT(G_io_seproxyhal_spi_buffer);
break; break;
case SEPROXYHAL_TAG_BUTTON_PUSH_EVENT: case SEPROXYHAL_TAG_BUTTON_PUSH_EVENT:
UX_BUTTON_PUSH_EVENT(G_io_seproxyhal_spi_buffer); UX_BUTTON_PUSH_EVENT(G_io_seproxyhal_spi_buffer);
break; break;
case SEPROXYHAL_TAG_STATUS_EVENT: case SEPROXYHAL_TAG_STATUS_EVENT:
if (G_io_apdu_media == IO_APDU_MEDIA_USB_HID && !(U4BE(G_io_seproxyhal_spi_buffer, 3) & SEPROXYHAL_TAG_STATUS_EVENT_FLAG_USB_POWERED)) { if (G_io_apdu_media == IO_APDU_MEDIA_USB_HID &&
THROW(EXCEPTION_IO_RESET); !(U4BE(G_io_seproxyhal_spi_buffer, 3) &
} SEPROXYHAL_TAG_STATUS_EVENT_FLAG_USB_POWERED)) {
// no break is intentional THROW(EXCEPTION_IO_RESET);
default: }
UX_DEFAULT_EVENT(); // no break is intentional
break; default:
UX_DEFAULT_EVENT();
break;
case SEPROXYHAL_TAG_DISPLAY_PROCESSED_EVENT: case SEPROXYHAL_TAG_DISPLAY_PROCESSED_EVENT:
UX_DISPLAYED_EVENT({}); UX_DISPLAYED_EVENT({});
break; break;
#if 0 #if 0
case SEPROXYHAL_TAG_TICKER_EVENT: case SEPROXYHAL_TAG_TICKER_EVENT:
@@ -609,21 +670,17 @@ unsigned char io_event(unsigned char channel) {
} }
void app_exit() { void app_exit() {
BEGIN_TRY_L(exit) { BEGIN_TRY_L(exit) {
TRY_L(exit) { TRY_L(exit) {
os_sched_exit(-1); os_sched_exit(-1);
} }
FINALLY_L(exit) { FINALLY_L(exit) {
} }
} }
END_TRY_L(exit); END_TRY_L(exit);
} }
void coin_main_with_config(chain_config_t *config) { void coin_main_with_config(chain_config_t *config) {
chainConfig = config; chainConfig = config;
reset_app_context(); reset_app_context();
tmpCtx.transactionContext.currentTokenIndex = 0; tmpCtx.transactionContext.currentTokenIndex = 0;
@@ -638,14 +695,14 @@ void coin_main_with_config(chain_config_t *config) {
#ifdef TARGET_NANOX #ifdef TARGET_NANOX
// grab the current plane mode setting // grab the current plane mode setting
G_io_app.plane_mode = os_setting_get(OS_SETTING_PLANEMODE, NULL, 0); G_io_app.plane_mode = os_setting_get(OS_SETTING_PLANEMODE, NULL, 0);
#endif // TARGET_NANOX #endif // TARGET_NANOX
if (N_storage.initialized != 0x01) { if (N_storage.initialized != 0x01) {
internalStorage_t storage; internalStorage_t storage;
storage.dataAllowed = 0x00; storage.dataAllowed = 0x00;
storage.contractDetails = 0x00; storage.contractDetails = 0x00;
storage.initialized = 0x01; storage.initialized = 0x01;
nvm_write((void*)&N_storage, (void*)&storage, sizeof(internalStorage_t)); nvm_write((void *) &N_storage, (void *) &storage, sizeof(internalStorage_t));
} }
USB_power(0); USB_power(0);
@@ -656,7 +713,7 @@ void coin_main_with_config(chain_config_t *config) {
#ifdef HAVE_BLE #ifdef HAVE_BLE
BLE_power(0, NULL); BLE_power(0, NULL);
BLE_power(1, "Nano X"); BLE_power(1, "Nano X");
#endif // HAVE_BLE #endif // HAVE_BLE
app_main(); app_main();
} }
@@ -690,30 +747,37 @@ void coin_main() {
coin_main_with_config(&coin_config); coin_main_with_config(&coin_config);
} }
void library_main_with_config(chain_config_t *config, unsigned int command, unsigned int* call_parameters) { void library_main_with_config(chain_config_t *config,
unsigned int command,
unsigned int *call_parameters) {
BEGIN_TRY { BEGIN_TRY {
TRY { TRY {
check_api_level(CX_COMPAT_APILEVEL); check_api_level(CX_COMPAT_APILEVEL);
PRINTF("Inside a library \n"); PRINTF("Inside a library \n");
switch (command) { switch (command) {
case CHECK_ADDRESS: case CHECK_ADDRESS:
handle_check_address((check_address_parameters_t*)call_parameters, config); handle_check_address((check_address_parameters_t *) call_parameters, config);
break; break;
case SIGN_TRANSACTION: case SIGN_TRANSACTION:
handle_swap_sign_transaction((create_transaction_parameters_t*)call_parameters, config); handle_swap_sign_transaction(
break; (create_transaction_parameters_t *) call_parameters,
config);
break;
case GET_PRINTABLE_AMOUNT: case GET_PRINTABLE_AMOUNT:
handle_get_printable_amount((get_printable_amount_parameters_t*)call_parameters, config); handle_get_printable_amount(
break; (get_printable_amount_parameters_t *) call_parameters,
config);
break;
} }
os_lib_end(); os_lib_end();
} }
FINALLY {} FINALLY {
}
} }
END_TRY; END_TRY;
} }
void library_main(unsigned int call_id, unsigned int* call_parameters) { void library_main(unsigned int call_id, unsigned int *call_parameters) {
chain_config_t coin_config; chain_config_t coin_config;
init_coin_config(&coin_config); init_coin_config(&coin_config);
library_main_with_config(&coin_config, call_id, call_parameters); library_main_with_config(&coin_config, call_id, call_parameters);
@@ -736,22 +800,22 @@ __attribute__((section(".boot"))) int main(int arg0) {
libcall_params[4] = 0; libcall_params[4] = 0;
if (arg0) { if (arg0) {
// call as a library // call as a library
libcall_params[2] = ((unsigned int *)arg0)[1]; libcall_params[2] = ((unsigned int *) arg0)[1];
libcall_params[4] = ((unsigned int *)arg0)[3]; // library arguments libcall_params[4] = ((unsigned int *) arg0)[3]; // library arguments
os_lib_call(&libcall_params); os_lib_call(&libcall_params);
((unsigned int *)arg0)[0] = libcall_params[1]; ((unsigned int *) arg0)[0] = libcall_params[1];
os_lib_end(); os_lib_end();
} } else {
else {
// launch coin application // launch coin application
libcall_params[1] = 0x100; // use the Init call, as we won't exit libcall_params[1] = 0x100; // use the Init call, as we won't exit
os_lib_call(&libcall_params); os_lib_call(&libcall_params);
} }
} }
FINALLY {} FINALLY {
}
} }
END_TRY; END_TRY;
// no return // no return
#else #else
// exit critical section // exit critical section
__asm volatile("cpsie i"); __asm volatile("cpsie i");
@@ -765,12 +829,12 @@ __attribute__((section(".boot"))) int main(int arg0) {
return 0; return 0;
} }
if (((unsigned int *)arg0)[0] != 0x100) { if (((unsigned int *) arg0)[0] != 0x100) {
app_exit(); app_exit();
return 0; return 0;
} }
unsigned int command = ((unsigned int *)arg0)[1]; unsigned int command = ((unsigned int *) arg0)[1];
chain_config_t * chain_config = ((unsigned int *)arg0)[2]; chain_config_t *chain_config = ((unsigned int *) arg0)[2];
switch (command) { switch (command) {
case RUN_APPLICATION: case RUN_APPLICATION:
// coin application launched from dashboard // coin application launched from dashboard
@@ -778,25 +842,18 @@ __attribute__((section(".boot"))) int main(int arg0) {
app_exit(); app_exit();
else else
coin_main_with_config(chain_config); coin_main_with_config(chain_config);
break; break;
default: default:
if (chain_config == NULL) if (chain_config == NULL)
// Called as standalone eth library // Called as standalone eth library
library_main(command, ((unsigned int *)arg0)[3]);// called as bitcoin library library_main(command, ((unsigned int *) arg0)[3]); // called as bitcoin library
else else
// Called as a library from an altcoin // Called as a library from an altcoin
library_main_with_config(chain_config, command, ((unsigned int *)arg0)[3]);// called as coin library library_main_with_config(chain_config,
break; command,
((unsigned int *) arg0)[3]); // called as coin library
break;
} }
#endif #endif
return 0; return 0;
} }

View File

@@ -3,12 +3,12 @@
#include "poorstream.h" #include "poorstream.h"
void poorstream_init(poorstream_t *stream, uint8_t *buffer) { void poorstream_init(poorstream_t *stream, uint8_t *buffer) {
memset((void*)stream, 0, sizeof(poorstream_t)); memset((void *) stream, 0, sizeof(poorstream_t));
stream->pointer = buffer; stream->pointer = buffer;
} }
void poorstream_flush(poorstream_t *stream) { void poorstream_flush(poorstream_t *stream) {
//PRINTF("Flush\n"); // PRINTF("Flush\n");
*(stream->pointer + 0) = (stream->accumulator >> 56); *(stream->pointer + 0) = (stream->accumulator >> 56);
*(stream->pointer + 1) = (stream->accumulator >> 48); *(stream->pointer + 1) = (stream->accumulator >> 48);
*(stream->pointer + 2) = (stream->accumulator >> 40); *(stream->pointer + 2) = (stream->accumulator >> 40);
@@ -23,12 +23,12 @@ void poorstream_write_bits(poorstream_t *stream, uint64_t bits, uint32_t num_bit
stream->offset += num_bits; stream->offset += num_bits;
if (stream->offset < 64) { if (stream->offset < 64) {
stream->accumulator |= (bits << (64 - stream->offset)); stream->accumulator |= (bits << (64 - stream->offset));
//PRINTF("ACC |= << %d\n", (64 - stream->offset)); // PRINTF("ACC |= << %d\n", (64 - stream->offset));
} else { } else {
stream->offset -= 64; stream->offset -= 64;
stream->mask = ((1 << (num_bits - stream->offset)) - 1); stream->mask = ((1 << (num_bits - stream->offset)) - 1);
//PRINTF("Mask %lx\n", stream->mask); // PRINTF("Mask %lx\n", stream->mask);
//PRINTF("Offset %d\n", stream->offset); // PRINTF("Offset %d\n", stream->offset);
stream->accumulator |= ((bits >> stream->offset) & stream->mask); stream->accumulator |= ((bits >> stream->offset) & stream->mask);
poorstream_flush(stream); poorstream_flush(stream);
stream->accumulator = 0; stream->accumulator = 0;

View File

@@ -8,10 +8,10 @@
#include "os.h" #include "os.h"
typedef struct poorstream_t { typedef struct poorstream_t {
uint8_t *pointer; uint8_t *pointer;
uint32_t offset; uint32_t offset;
uint64_t mask; uint64_t mask;
uint64_t accumulator; uint64_t accumulator;
} poorstream_t; } poorstream_t;
void poorstream_init(poorstream_t *stream, uint8_t *buffer); void poorstream_init(poorstream_t *stream, uint8_t *buffer);

View File

@@ -22,24 +22,24 @@
#define WEI_TO_ETHER 18 #define WEI_TO_ETHER 18
#define N_storage (*(volatile internalStorage_t*) PIC(&N_storage_real)) #define N_storage (*(volatile internalStorage_t *) PIC(&N_storage_real))
typedef struct internalStorage_t { typedef struct internalStorage_t {
unsigned char dataAllowed; unsigned char dataAllowed;
unsigned char contractDetails; unsigned char contractDetails;
uint8_t initialized; uint8_t initialized;
} internalStorage_t; } internalStorage_t;
#ifdef HAVE_STARKWARE #ifdef HAVE_STARKWARE
typedef enum starkQuantumType_e { typedef enum starkQuantumType_e {
STARK_QUANTUM_LEGACY = 0x00, STARK_QUANTUM_LEGACY = 0x00,
STARK_QUANTUM_ETH, STARK_QUANTUM_ETH,
STARK_QUANTUM_ERC20, STARK_QUANTUM_ERC20,
STARK_QUANTUM_ERC721, STARK_QUANTUM_ERC721,
STARK_QUANTUM_MINTABLE_ERC20, STARK_QUANTUM_MINTABLE_ERC20,
STARK_QUANTUM_MINTABLE_ERC721 STARK_QUANTUM_MINTABLE_ERC721
} starkQuantumType_e; } starkQuantumType_e;
@@ -98,7 +98,6 @@ typedef struct messageSigningContext712_t {
uint8_t messageHash[32]; uint8_t messageHash[32];
} messageSigningContext712_t; } messageSigningContext712_t;
typedef union { typedef union {
publicKeyContext_t publicKeyContext; publicKeyContext_t publicKeyContext;
transactionContext_t transactionContext; transactionContext_t transactionContext;
@@ -107,22 +106,22 @@ typedef union {
} tmpCtx_t; } tmpCtx_t;
typedef union { typedef union {
txContent_t txContent; txContent_t txContent;
cx_sha256_t sha2; cx_sha256_t sha2;
char tmp[100]; char tmp[100];
} tmpContent_t; } tmpContent_t;
#ifdef HAVE_STARKWARE #ifdef HAVE_STARKWARE
typedef struct starkContext_t { typedef struct starkContext_t {
uint8_t w1[32]; uint8_t w1[32];
uint8_t w2[32]; uint8_t w2[32];
uint8_t w3[32]; uint8_t w3[32];
uint8_t w4[32]; uint8_t w4[32];
uint8_t conditional; uint8_t conditional;
uint8_t transferDestination[32]; uint8_t transferDestination[32];
uint8_t fact[32]; uint8_t fact[32];
uint8_t conditionAddress[20]; uint8_t conditionAddress[20];
} starkContext_t; } starkContext_t;
#endif #endif
@@ -134,27 +133,23 @@ typedef union {
#endif #endif
} dataContext_t; } dataContext_t;
typedef enum { typedef enum { APP_STATE_IDLE, APP_STATE_SIGNING_TX, APP_STATE_SIGNING_MESSAGE } app_state_t;
APP_STATE_IDLE,
APP_STATE_SIGNING_TX,
APP_STATE_SIGNING_MESSAGE
} app_state_t;
typedef enum { typedef enum {
CONTRACT_NONE, CONTRACT_NONE,
CONTRACT_ERC20, CONTRACT_ERC20,
CONTRACT_ALLOWANCE, CONTRACT_ALLOWANCE,
#ifdef HAVE_STARKWARE #ifdef HAVE_STARKWARE
CONTRACT_STARKWARE_REGISTER, CONTRACT_STARKWARE_REGISTER,
CONTRACT_STARKWARE_DEPOSIT_TOKEN, CONTRACT_STARKWARE_DEPOSIT_TOKEN,
CONTRACT_STARKWARE_DEPOSIT_ETH, CONTRACT_STARKWARE_DEPOSIT_ETH,
CONTRACT_STARKWARE_WITHDRAW, CONTRACT_STARKWARE_WITHDRAW,
CONTRACT_STARKWARE_DEPOSIT_CANCEL, CONTRACT_STARKWARE_DEPOSIT_CANCEL,
CONTRACT_STARKWARE_DEPOSIT_RECLAIM, CONTRACT_STARKWARE_DEPOSIT_RECLAIM,
CONTRACT_STARKWARE_FULL_WITHDRAWAL, CONTRACT_STARKWARE_FULL_WITHDRAWAL,
CONTRACT_STARKWARE_FREEZE, CONTRACT_STARKWARE_FREEZE,
CONTRACT_STARKWARE_ESCAPE, CONTRACT_STARKWARE_ESCAPE,
CONTRACT_STARKWARE_VERIFY_ESCAPE CONTRACT_STARKWARE_VERIFY_ESCAPE
#endif #endif
} contract_call_t; } contract_call_t;
@@ -196,5 +191,4 @@ extern uint32_t eth2WithdrawalIndex;
void reset_app_context(void); void reset_app_context(void);
#endif // __SHARED_CONTEXT_H__ #endif // __SHARED_CONTEXT_H__

View File

@@ -5,16 +5,15 @@
#include "ui_callbacks.h" #include "ui_callbacks.h"
#include "utils.h" #include "utils.h"
static unsigned char const C_cx_Stark256_n[] = { static unsigned char const C_cx_Stark256_n[] = {
//n: 0x0800000000000010ffffffffffffffffb781126dcae7b2321e66a241adc64d2f // n: 0x0800000000000010ffffffffffffffffb781126dcae7b2321e66a241adc64d2f
0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xb7, 0x81, 0x12, 0x6d, 0xca, 0xe7, 0xb2, 0x32, 0x1e, 0x66, 0xa2, 0x41, 0xad, 0xc6, 0x4d, 0x2f}; 0xb7, 0x81, 0x12, 0x6d, 0xca, 0xe7, 0xb2, 0x32, 0x1e, 0x66, 0xa2, 0x41, 0xad, 0xc6, 0x4d, 0x2f};
// C_cx_secp256k1_n - (C_cx_secp256k1_n % C_cx_Stark256_n) // C_cx_secp256k1_n - (C_cx_secp256k1_n % C_cx_Stark256_n)
static unsigned char const STARK_DERIVE_BIAS[] = { static unsigned char const STARK_DERIVE_BIAS[] = {
0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x0e, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf7, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x0e, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf7,
0x38, 0xa1, 0x3b, 0x4b, 0x92, 0x0e, 0x94, 0x11, 0xae, 0x6d, 0xa5, 0xf4, 0x0b, 0x03, 0x58, 0xb1 0x38, 0xa1, 0x3b, 0x4b, 0x92, 0x0e, 0x94, 0x11, 0xae, 0x6d, 0xa5, 0xf4, 0x0b, 0x03, 0x58, 0xb1};
};
void starkDerivePrivateKey(uint32_t *bip32Path, uint32_t bip32PathLength, uint8_t *privateKeyData) { void starkDerivePrivateKey(uint32_t *bip32Path, uint32_t bip32PathLength, uint8_t *privateKeyData) {
#if 0 #if 0
@@ -29,59 +28,62 @@ void starkDerivePrivateKey(uint32_t *bip32Path, uint32_t bip32PathLength, uint8_
cx_math_modm(privateKeyData, 32, C_cx_Stark256_n, 32); cx_math_modm(privateKeyData, 32, C_cx_Stark256_n, 32);
PRINTF("Private key after processing %.*H\n", 32, privateKeyData); PRINTF("Private key after processing %.*H\n", 32, privateKeyData);
#else #else
uint8_t tmp[33]; uint8_t tmp[33];
uint8_t index = 0; uint8_t index = 0;
// Sanity check // Sanity check
if ((bip32PathLength < 2) || (bip32Path[0] != STARK_BIP32_PATH_0) || (bip32Path[1] != STARK_BIP32_PATH_1)) { if ((bip32PathLength < 2) || (bip32Path[0] != STARK_BIP32_PATH_0) ||
PRINTF("Invalid Stark derivation path %d %d\n", bip32Path[0], bip32Path[1]); (bip32Path[1] != STARK_BIP32_PATH_1)) {
THROW(0x6a80); PRINTF("Invalid Stark derivation path %d %d\n", bip32Path[0], bip32Path[1]);
} THROW(0x6a80);
os_perso_derive_node_bip32(CX_CURVE_256K1, bip32Path, bip32PathLength, tmp, NULL);
PRINTF("Private key before processing %.*H\n", 32, tmp);
for(;;) {
tmp[32] = index;
cx_hash_sha256(tmp, 33, privateKeyData, 32);
PRINTF("Key hash %.*H\n", 32, privateKeyData);
if (cx_math_cmp(privateKeyData, STARK_DERIVE_BIAS, 32) < 0) {
cx_math_modm(privateKeyData, 32, C_cx_Stark256_n, 32);
break;
} }
index++; os_perso_derive_node_bip32(CX_CURVE_256K1, bip32Path, bip32PathLength, tmp, NULL);
} PRINTF("Private key before processing %.*H\n", 32, tmp);
PRINTF("Key result %.*H\n", 32, privateKeyData); for (;;) {
tmp[32] = index;
cx_hash_sha256(tmp, 33, privateKeyData, 32);
PRINTF("Key hash %.*H\n", 32, privateKeyData);
if (cx_math_cmp(privateKeyData, STARK_DERIVE_BIAS, 32) < 0) {
cx_math_modm(privateKeyData, 32, C_cx_Stark256_n, 32);
break;
}
index++;
}
PRINTF("Key result %.*H\n", 32, privateKeyData);
#endif #endif
} }
void stark_get_amount_string(uint8_t *contractAddress, uint8_t *quantum256, uint8_t *amount64, char *tmp100, char *target100) { void stark_get_amount_string(uint8_t *contractAddress,
uint256_t amountPre, quantum, amount; uint8_t *quantum256,
uint8_t decimals; uint8_t *amount64,
char *ticker = (char*)PIC(chainConfig->coinName); char *tmp100,
char *target100) {
uint256_t amountPre, quantum, amount;
uint8_t decimals;
char *ticker = (char *) PIC(chainConfig->coinName);
PRINTF("stark_get_amount_string %.*H\n", 20, contractAddress); PRINTF("stark_get_amount_string %.*H\n", 20, contractAddress);
if (allzeroes(contractAddress, 20)) { if (allzeroes(contractAddress, 20)) {
decimals = WEI_TO_ETHER; decimals = WEI_TO_ETHER;
PRINTF("stark_get_amount_string - ETH\n"); PRINTF("stark_get_amount_string - ETH\n");
} } else {
else { tokenDefinition_t *token = getKnownToken(contractAddress);
tokenDefinition_t *token = getKnownToken(contractAddress); if (token == NULL) { // caught earlier
if (token == NULL) { // caught earlier THROW(0x6A80);
THROW(0x6A80); }
decimals = token->decimals;
ticker = (char *) token->ticker;
PRINTF("stark_get_amount_string - decimals %d ticker %s\n", decimals, ticker);
} }
decimals = token->decimals; convertUint256BE(amount64, 8, &amountPre);
ticker = (char*)token->ticker; readu256BE(quantum256, &quantum);
PRINTF("stark_get_amount_string - decimals %d ticker %s\n", decimals, ticker); mul256(&amountPre, &quantum, &amount);
} tostring256(&amount, 10, tmp100, 100);
convertUint256BE(amount64, 8, &amountPre); PRINTF("stark_get_amount_string - mul256 %s\n", tmp100);
readu256BE(quantum256, &quantum); strcpy(target100, ticker);
mul256(&amountPre, &quantum, &amount); adjustDecimals(tmp100, strlen(tmp100), target100 + strlen(ticker), 100, decimals);
tostring256(&amount, 10, tmp100, 100); PRINTF("get_amount_string %s\n", target100);
PRINTF("stark_get_amount_string - mul256 %s\n", tmp100);
strcpy(target100, ticker);
adjustDecimals(tmp100, strlen(tmp100), target100 + strlen(ticker), 100, decimals);
PRINTF("get_amount_string %s\n", target100);
} }
#endif // HAVE_STARK
#endif // HAVE_STARK

View File

@@ -8,14 +8,14 @@
#include "os.h" #include "os.h"
#include "cx.h" #include "cx.h"
/* EC points */ /* EC points */
#define FIELD_ELEMENT_SIZE (32) #define FIELD_ELEMENT_SIZE (32)
#define EC_POINT_SIZE (2 * FIELD_ELEMENT_SIZE + 1) #define EC_POINT_SIZE (2 * FIELD_ELEMENT_SIZE + 1)
typedef unsigned char FieldElement[FIELD_ELEMENT_SIZE]; typedef unsigned char FieldElement[FIELD_ELEMENT_SIZE];
typedef unsigned char ECPoint[EC_POINT_SIZE]; typedef unsigned char ECPoint[EC_POINT_SIZE];
void pedersen(FieldElement res, /* out */ void pedersen(FieldElement res, /* out */
FieldElement a, FieldElement b); FieldElement a,
FieldElement b);
#endif #endif

View File

@@ -8,16 +8,14 @@
#define SIGNATURE_MAX_LEN (72) #define SIGNATURE_MAX_LEN (72)
static const ECPoint PEDERSEN_SHIFT[] = { { static const ECPoint PEDERSEN_SHIFT[] = {{
0x04, 0x04,
0x04, 0x9e, 0xe3, 0xeb, 0xa8, 0xc1, 0x60, 0x07, 0x00, 0xee, 0x1b, 0x04, 0x9e, 0xe3, 0xeb, 0xa8, 0xc1, 0x60, 0x07, 0x00, 0xee, 0x1b, 0x87, 0xeb, 0x59, 0x9f, 0x16,
0x87, 0xeb, 0x59, 0x9f, 0x16, 0x71, 0x6b, 0x0b, 0x10, 0x22, 0x94, 0x71, 0x6b, 0x0b, 0x10, 0x22, 0x94, 0x77, 0x33, 0x55, 0x1f, 0xde, 0x40, 0x50, 0xca, 0x68, 0x04,
0x77, 0x33, 0x55, 0x1f, 0xde, 0x40, 0x50, 0xca, 0x68, 0x04,
0x03, 0xca, 0x0c, 0xfe, 0x4b, 0x3b, 0xc6, 0xdd, 0xf3, 0x46, 0xd4, 0x03, 0xca, 0x0c, 0xfe, 0x4b, 0x3b, 0xc6, 0xdd, 0xf3, 0x46, 0xd4, 0x9d, 0x06, 0xea, 0x0e, 0xd3,
0x9d, 0x06, 0xea, 0x0e, 0xd3, 0x4e, 0x62, 0x10, 0x62, 0xc0, 0xe0, 0x4e, 0x62, 0x10, 0x62, 0xc0, 0xe0, 0x56, 0xc1, 0xd0, 0x40, 0x5d, 0x26, 0x6e, 0x10, 0x26, 0x8a,
0x56, 0xc1, 0xd0, 0x40, 0x5d, 0x26, 0x6e, 0x10, 0x26, 0x8a,
}}; }};
static const ECPoint PEDERSEN_POINTS[4] = { static const ECPoint PEDERSEN_POINTS[4] = {
@@ -78,15 +76,16 @@ void accum_ec_mul(ECPoint *hash, uint8_t *buf, int len, int pedersen_idx) {
} }
void pedersen(FieldElement res, /* out */ void pedersen(FieldElement res, /* out */
FieldElement a, FieldElement b) { FieldElement a,
FieldElement b) {
ECPoint hash; ECPoint hash;
memcpy(hash, PEDERSEN_SHIFT, sizeof(hash)); memcpy(hash, PEDERSEN_SHIFT, sizeof(hash));
accum_ec_mul(&hash, a, 1, 1); accum_ec_mul(&hash, a, 1, 1);
accum_ec_mul(&hash, a+1, FIELD_ELEMENT_SIZE-1, 0); accum_ec_mul(&hash, a + 1, FIELD_ELEMENT_SIZE - 1, 0);
accum_ec_mul(&hash, b, 1, 3); accum_ec_mul(&hash, b, 1, 3);
accum_ec_mul(&hash, b+1, FIELD_ELEMENT_SIZE-1, 2); accum_ec_mul(&hash, b + 1, FIELD_ELEMENT_SIZE - 1, 2);
memcpy(res, hash + 1, FIELD_ELEMENT_SIZE); memcpy(res, hash + 1, FIELD_ELEMENT_SIZE);
} }
@@ -116,31 +115,43 @@ int stark_sign(uint8_t *signature, /* out */
PRINTF("Pedersen hash 2 %.*H\n", 32, hash); PRINTF("Pedersen hash 2 %.*H\n", 32, hash);
cx_ecfp_init_private_key(CX_CURVE_Stark256, privateKeyData, 32, &privateKey); cx_ecfp_init_private_key(CX_CURVE_Stark256, privateKeyData, 32, &privateKey);
io_seproxyhal_io_heartbeat(); io_seproxyhal_io_heartbeat();
int signatureLength = cx_ecdsa_sign(&privateKey, CX_RND_RFC6979 | CX_LAST, CX_SHA256, int signatureLength = cx_ecdsa_sign(&privateKey,
hash, sizeof(hash), signature, SIGNATURE_MAX_LEN, &info); CX_RND_RFC6979 | CX_LAST,
CX_SHA256,
hash,
sizeof(hash),
signature,
SIGNATURE_MAX_LEN,
&info);
PRINTF("Stark signature %.*H\n", signatureLength, signature); PRINTF("Stark signature %.*H\n", signatureLength, signature);
return signatureLength; return signatureLength;
} }
// ERC20Token(address) // ERC20Token(address)
static const uint8_t ERC20_SELECTOR[] = { 0xf4, 0x72, 0x61, 0xb0 }; static const uint8_t ERC20_SELECTOR[] = {0xf4, 0x72, 0x61, 0xb0};
// ETH() // ETH()
static const uint8_t ETH_SELECTOR[] = { 0x83, 0x22, 0xff, 0xf2 }; static const uint8_t ETH_SELECTOR[] = {0x83, 0x22, 0xff, 0xf2};
// ERC721Token(address, uint256) // ERC721Token(address, uint256)
static const uint8_t ERC721_SELECTOR[] = { 0x02, 0x57, 0x17, 0x92 }; static const uint8_t ERC721_SELECTOR[] = {0x02, 0x57, 0x17, 0x92};
// MintableERC20Token(address) // MintableERC20Token(address)
static const uint8_t MINTABLE_ERC20_SELECTOR[] = { 0x68, 0x64, 0x6e, 0x2d }; static const uint8_t MINTABLE_ERC20_SELECTOR[] = {0x68, 0x64, 0x6e, 0x2d};
// MintableERC721Token(address,uint256) // MintableERC721Token(address,uint256)
static const uint8_t MINTABLE_ERC721_SELECTOR[] = { 0xb8, 0xb8, 0x66, 0x72 }; static const uint8_t MINTABLE_ERC721_SELECTOR[] = {0xb8, 0xb8, 0x66, 0x72};
static const char NFT_ASSET_ID_PREFIX[] = { 'N', 'F', 'T', ':', 0 }; static const char NFT_ASSET_ID_PREFIX[] = {'N', 'F', 'T', ':', 0};
static const char MINTABLE_ASSET_ID_PREFIX[] = { 'M', 'I', 'N', 'T', 'A', 'B', 'L', 'E', ':', 0 }; static const char MINTABLE_ASSET_ID_PREFIX[] = {'M', 'I', 'N', 'T', 'A', 'B', 'L', 'E', ':', 0};
void compute_token_id(cx_sha3_t *sha3, uint8_t *contractAddress, uint8_t quantumType, uint8_t *quantum, uint8_t *mintingBlob, bool assetTypeOnly, uint8_t *output) { void compute_token_id(cx_sha3_t *sha3,
uint8_t *contractAddress,
uint8_t quantumType,
uint8_t *quantum,
uint8_t *mintingBlob,
bool assetTypeOnly,
uint8_t *output) {
uint8_t tmp[36]; uint8_t tmp[36];
cx_keccak_init(sha3, 256); cx_keccak_init(sha3, 256);
if ((contractAddress != NULL) && (!allzeroes(contractAddress, 20))) { if ((contractAddress != NULL) && (!allzeroes(contractAddress, 20))) {
const uint8_t *selector = NULL; const uint8_t *selector = NULL;
switch(quantumType) { switch (quantumType) {
case STARK_QUANTUM_ERC20: case STARK_QUANTUM_ERC20:
case STARK_QUANTUM_LEGACY: case STARK_QUANTUM_LEGACY:
selector = ERC20_SELECTOR; selector = ERC20_SELECTOR;
@@ -162,29 +173,27 @@ void compute_token_id(cx_sha3_t *sha3, uint8_t *contractAddress, uint8_t quantum
memset(tmp, 0, sizeof(tmp)); memset(tmp, 0, sizeof(tmp));
memmove(tmp, selector, 4); memmove(tmp, selector, 4);
memmove(tmp + 16, contractAddress, 20); memmove(tmp + 16, contractAddress, 20);
cx_hash((cx_hash_t*)sha3, 0, tmp, sizeof(tmp), NULL, 0); cx_hash((cx_hash_t *) sha3, 0, tmp, sizeof(tmp), NULL, 0);
} } else {
else {
PRINTF("compute_token_id for ETH\n"); PRINTF("compute_token_id for ETH\n");
cx_hash((cx_hash_t*)sha3, 0, ETH_SELECTOR, sizeof(ETH_SELECTOR), NULL, 0); cx_hash((cx_hash_t *) sha3, 0, ETH_SELECTOR, sizeof(ETH_SELECTOR), NULL, 0);
} }
if ((quantumType == STARK_QUANTUM_ERC721) || (quantumType == STARK_QUANTUM_MINTABLE_ERC721)) { if ((quantumType == STARK_QUANTUM_ERC721) || (quantumType == STARK_QUANTUM_MINTABLE_ERC721)) {
memset(tmp, 0, 32); memset(tmp, 0, 32);
tmp[31] = 1; tmp[31] = 1;
PRINTF("compute_token_id quantum %.*H\n", 32, tmp); PRINTF("compute_token_id quantum %.*H\n", 32, tmp);
cx_hash((cx_hash_t*)sha3, CX_LAST, tmp, 32, output, 32); cx_hash((cx_hash_t *) sha3, CX_LAST, tmp, 32, output, 32);
} } else {
else {
PRINTF("compute_token_id quantum %.*H\n", 32, quantum); PRINTF("compute_token_id quantum %.*H\n", 32, quantum);
cx_hash((cx_hash_t*)sha3, CX_LAST, quantum, 32, output, 32); cx_hash((cx_hash_t *) sha3, CX_LAST, quantum, 32, output, 32);
} }
if (!assetTypeOnly && ((quantumType != STARK_QUANTUM_LEGACY) && if (!assetTypeOnly &&
(quantumType != STARK_QUANTUM_ETH) && ((quantumType != STARK_QUANTUM_LEGACY) && (quantumType != STARK_QUANTUM_ETH) &&
(quantumType != STARK_QUANTUM_ERC20))) { (quantumType != STARK_QUANTUM_ERC20))) {
const char *prefix = NULL; const char *prefix = NULL;
output[0] &= 0x03; output[0] &= 0x03;
cx_keccak_init(sha3, 256); cx_keccak_init(sha3, 256);
switch(quantumType) { switch (quantumType) {
case STARK_QUANTUM_ERC721: case STARK_QUANTUM_ERC721:
prefix = NFT_ASSET_ID_PREFIX; prefix = NFT_ASSET_ID_PREFIX;
break; break;
@@ -196,18 +205,18 @@ void compute_token_id(cx_sha3_t *sha3, uint8_t *contractAddress, uint8_t quantum
PRINTF("Unsupported non default quantum type %d\n", quantumType); PRINTF("Unsupported non default quantum type %d\n", quantumType);
return; return;
} }
cx_hash((cx_hash_t*)sha3, 0, (const uint8_t*)prefix, strlen(prefix), NULL, 0); cx_hash((cx_hash_t *) sha3, 0, (const uint8_t *) prefix, strlen(prefix), NULL, 0);
cx_hash((cx_hash_t*)sha3, 0, output, 32, NULL, 0); cx_hash((cx_hash_t *) sha3, 0, output, 32, NULL, 0);
cx_hash((cx_hash_t*)sha3, CX_LAST, mintingBlob, 32, output, 32); cx_hash((cx_hash_t *) sha3, CX_LAST, mintingBlob, 32, output, 32);
} }
if (!assetTypeOnly && ((quantumType == STARK_QUANTUM_MINTABLE_ERC20) || (quantumType == STARK_QUANTUM_MINTABLE_ERC721))) { if (!assetTypeOnly && ((quantumType == STARK_QUANTUM_MINTABLE_ERC20) ||
(quantumType == STARK_QUANTUM_MINTABLE_ERC721))) {
output[0] = 0x04; output[0] = 0x04;
output[1] = 0x00; output[1] = 0x00;
} } else {
else {
output[0] &= 0x03; output[0] &= 0x03;
} }
PRINTF("compute_token_id computed token %.*H\n", 32, output); PRINTF("compute_token_id computed token %.*H\n", 32, output);
} }
#endif // HAVE_STARK #endif // HAVE_STARK

View File

@@ -9,11 +9,21 @@
#include "cx.h" #include "cx.h"
#include "stark_crypto.h" #include "stark_crypto.h"
void compute_token_id(cx_sha3_t *sha3, uint8_t *contractAddress, uint8_t quantumType, uint8_t *quantum, uint8_t *mintingBlob, bool assetTypeOnly, uint8_t *output); void compute_token_id(cx_sha3_t *sha3,
uint8_t *contractAddress,
uint8_t quantumType,
uint8_t *quantum,
uint8_t *mintingBlob,
bool assetTypeOnly,
uint8_t *output);
void starkDerivePrivateKey(uint32_t *bip32Path, uint32_t bip32PathLength, uint8_t *privateKeyData); void starkDerivePrivateKey(uint32_t *bip32Path, uint32_t bip32PathLength, uint8_t *privateKeyData);
void stark_get_amount_string(uint8_t *contractAddress, uint8_t *quantum256, uint8_t *amount64, char *tmp100, char *target100); void stark_get_amount_string(uint8_t *contractAddress,
uint8_t *quantum256,
uint8_t *amount64,
char *tmp100,
char *target100);
int stark_sign(uint8_t *signature, /* out */ int stark_sign(uint8_t *signature, /* out */
uint8_t *privateKeyData, uint8_t *privateKeyData,
@@ -23,4 +33,3 @@ int stark_sign(uint8_t *signature, /* out */
FieldElement condition); FieldElement condition);
#endif #endif

View File

@@ -20,8 +20,8 @@ typedef struct check_address_parameters_s {
// fields and serialization format depends on spesific coin app // fields and serialization format depends on spesific coin app
unsigned char* address_parameters; unsigned char* address_parameters;
unsigned char address_parameters_length; unsigned char address_parameters_length;
char *address_to_check; char* address_to_check;
char *extra_id_to_check; char* extra_id_to_check;
// OUT // OUT
int result; int result;
} check_address_parameters_t; } check_address_parameters_t;
@@ -45,8 +45,8 @@ typedef struct create_transaction_parameters_s {
unsigned char amount_length; unsigned char amount_length;
unsigned char* fee_amount; unsigned char* fee_amount;
unsigned char fee_amount_length; unsigned char fee_amount_length;
char *destination_address; char* destination_address;
char *destination_address_extra_id; char* destination_address_extra_id;
} create_transaction_parameters_t; } create_transaction_parameters_t;
#endif #endif

File diff suppressed because it is too large Load Diff

View File

@@ -1,26 +1,26 @@
/******************************************************************************* /*******************************************************************************
* Ledger Ethereum App * Ledger Ethereum App
* (c) 2016-2019 Ledger * (c) 2016-2019 Ledger
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
********************************************************************************/ ********************************************************************************/
#ifndef _TOKENS_H_ #ifndef _TOKENS_H_
#define _TOKENS_H_ #define _TOKENS_H_
#include <stdint.h> #include <stdint.h>
#define MAX_TICKER_LEN 12 // 10 characters + ' ' + '\0' #define MAX_TICKER_LEN 12 // 10 characters + ' ' + '\0'
typedef struct tokenDefinition_t { typedef struct tokenDefinition_t {
#ifdef HAVE_CONTRACT_NAME_IN_DESCRIPTOR #ifdef HAVE_CONTRACT_NAME_IN_DESCRIPTOR
@@ -41,36 +41,36 @@ extern tokenDefinition_t const TOKENS_EXTRA[NUM_TOKENS_EXTRA];
#ifdef HAVE_TOKENS_LIST #ifdef HAVE_TOKENS_LIST
#define NUM_TOKENS_AKROMA 0 #define NUM_TOKENS_AKROMA 0
#define NUM_TOKENS_ELLAISM 1 #define NUM_TOKENS_ELLAISM 1
#define NUM_TOKENS_ETHEREUM 1102 #define NUM_TOKENS_ETHEREUM 1102
#define NUM_TOKENS_ETHEREUM_CLASSIC 4 #define NUM_TOKENS_ETHEREUM_CLASSIC 4
#define NUM_TOKENS_ETHERSOCIAL 0 #define NUM_TOKENS_ETHERSOCIAL 0
#define NUM_TOKENS_ETHER1 0 #define NUM_TOKENS_ETHER1 0
#define NUM_TOKENS_PIRL 0 #define NUM_TOKENS_PIRL 0
#define NUM_TOKENS_POA 0 #define NUM_TOKENS_POA 0
#define NUM_TOKENS_RSK 0 #define NUM_TOKENS_RSK 0
#define NUM_TOKENS_UBIQ 6 #define NUM_TOKENS_UBIQ 6
#define NUM_TOKENS_EXPANSE 0 #define NUM_TOKENS_EXPANSE 0
#define NUM_TOKENS_WANCHAIN 0 #define NUM_TOKENS_WANCHAIN 0
#define NUM_TOKENS_KUSD 0 #define NUM_TOKENS_KUSD 0
#define NUM_TOKENS_MUSICOIN 0 #define NUM_TOKENS_MUSICOIN 0
#define NUM_TOKENS_CALLISTO 0 #define NUM_TOKENS_CALLISTO 0
#define NUM_TOKENS_ETHERGEM 0 #define NUM_TOKENS_ETHERGEM 0
#define NUM_TOKENS_ATHEIOS 0 #define NUM_TOKENS_ATHEIOS 0
#define NUM_TOKENS_GOCHAIN 0 #define NUM_TOKENS_GOCHAIN 0
#define NUM_TOKENS_MIX 0 #define NUM_TOKENS_MIX 0
#define NUM_TOKENS_REOSC 0 #define NUM_TOKENS_REOSC 0
#define NUM_TOKENS_HPB 0 #define NUM_TOKENS_HPB 0
#define NUM_TOKENS_TOMOCHAIN 0 #define NUM_TOKENS_TOMOCHAIN 0
#define NUM_TOKENS_TOBALABA 0 #define NUM_TOKENS_TOBALABA 0
#define NUM_TOKENS_DEXON 0 #define NUM_TOKENS_DEXON 0
#define NUM_TOKENS_VOLTA 0 #define NUM_TOKENS_VOLTA 0
#define NUM_TOKENS_EWC 0 #define NUM_TOKENS_EWC 0
#define NUM_TOKENS_ARTIS_SIGMA1 0 #define NUM_TOKENS_ARTIS_SIGMA1 0
#define NUM_TOKENS_ARTIS_TAU1 0 #define NUM_TOKENS_ARTIS_TAU1 0
#define NUM_TOKENS_WEBCHAIN 0 #define NUM_TOKENS_WEBCHAIN 0
#define NUM_TOKENS_THUNDERCORE 0 #define NUM_TOKENS_THUNDERCORE 0
extern tokenDefinition_t const TOKENS_AKROMA[NUM_TOKENS_AKROMA]; extern tokenDefinition_t const TOKENS_AKROMA[NUM_TOKENS_AKROMA];
extern tokenDefinition_t const TOKENS_ELLAISM[NUM_TOKENS_ELLAISM]; extern tokenDefinition_t const TOKENS_ELLAISM[NUM_TOKENS_ELLAISM];

View File

@@ -17,7 +17,6 @@ unsigned int io_seproxyhal_touch_eth2_address_ok(const bagl_element_t *e);
void ui_idle(void); void ui_idle(void);
void io_seproxyhal_send_status(uint32_t sw); void io_seproxyhal_send_status(uint32_t sw);
void format_signature_out(const uint8_t* signature); void format_signature_out(const uint8_t *signature);
void finalizeParsing(bool direct); void finalizeParsing(bool direct);
tokenDefinition_t* getKnownToken(uint8_t *contractAddress); tokenDefinition_t *getKnownToken(uint8_t *contractAddress);

View File

@@ -6,6 +6,7 @@ void switch_settings_contract_data(void);
void switch_settings_display_data(void); void switch_settings_display_data(void);
////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////
// clang-format off
UX_STEP_NOCB( UX_STEP_NOCB(
ux_idle_flow_1_step, ux_idle_flow_1_step,
nn, //pnn, nn, //pnn,
@@ -37,16 +38,18 @@ UX_STEP_CB(
&C_icon_dashboard_x, &C_icon_dashboard_x,
"Quit", "Quit",
}); });
// clang-format on
UX_FLOW(ux_idle_flow, UX_FLOW(ux_idle_flow,
&ux_idle_flow_1_step, &ux_idle_flow_1_step,
&ux_idle_flow_2_step, &ux_idle_flow_2_step,
&ux_idle_flow_3_step, &ux_idle_flow_3_step,
&ux_idle_flow_4_step, &ux_idle_flow_4_step,
FLOW_LOOP FLOW_LOOP);
);
#if defined(TARGET_NANOS) #if defined(TARGET_NANOS)
// clang-format off
UX_STEP_CB( UX_STEP_CB(
ux_settings_flow_1_step, ux_settings_flow_1_step,
bnnn_paging, bnnn_paging,
@@ -99,28 +102,28 @@ UX_STEP_CB(
&C_icon_back_x, &C_icon_back_x,
"Back", "Back",
}); });
// clang-format on
UX_FLOW(ux_settings_flow, UX_FLOW(ux_settings_flow,
&ux_settings_flow_1_step, &ux_settings_flow_1_step,
&ux_settings_flow_2_step, &ux_settings_flow_2_step,
&ux_settings_flow_3_step &ux_settings_flow_3_step);
);
void display_settings() { void display_settings() {
strcpy(strings.common.fullAddress, (N_storage.dataAllowed ? "Allowed" : "NOT Allowed")); strcpy(strings.common.fullAddress, (N_storage.dataAllowed ? "Allowed" : "NOT Allowed"));
strcpy(strings.common.fullAddress + 20, (N_storage.contractDetails ? "Displayed" : "NOT Displayed")); strcpy(strings.common.fullAddress + 20,
ux_flow_init(0, ux_settings_flow, NULL); (N_storage.contractDetails ? "Displayed" : "NOT Displayed"));
ux_flow_init(0, ux_settings_flow, NULL);
} }
void switch_settings_contract_data() { void switch_settings_contract_data() {
uint8_t value = (N_storage.dataAllowed ? 0 : 1); uint8_t value = (N_storage.dataAllowed ? 0 : 1);
nvm_write((void*)&N_storage.dataAllowed, (void*)&value, sizeof(uint8_t)); nvm_write((void*) &N_storage.dataAllowed, (void*) &value, sizeof(uint8_t));
display_settings(); display_settings();
} }
void switch_settings_display_data() { void switch_settings_display_data() {
uint8_t value = (N_storage.contractDetails ? 0 : 1); uint8_t value = (N_storage.contractDetails ? 0 : 1);
nvm_write((void*)&N_storage.contractDetails, (void*)&value, sizeof(uint8_t)); nvm_write((void*) &N_storage.contractDetails, (void*) &value, sizeof(uint8_t));
display_settings(); display_settings();
} }

View File

@@ -2,55 +2,54 @@
#include "os_io_seproxyhal.h" #include "os_io_seproxyhal.h"
extern const ux_flow_step_t * const ux_idle_flow []; extern const ux_flow_step_t* const ux_idle_flow[];
extern const ux_flow_step_t * const ux_settings_flow []; extern const ux_flow_step_t* const ux_settings_flow[];
extern const ux_flow_step_t * const ux_display_public_flow []; extern const ux_flow_step_t* const ux_display_public_flow[];
extern const ux_flow_step_t * const ux_confirm_selector_flow []; extern const ux_flow_step_t* const ux_confirm_selector_flow[];
extern const ux_flow_step_t * const ux_confirm_parameter_flow []; extern const ux_flow_step_t* const ux_confirm_parameter_flow[];
extern const ux_flow_step_t * const ux_approval_tx_flow []; extern const ux_flow_step_t* const ux_approval_tx_flow[];
extern const ux_flow_step_t * const ux_approval_tx_data_warning_flow []; extern const ux_flow_step_t* const ux_approval_tx_data_warning_flow[];
extern const ux_flow_step_t * const ux_approval_allowance_flow []; extern const ux_flow_step_t* const ux_approval_allowance_flow[];
extern const ux_flow_step_t * const ux_sign_flow []; extern const ux_flow_step_t* const ux_sign_flow[];
extern const ux_flow_step_t * const ux_sign_712_v0_flow []; extern const ux_flow_step_t* const ux_sign_712_v0_flow[];
extern const ux_flow_step_t * const ux_display_public_eth2_flow []; extern const ux_flow_step_t* const ux_display_public_eth2_flow[];
#ifdef HAVE_STARKWARE #ifdef HAVE_STARKWARE
extern const ux_flow_step_t * const ux_display_stark_public_flow []; extern const ux_flow_step_t* const ux_display_stark_public_flow[];
extern const ux_flow_step_t * const ux_stark_limit_order_flow []; extern const ux_flow_step_t* const ux_stark_limit_order_flow[];
extern const ux_flow_step_t * const ux_stark_transfer_flow []; extern const ux_flow_step_t* const ux_stark_transfer_flow[];
extern const ux_flow_step_t * const ux_stark_self_transfer_flow []; extern const ux_flow_step_t* const ux_stark_self_transfer_flow[];
extern const ux_flow_step_t * const ux_stark_transfer_conditional_flow []; extern const ux_flow_step_t* const ux_stark_transfer_conditional_flow[];
extern const ux_flow_step_t * const ux_stark_self_transfer_conditional_flow []; extern const ux_flow_step_t* const ux_stark_self_transfer_conditional_flow[];
extern const ux_flow_step_t * const ux_approval_starkware_register_flow []; extern const ux_flow_step_t* const ux_approval_starkware_register_flow[];
extern const ux_flow_step_t * const ux_approval_starkware_deposit_flow []; extern const ux_flow_step_t* const ux_approval_starkware_deposit_flow[];
extern const ux_flow_step_t * const ux_approval_starkware_withdraw_flow []; extern const ux_flow_step_t* const ux_approval_starkware_withdraw_flow[];
extern const ux_flow_step_t * const ux_approval_starkware_verify_vault_id_flow []; extern const ux_flow_step_t* const ux_approval_starkware_verify_vault_id_flow[];
extern const ux_flow_step_t * const ux_approval_starkware_escape_flow []; extern const ux_flow_step_t* const ux_approval_starkware_escape_flow[];
extern const ux_flow_step_t * const ux_approval_starkware_verify_escape_flow []; extern const ux_flow_step_t* const ux_approval_starkware_verify_escape_flow[];
extern const ux_flow_step_t * const ux_stark_unsafe_sign_flow []; extern const ux_flow_step_t* const ux_stark_unsafe_sign_flow[];
#endif #endif

View File

@@ -1,19 +1,19 @@
/******************************************************************************* /*******************************************************************************
* Ledger Ethereum App * Ledger Ethereum App
* (c) 2016-2019 Ledger * (c) 2016-2019 Ledger
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
********************************************************************************/ ********************************************************************************/
#include <stdint.h> #include <stdint.h>
#include <string.h> #include <string.h>
@@ -23,16 +23,16 @@
#include "uint256.h" #include "uint256.h"
#include "tokens.h" #include "tokens.h"
static const unsigned char hex_digits[] = {'0', '1', '2', '3', '4', '5', '6', '7', static const unsigned char hex_digits[] =
'8', '9', 'A', 'B', 'C', 'D', 'E', 'F'}; {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
void array_hexstr(char *strbuf, const void *bin, unsigned int len) { void array_hexstr(char *strbuf, const void *bin, unsigned int len) {
while (len--) { while (len--) {
*strbuf++ = hex_digits[((*((char *)bin)) >> 4) & 0xF]; *strbuf++ = hex_digits[((*((char *) bin)) >> 4) & 0xF];
*strbuf++ = hex_digits[(*((char *)bin)) & 0xF]; *strbuf++ = hex_digits[(*((char *) bin)) & 0xF];
bin = (const void *)((unsigned int)bin + 1); bin = (const void *) ((unsigned int) bin + 1);
} }
*strbuf = 0; // EOS *strbuf = 0; // EOS
} }
void convertUint256BE(uint8_t *data, uint32_t length, uint256_t *target) { void convertUint256BE(uint8_t *data, uint32_t length, uint256_t *target) {
@@ -45,7 +45,7 @@ void convertUint256BE(uint8_t *data, uint32_t length, uint256_t *target) {
int local_strchr(char *string, char ch) { int local_strchr(char *string, char ch) {
unsigned int length = strlen(string); unsigned int length = strlen(string);
unsigned int i; unsigned int i;
for (i=0; i<length; i++) { for (i = 0; i < length; i++) {
if (string[i] == ch) { if (string[i] == ch) {
return i; return i;
} }
@@ -56,30 +56,27 @@ int local_strchr(char *string, char ch) {
uint32_t getV(txContent_t *txContent) { uint32_t getV(txContent_t *txContent) {
uint32_t v = 0; uint32_t v = 0;
if (txContent->vLength == 1) { if (txContent->vLength == 1) {
v = txContent->v[0]; v = txContent->v[0];
} } else if (txContent->vLength == 2) {
else v = (txContent->v[0] << 8) | txContent->v[1];
if (txContent->vLength == 2) { } else if (txContent->vLength == 3) {
v = (txContent->v[0] << 8) | txContent->v[1]; v = (txContent->v[0] << 16) | (txContent->v[1] << 8) | txContent->v[2];
} } else if (txContent->vLength == 4) {
else v = (txContent->v[0] << 24) | (txContent->v[1] << 16) | (txContent->v[2] << 8) |
if (txContent->vLength == 3) { txContent->v[3];
v = (txContent->v[0] << 16) | (txContent->v[1] << 8) | txContent->v[2]; } else if (txContent->vLength != 0) {
}
else
if (txContent->vLength == 4) {
v = (txContent->v[0] << 24) | (txContent->v[1] << 16) |
(txContent->v[2] << 8) | txContent->v[3];
}
else
if (txContent->vLength != 0) {
PRINTF("Unexpected v format\n"); PRINTF("Unexpected v format\n");
THROW(EXCEPTION); THROW(EXCEPTION);
} }
return v; return v;
} }
void amountToString(uint8_t* amount, uint8_t amount_size, uint8_t decimals, char* ticker, char* out_buffer, uint8_t out_buffer_size){ void amountToString(uint8_t *amount,
uint8_t amount_size,
uint8_t decimals,
char *ticker,
char *out_buffer,
uint8_t out_buffer_size) {
uint256_t amount_256; uint256_t amount_256;
char tmp_buffer[100]; char tmp_buffer[100];
convertUint256BE(amount, amount_size, &amount_256); convertUint256BE(amount, amount_size, &amount_256);
@@ -90,25 +87,29 @@ void amountToString(uint8_t* amount, uint8_t amount_size, uint8_t decimals, char
memcpy(out_buffer, ticker, MIN(out_buffer_size, ticker_len)); memcpy(out_buffer, ticker, MIN(out_buffer_size, ticker_len));
adjustDecimals(tmp_buffer, amount_len, out_buffer + ticker_len, out_buffer_size - ticker_len -1, decimals); adjustDecimals(tmp_buffer,
out_buffer[out_buffer_size-1] = '\0'; amount_len,
out_buffer + ticker_len,
out_buffer_size - ticker_len - 1,
decimals);
out_buffer[out_buffer_size - 1] = '\0';
} }
bool parse_swap_config(uint8_t* config, uint8_t config_len, char* ticker, uint8_t* decimals){ bool parse_swap_config(uint8_t *config, uint8_t config_len, char *ticker, uint8_t *decimals) {
uint8_t ticker_len, offset = 0; uint8_t ticker_len, offset = 0;
if (config_len == 0){ if (config_len == 0) {
return false; return false;
} }
ticker_len = config[offset++]; ticker_len = config[offset++];
if(ticker_len == 0 || ticker_len > MAX_TICKER_LEN - 2 || config_len - offset < ticker_len){ if (ticker_len == 0 || ticker_len > MAX_TICKER_LEN - 2 || config_len - offset < ticker_len) {
return false; return false;
} }
memcpy(ticker, config+offset, ticker_len); memcpy(ticker, config + offset, ticker_len);
offset += ticker_len; offset += ticker_len;
ticker[ticker_len] = ' '; ticker[ticker_len] = ' ';
ticker[ticker_len+1] = '\0'; ticker[ticker_len + 1] = '\0';
if(config_len - offset < 1){ if (config_len - offset < 1) {
return false; return false;
} }
*decimals = config[offset]; *decimals = config[offset];

View File

@@ -1,19 +1,19 @@
/******************************************************************************* /*******************************************************************************
* Ledger Ethereum App * Ledger Ethereum App
* (c) 2016-2019 Ledger * (c) 2016-2019 Ledger
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
********************************************************************************/ ********************************************************************************/
#ifndef _UTILS_H_ #ifndef _UTILS_H_
#define _UTILS_H_ #define _UTILS_H_
@@ -22,15 +22,20 @@
#include "uint256.h" #include "uint256.h"
void array_hexstr(char *strbuf, const void *bin, unsigned int len); void array_hexstr(char* strbuf, const void* bin, unsigned int len);
void convertUint256BE(uint8_t *data, uint32_t length, uint256_t *target); void convertUint256BE(uint8_t* data, uint32_t length, uint256_t* target);
int local_strchr(char *string, char ch); int local_strchr(char* string, char ch);
uint32_t getV(txContent_t *txContent); uint32_t getV(txContent_t* txContent);
void amountToString(uint8_t* amount, uint8_t amount_len, uint8_t decimals, char* ticker, char* out_buffer, uint8_t out_buffer_size); void amountToString(uint8_t* amount,
uint8_t amount_len,
uint8_t decimals,
char* ticker,
char* out_buffer,
uint8_t out_buffer_size);
bool parse_swap_config(uint8_t* config, uint8_t config_len, char* ticker, uint8_t* decimals); bool parse_swap_config(uint8_t* config, uint8_t config_len, char* ticker, uint8_t* decimals);

View File

@@ -1,31 +1,34 @@
/******************************************************************************* /*******************************************************************************
* Ledger Ethereum App * Ledger Ethereum App
* (c) 2016-2019 Ledger * (c) 2016-2019 Ledger
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
********************************************************************************/ ********************************************************************************/
#include <stdint.h> #include <stdint.h>
#include "ethUstream.h" #include "ethUstream.h"
#include "ethUtils.h" #include "ethUtils.h"
#define MAX_INT256 32 #define MAX_INT256 32
#define MAX_ADDRESS 20 #define MAX_ADDRESS 20
#define MAX_V 4 #define MAX_V 4
void initTx(txContext_t *context, cx_sha3_t *sha3, txContent_t *content, void initTx(txContext_t *context,
ustreamProcess_t customProcessor, void *extra) { cx_sha3_t *sha3,
txContent_t *content,
ustreamProcess_t customProcessor,
void *extra) {
memset(context, 0, sizeof(txContext_t)); memset(context, 0, sizeof(txContext_t));
context->sha3 = sha3; context->sha3 = sha3;
context->content = content; context->content = content;
@@ -48,7 +51,7 @@ uint8_t readTxByte(txContext_t *context) {
context->currentFieldPos++; context->currentFieldPos++;
} }
if (!(context->processingField && context->fieldSingleByte)) { if (!(context->processingField && context->fieldSingleByte)) {
cx_hash((cx_hash_t*)context->sha3, 0, &data, 1, NULL, 0); cx_hash((cx_hash_t *) context->sha3, 0, &data, 1, NULL, 0);
} }
return data; return data;
} }
@@ -62,7 +65,7 @@ void copyTxData(txContext_t *context, uint8_t *out, uint32_t length) {
memmove(out, context->workBuffer, length); memmove(out, context->workBuffer, length);
} }
if (!(context->processingField && context->fieldSingleByte)) { if (!(context->processingField && context->fieldSingleByte)) {
cx_hash((cx_hash_t*)context->sha3, 0, context->workBuffer, length, NULL, 0); cx_hash((cx_hash_t *) context->sha3, 0, context->workBuffer, length, NULL, 0);
} }
context->workBuffer += length; context->workBuffer += length;
context->commandLength -= length; context->commandLength -= length;
@@ -82,7 +85,6 @@ static void processContent(txContext_t *context) {
context->processingField = false; context->processingField = false;
} }
static void processType(txContext_t *context) { static void processType(txContext_t *context) {
if (context->currentFieldIsList) { if (context->currentFieldIsList) {
PRINTF("Invalid type for RLP_TYPE\n"); PRINTF("Invalid type for RLP_TYPE\n");
@@ -93,8 +95,8 @@ static void processType(txContext_t *context) {
THROW(EXCEPTION); THROW(EXCEPTION);
} }
if (context->currentFieldPos < context->currentFieldLength) { if (context->currentFieldPos < context->currentFieldLength) {
uint32_t copySize = MIN(context->commandLength, uint32_t copySize =
context->currentFieldLength - context->currentFieldPos); MIN(context->commandLength, context->currentFieldLength - context->currentFieldPos);
copyTxData(context, NULL, copySize); copyTxData(context, NULL, copySize);
} }
if (context->currentFieldPos == context->currentFieldLength) { if (context->currentFieldPos == context->currentFieldLength) {
@@ -113,8 +115,8 @@ static void processNonce(txContext_t *context) {
THROW(EXCEPTION); THROW(EXCEPTION);
} }
if (context->currentFieldPos < context->currentFieldLength) { if (context->currentFieldPos < context->currentFieldLength) {
uint32_t copySize = MIN(context->commandLength, uint32_t copySize =
context->currentFieldLength - context->currentFieldPos); MIN(context->commandLength, context->currentFieldLength - context->currentFieldPos);
copyTxData(context, NULL, copySize); copyTxData(context, NULL, copySize);
} }
if (context->currentFieldPos == context->currentFieldLength) { if (context->currentFieldPos == context->currentFieldLength) {
@@ -129,16 +131,13 @@ static void processStartGas(txContext_t *context) {
THROW(EXCEPTION); THROW(EXCEPTION);
} }
if (context->currentFieldLength > MAX_INT256) { if (context->currentFieldLength > MAX_INT256) {
PRINTF("Invalid length for RLP_STARTGAS %d\n", PRINTF("Invalid length for RLP_STARTGAS %d\n", context->currentFieldLength);
context->currentFieldLength);
THROW(EXCEPTION); THROW(EXCEPTION);
} }
if (context->currentFieldPos < context->currentFieldLength) { if (context->currentFieldPos < context->currentFieldLength) {
uint32_t copySize = MIN(context->commandLength, uint32_t copySize =
context->currentFieldLength - context->currentFieldPos); MIN(context->commandLength, context->currentFieldLength - context->currentFieldPos);
copyTxData(context, copyTxData(context, context->content->startgas.value + context->currentFieldPos, copySize);
context->content->startgas.value + context->currentFieldPos,
copySize);
} }
if (context->currentFieldPos == context->currentFieldLength) { if (context->currentFieldPos == context->currentFieldLength) {
context->content->startgas.length = context->currentFieldLength; context->content->startgas.length = context->currentFieldLength;
@@ -157,11 +156,9 @@ static void processGasprice(txContext_t *context) {
THROW(EXCEPTION); THROW(EXCEPTION);
} }
if (context->currentFieldPos < context->currentFieldLength) { if (context->currentFieldPos < context->currentFieldLength) {
uint32_t copySize = MIN(context->commandLength, uint32_t copySize =
context->currentFieldLength - context->currentFieldPos); MIN(context->commandLength, context->currentFieldLength - context->currentFieldPos);
copyTxData(context, copyTxData(context, context->content->gasprice.value + context->currentFieldPos, copySize);
context->content->gasprice.value + context->currentFieldPos,
copySize);
} }
if (context->currentFieldPos == context->currentFieldLength) { if (context->currentFieldPos == context->currentFieldLength) {
context->content->gasprice.length = context->currentFieldLength; context->content->gasprice.length = context->currentFieldLength;
@@ -180,11 +177,9 @@ static void processValue(txContext_t *context) {
THROW(EXCEPTION); THROW(EXCEPTION);
} }
if (context->currentFieldPos < context->currentFieldLength) { if (context->currentFieldPos < context->currentFieldLength) {
uint32_t copySize = MIN(context->commandLength, uint32_t copySize =
context->currentFieldLength - context->currentFieldPos); MIN(context->commandLength, context->currentFieldLength - context->currentFieldPos);
copyTxData(context, copyTxData(context, context->content->value.value + context->currentFieldPos, copySize);
context->content->value.value + context->currentFieldPos,
copySize);
} }
if (context->currentFieldPos == context->currentFieldLength) { if (context->currentFieldPos == context->currentFieldLength) {
context->content->value.length = context->currentFieldLength; context->content->value.length = context->currentFieldLength;
@@ -203,11 +198,9 @@ static void processTo(txContext_t *context) {
THROW(EXCEPTION); THROW(EXCEPTION);
} }
if (context->currentFieldPos < context->currentFieldLength) { if (context->currentFieldPos < context->currentFieldLength) {
uint32_t copySize = MIN(context->commandLength, uint32_t copySize =
context->currentFieldLength - context->currentFieldPos); MIN(context->commandLength, context->currentFieldLength - context->currentFieldPos);
copyTxData(context, copyTxData(context, context->content->destination + context->currentFieldPos, copySize);
context->content->destination + context->currentFieldPos,
copySize);
} }
if (context->currentFieldPos == context->currentFieldLength) { if (context->currentFieldPos == context->currentFieldLength) {
context->content->destinationLength = context->currentFieldLength; context->content->destinationLength = context->currentFieldLength;
@@ -222,8 +215,8 @@ static void processData(txContext_t *context) {
THROW(EXCEPTION); THROW(EXCEPTION);
} }
if (context->currentFieldPos < context->currentFieldLength) { if (context->currentFieldPos < context->currentFieldLength) {
uint32_t copySize = MIN(context->commandLength, uint32_t copySize =
context->currentFieldLength - context->currentFieldPos); MIN(context->commandLength, context->currentFieldLength - context->currentFieldPos);
copyTxData(context, NULL, copySize); copyTxData(context, NULL, copySize);
} }
if (context->currentFieldPos == context->currentFieldLength) { if (context->currentFieldPos == context->currentFieldLength) {
@@ -242,11 +235,9 @@ static void processV(txContext_t *context) {
THROW(EXCEPTION); THROW(EXCEPTION);
} }
if (context->currentFieldPos < context->currentFieldLength) { if (context->currentFieldPos < context->currentFieldLength) {
uint32_t copySize = MIN(context->commandLength, uint32_t copySize =
context->currentFieldLength - context->currentFieldPos); MIN(context->commandLength, context->currentFieldLength - context->currentFieldPos);
copyTxData(context, copyTxData(context, context->content->v + context->currentFieldPos, copySize);
context->content->v + context->currentFieldPos,
copySize);
} }
if (context->currentFieldPos == context->currentFieldLength) { if (context->currentFieldPos == context->currentFieldLength) {
context->content->vLength = context->currentFieldLength; context->content->vLength = context->currentFieldLength;
@@ -255,7 +246,6 @@ static void processV(txContext_t *context) {
} }
} }
static parserStatus_e processTxInternal(txContext_t *context) { static parserStatus_e processTxInternal(txContext_t *context) {
for (;;) { for (;;) {
customStatus_e customStatus = CUSTOM_NOT_HANDLED; customStatus_e customStatus = CUSTOM_NOT_HANDLED;
@@ -277,10 +267,8 @@ static parserStatus_e processTxInternal(txContext_t *context) {
while (context->commandLength != 0) { while (context->commandLength != 0) {
bool valid; bool valid;
// Feed the RLP buffer until the length can be decoded // Feed the RLP buffer until the length can be decoded
context->rlpBuffer[context->rlpBufferPos++] = context->rlpBuffer[context->rlpBufferPos++] = readTxByte(context);
readTxByte(context); if (rlpCanDecode(context->rlpBuffer, context->rlpBufferPos, &valid)) {
if (rlpCanDecode(context->rlpBuffer, context->rlpBufferPos,
&valid)) {
// Can decode now, if valid // Can decode now, if valid
if (!valid) { if (!valid) {
PRINTF("RLP pre-decode error\n"); PRINTF("RLP pre-decode error\n");
@@ -300,8 +288,10 @@ static parserStatus_e processTxInternal(txContext_t *context) {
return USTREAM_PROCESSING; return USTREAM_PROCESSING;
} }
// Ready to process this field // Ready to process this field
if (!rlpDecodeLength(context->rlpBuffer, context->rlpBufferPos, if (!rlpDecodeLength(context->rlpBuffer,
&context->currentFieldLength, &offset, context->rlpBufferPos,
&context->currentFieldLength,
&offset,
&context->currentFieldIsList)) { &context->currentFieldIsList)) {
PRINTF("RLP decode error\n"); PRINTF("RLP decode error\n");
return USTREAM_FAULT; return USTREAM_FAULT;
@@ -320,7 +310,7 @@ static parserStatus_e processTxInternal(txContext_t *context) {
} }
if (context->customProcessor != NULL) { if (context->customProcessor != NULL) {
customStatus = context->customProcessor(context); customStatus = context->customProcessor(context);
switch(customStatus) { switch (customStatus) {
case CUSTOM_NOT_HANDLED: case CUSTOM_NOT_HANDLED:
case CUSTOM_HANDLED: case CUSTOM_HANDLED:
break; break;
@@ -336,48 +326,50 @@ static parserStatus_e processTxInternal(txContext_t *context) {
} }
if (customStatus == CUSTOM_NOT_HANDLED) { if (customStatus == CUSTOM_NOT_HANDLED) {
switch (context->currentField) { switch (context->currentField) {
case TX_RLP_CONTENT: case TX_RLP_CONTENT:
processContent(context); processContent(context);
if ((context->processingFlags & TX_FLAG_TYPE) == 0) { if ((context->processingFlags & TX_FLAG_TYPE) == 0) {
context->currentField++; context->currentField++;
} }
break; break;
case TX_RLP_TYPE: case TX_RLP_TYPE:
processType(context); processType(context);
break; break;
case TX_RLP_NONCE: case TX_RLP_NONCE:
processNonce(context); processNonce(context);
break; break;
case TX_RLP_GASPRICE: case TX_RLP_GASPRICE:
processGasprice(context); processGasprice(context);
break; break;
case TX_RLP_STARTGAS: case TX_RLP_STARTGAS:
processStartGas(context); processStartGas(context);
break; break;
case TX_RLP_VALUE: case TX_RLP_VALUE:
processValue(context); processValue(context);
break; break;
case TX_RLP_TO: case TX_RLP_TO:
processTo(context); processTo(context);
break; break;
case TX_RLP_DATA: case TX_RLP_DATA:
case TX_RLP_R: case TX_RLP_R:
case TX_RLP_S: case TX_RLP_S:
processData(context); processData(context);
break; break;
case TX_RLP_V: case TX_RLP_V:
processV(context); processV(context);
break; break;
default: default:
PRINTF("Invalid RLP decoder context\n"); PRINTF("Invalid RLP decoder context\n");
return USTREAM_FAULT; return USTREAM_FAULT;
} }
} }
} }
} }
parserStatus_e processTx(txContext_t *context, uint8_t *buffer, parserStatus_e processTx(txContext_t *context,
uint32_t length, uint32_t processingFlags) { uint8_t *buffer,
uint32_t length,
uint32_t processingFlags) {
parserStatus_e result; parserStatus_e result;
BEGIN_TRY { BEGIN_TRY {
TRY { TRY {

View File

@@ -1,19 +1,19 @@
/******************************************************************************* /*******************************************************************************
* Ledger Ethereum App * Ledger Ethereum App
* (c) 2016-2019 Ledger * (c) 2016-2019 Ledger
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
********************************************************************************/ ********************************************************************************/
#ifndef _ETHUSTREAM_H_ #ifndef _ETHUSTREAM_H_
#define _ETHUSTREAM_H_ #define _ETHUSTREAM_H_
@@ -94,10 +94,15 @@ typedef struct txContext_t {
void *extra; void *extra;
} txContext_t; } txContext_t;
void initTx(txContext_t *context, cx_sha3_t *sha3, txContent_t *content, void initTx(txContext_t *context,
ustreamProcess_t customProcessor, void *extra); cx_sha3_t *sha3,
parserStatus_e processTx(txContext_t *context, uint8_t *buffer, txContent_t *content,
uint32_t length, uint32_t processingFlags); ustreamProcess_t customProcessor,
void *extra);
parserStatus_e processTx(txContext_t *context,
uint8_t *buffer,
uint32_t length,
uint32_t processingFlags);
parserStatus_e continueTx(txContext_t *context); parserStatus_e continueTx(txContext_t *context);
void copyTxData(txContext_t *context, uint8_t *out, uint32_t length); void copyTxData(txContext_t *context, uint8_t *out, uint32_t length);
uint8_t readTxByte(txContext_t *context); uint8_t readTxByte(txContext_t *context);

View File

@@ -1,19 +1,19 @@
/******************************************************************************* /*******************************************************************************
* Ledger Ethereum App * Ledger Ethereum App
* (c) 2016-2019 Ledger * (c) 2016-2019 Ledger
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
********************************************************************************/ ********************************************************************************/
/** /**
* @brief Utilities for an Ethereum Hardware Wallet logic * @brief Utilities for an Ethereum Hardware Wallet logic
@@ -40,7 +40,7 @@ bool rlpCanDecode(uint8_t *buffer, uint32_t bufferLength, bool *valid) {
return false; return false;
} }
if (*buffer > 0xbb) { if (*buffer > 0xbb) {
*valid = false; // arbitrary 32 bits length limitation *valid = false; // arbitrary 32 bits length limitation
return true; return true;
} }
} else if (*buffer <= 0xf7) { } else if (*buffer <= 0xf7) {
@@ -49,7 +49,7 @@ bool rlpCanDecode(uint8_t *buffer, uint32_t bufferLength, bool *valid) {
return false; return false;
} }
if (*buffer > 0xfb) { if (*buffer > 0xfb) {
*valid = false; // arbitrary 32 bits length limitation *valid = false; // arbitrary 32 bits length limitation
return true; return true;
} }
} }
@@ -57,8 +57,11 @@ bool rlpCanDecode(uint8_t *buffer, uint32_t bufferLength, bool *valid) {
return true; return true;
} }
bool rlpDecodeLength(uint8_t *buffer, uint32_t bufferLength, bool rlpDecodeLength(uint8_t *buffer,
uint32_t *fieldLength, uint32_t *offset, bool *list) { uint32_t bufferLength,
uint32_t *fieldLength,
uint32_t *offset,
bool *list) {
if (*buffer <= 0x7f) { if (*buffer <= 0x7f) {
*offset = 0; *offset = 0;
*fieldLength = 1; *fieldLength = 1;
@@ -71,22 +74,21 @@ bool rlpDecodeLength(uint8_t *buffer, uint32_t bufferLength,
*offset = 1 + (*buffer - 0xb7); *offset = 1 + (*buffer - 0xb7);
*list = false; *list = false;
switch (*buffer) { switch (*buffer) {
case 0xb8: case 0xb8:
*fieldLength = *(buffer + 1); *fieldLength = *(buffer + 1);
break; break;
case 0xb9: case 0xb9:
*fieldLength = (*(buffer + 1) << 8) + *(buffer + 2); *fieldLength = (*(buffer + 1) << 8) + *(buffer + 2);
break; break;
case 0xba: case 0xba:
*fieldLength = *fieldLength = (*(buffer + 1) << 16) + (*(buffer + 2) << 8) + *(buffer + 3);
(*(buffer + 1) << 16) + (*(buffer + 2) << 8) + *(buffer + 3); break;
break; case 0xbb:
case 0xbb: *fieldLength = (*(buffer + 1) << 24) + (*(buffer + 2) << 16) +
*fieldLength = (*(buffer + 1) << 24) + (*(buffer + 2) << 16) + (*(buffer + 3) << 8) + *(buffer + 4);
(*(buffer + 3) << 8) + *(buffer + 4); break;
break; default:
default: return false; // arbitrary 32 bits length limitation
return false; // arbitrary 32 bits length limitation
} }
} else if (*buffer <= 0xf7) { } else if (*buffer <= 0xf7) {
*offset = 1; *offset = 1;
@@ -96,43 +98,39 @@ bool rlpDecodeLength(uint8_t *buffer, uint32_t bufferLength,
*offset = 1 + (*buffer - 0xf7); *offset = 1 + (*buffer - 0xf7);
*list = true; *list = true;
switch (*buffer) { switch (*buffer) {
case 0xf8: case 0xf8:
*fieldLength = *(buffer + 1); *fieldLength = *(buffer + 1);
break; break;
case 0xf9: case 0xf9:
*fieldLength = (*(buffer + 1) << 8) + *(buffer + 2); *fieldLength = (*(buffer + 1) << 8) + *(buffer + 2);
break; break;
case 0xfa: case 0xfa:
*fieldLength = *fieldLength = (*(buffer + 1) << 16) + (*(buffer + 2) << 8) + *(buffer + 3);
(*(buffer + 1) << 16) + (*(buffer + 2) << 8) + *(buffer + 3); break;
break; case 0xfb:
case 0xfb: *fieldLength = (*(buffer + 1) << 24) + (*(buffer + 2) << 16) +
*fieldLength = (*(buffer + 1) << 24) + (*(buffer + 2) << 16) + (*(buffer + 3) << 8) + *(buffer + 4);
(*(buffer + 3) << 8) + *(buffer + 4); break;
break; default:
default: return false; // arbitrary 32 bits length limitation
return false; // arbitrary 32 bits length limitation
} }
} }
return true; return true;
} }
void getEthAddressFromKey(cx_ecfp_public_key_t *publicKey, uint8_t *out, void getEthAddressFromKey(cx_ecfp_public_key_t *publicKey, uint8_t *out, cx_sha3_t *sha3Context) {
cx_sha3_t *sha3Context) {
uint8_t hashAddress[32]; uint8_t hashAddress[32];
cx_keccak_init(sha3Context, 256); cx_keccak_init(sha3Context, 256);
cx_hash((cx_hash_t*)sha3Context, CX_LAST, publicKey->W + 1, 64, hashAddress, 32); cx_hash((cx_hash_t *) sha3Context, CX_LAST, publicKey->W + 1, 64, hashAddress, 32);
memmove(out, hashAddress + 12, 20); memmove(out, hashAddress + 12, 20);
} }
#ifdef CHECKSUM_1 #ifdef CHECKSUM_1
static const uint8_t const HEXDIGITS[] = "0123456789ABCDEF"; static const uint8_t const HEXDIGITS[] = "0123456789ABCDEF";
static const uint8_t const MASK[] = {0x80, 0x40, 0x20, 0x10, static const uint8_t const MASK[] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
0x08, 0x04, 0x02, 0x01};
char convertDigit(uint8_t *address, uint8_t index, uint8_t *hash) { char convertDigit(uint8_t *address, uint8_t index, uint8_t *hash) {
unsigned char digit = address[index / 2]; unsigned char digit = address[index / 2];
@@ -153,21 +151,25 @@ char convertDigit(uint8_t *address, uint8_t index, uint8_t *hash) {
} }
} }
void getEthAddressStringFromKey(cx_ecfp_public_key_t *publicKey, uint8_t *out, void getEthAddressStringFromKey(cx_ecfp_public_key_t *publicKey,
cx_sha3_t *sha3Context, chain_config_t* chain_config) { uint8_t *out,
cx_sha3_t *sha3Context,
chain_config_t *chain_config) {
uint8_t hashAddress[32]; uint8_t hashAddress[32];
cx_keccak_init(sha3Context, 256); cx_keccak_init(sha3Context, 256);
cx_hash((cx_hash_t*)sha3Context, CX_LAST, publicKey->W + 1, 64, hashAddress, 32); cx_hash((cx_hash_t *) sha3Context, CX_LAST, publicKey->W + 1, 64, hashAddress, 32);
getEthAddressStringFromBinary(hashAddress + 12, out, sha3Context, chain_config); getEthAddressStringFromBinary(hashAddress + 12, out, sha3Context, chain_config);
} }
void getEthAddressStringFromBinary(uint8_t *address, uint8_t *out, void getEthAddressStringFromBinary(uint8_t *address,
cx_sha3_t *sha3Context, chain_config_t* chain_config) { uint8_t *out,
cx_sha3_t *sha3Context,
chain_config_t *chain_config) {
UNUSED(chain_config); UNUSED(chain_config);
uint8_t hashChecksum[32]; uint8_t hashChecksum[32];
uint8_t i; uint8_t i;
cx_keccak_init(sha3Context, 256); cx_keccak_init(sha3Context, 256);
cx_hash((cx_hash_t*)sha3Context, CX_LAST, address, 20, hashChecksum, 32); cx_hash((cx_hash_t *) sha3Context, CX_LAST, address, 20, hashChecksum, 32);
for (i = 0; i < 40; i++) { for (i = 0; i < 40; i++) {
out[i] = convertDigit(address, i, hashChecksum); out[i] = convertDigit(address, i, hashChecksum);
} }
@@ -178,20 +180,22 @@ void getEthAddressStringFromBinary(uint8_t *address, uint8_t *out,
static const uint8_t const HEXDIGITS[] = "0123456789abcdef"; static const uint8_t const HEXDIGITS[] = "0123456789abcdef";
void getEthAddressStringFromKey(cx_ecfp_public_key_t *publicKey, uint8_t *out, void getEthAddressStringFromKey(cx_ecfp_public_key_t *publicKey,
cx_sha3_t *sha3Context, chain_config_t* chain_config) { uint8_t *out,
cx_sha3_t *sha3Context,
chain_config_t *chain_config) {
uint8_t hashAddress[32]; uint8_t hashAddress[32];
cx_keccak_init(sha3Context, 256); cx_keccak_init(sha3Context, 256);
cx_hash((cx_hash_t*)sha3Context, CX_LAST, publicKey->W + 1, 64, hashAddress, 32); cx_hash((cx_hash_t *) sha3Context, CX_LAST, publicKey->W + 1, 64, hashAddress, 32);
getEthAddressStringFromBinary(hashAddress + 12, out, sha3Context, chain_config); getEthAddressStringFromBinary(hashAddress + 12, out, sha3Context, chain_config);
} }
void getEthAddressStringFromBinary(uint8_t *address, uint8_t *out, void getEthAddressStringFromBinary(uint8_t *address,
cx_sha3_t *sha3Context, chain_config_t* chain_config) { uint8_t *out,
cx_sha3_t *sha3Context,
chain_config_t *chain_config) {
// save some precious stack space // save some precious stack space
union locals_union union locals_union {
{
uint8_t hashChecksum[32]; uint8_t hashChecksum[32];
uint8_t tmp[51]; uint8_t tmp[51];
} locals_union; } locals_union;
@@ -199,15 +203,18 @@ void getEthAddressStringFromBinary(uint8_t *address, uint8_t *out,
uint8_t i; uint8_t i;
bool eip1191 = false; bool eip1191 = false;
uint32_t offset = 0; uint32_t offset = 0;
switch(chain_config->chainId) { switch (chain_config->chainId) {
case 30: case 30:
case 31: case 31:
eip1191 = true; eip1191 = true;
break; break;
} }
if (eip1191) { if (eip1191) {
snprintf((char*)locals_union.tmp, sizeof(locals_union.tmp), "%d0x", chain_config->chainId); snprintf((char *) locals_union.tmp,
offset = strlen((char*)locals_union.tmp); sizeof(locals_union.tmp),
"%d0x",
chain_config->chainId);
offset = strlen((char *) locals_union.tmp);
} }
for (i = 0; i < 20; i++) { for (i = 0; i < 20; i++) {
uint8_t digit = address[i]; uint8_t digit = address[i];
@@ -215,7 +222,12 @@ void getEthAddressStringFromBinary(uint8_t *address, uint8_t *out,
locals_union.tmp[offset + 2 * i + 1] = HEXDIGITS[digit & 0x0f]; locals_union.tmp[offset + 2 * i + 1] = HEXDIGITS[digit & 0x0f];
} }
cx_keccak_init(sha3Context, 256); cx_keccak_init(sha3Context, 256);
cx_hash((cx_hash_t*)sha3Context, CX_LAST, locals_union.tmp, offset + 40, locals_union.hashChecksum, 32); cx_hash((cx_hash_t *) sha3Context,
CX_LAST,
locals_union.tmp,
offset + 40,
locals_union.hashChecksum,
32);
for (i = 0; i < 40; i++) { for (i = 0; i < 40; i++) {
uint8_t digit = address[i / 2]; uint8_t digit = address[i / 2];
if ((i % 2) == 0) { if ((i % 2) == 0) {
@@ -225,13 +237,11 @@ void getEthAddressStringFromBinary(uint8_t *address, uint8_t *out,
} }
if (digit < 10) { if (digit < 10) {
out[i] = HEXDIGITS[digit]; out[i] = HEXDIGITS[digit];
} } else {
else {
int v = (locals_union.hashChecksum[i / 2] >> (4 * (1 - i % 2))) & 0x0f; int v = (locals_union.hashChecksum[i / 2] >> (4 * (1 - i % 2))) & 0x0f;
if (v >= 8) { if (v >= 8) {
out[i] = HEXDIGITS[digit] - 'a' + 'A'; out[i] = HEXDIGITS[digit] - 'a' + 'A';
} } else {
else {
out[i] = HEXDIGITS[digit]; out[i] = HEXDIGITS[digit];
} }
} }
@@ -241,14 +251,17 @@ void getEthAddressStringFromBinary(uint8_t *address, uint8_t *out,
#endif #endif
bool adjustDecimals(char *src, uint32_t srcLength, char *target, bool adjustDecimals(char *src,
uint32_t targetLength, uint8_t decimals) { uint32_t srcLength,
char *target,
uint32_t targetLength,
uint8_t decimals) {
uint32_t startOffset; uint32_t startOffset;
uint32_t lastZeroOffset = 0; uint32_t lastZeroOffset = 0;
uint32_t offset = 0; uint32_t offset = 0;
if ((srcLength == 1) && (*src == '0')) { if ((srcLength == 1) && (*src == '0')) {
if (targetLength < 2) { if (targetLength < 2) {
return false; return false;
} }
target[0] = '0'; target[0] = '0';
target[1] = '\0'; target[1] = '\0';
@@ -285,7 +298,7 @@ bool adjustDecimals(char *src, uint32_t srcLength, char *target,
while (sourceOffset < srcLength) { while (sourceOffset < srcLength) {
target[offset++] = src[sourceOffset++]; target[offset++] = src[sourceOffset++];
} }
target[offset] = '\0'; target[offset] = '\0';
} }
for (uint32_t i = startOffset; i < offset; i++) { for (uint32_t i = startOffset; i < offset; i++) {
if (target[i] == '0') { if (target[i] == '0') {
@@ -299,7 +312,7 @@ bool adjustDecimals(char *src, uint32_t srcLength, char *target,
if (lastZeroOffset != 0) { if (lastZeroOffset != 0) {
target[lastZeroOffset] = '\0'; target[lastZeroOffset] = '\0';
if (target[lastZeroOffset - 1] == '.') { if (target[lastZeroOffset - 1] == '.') {
target[lastZeroOffset - 1] = '\0'; target[lastZeroOffset - 1] = '\0';
} }
} }
return true; return true;

View File

@@ -1,19 +1,19 @@
/******************************************************************************* /*******************************************************************************
* Ledger Ethereum App * Ledger Ethereum App
* (c) 2016-2019 Ledger * (c) 2016-2019 Ledger
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
********************************************************************************/ ********************************************************************************/
#ifndef _ETHUTILS_H_ #ifndef _ETHUTILS_H_
#define _ETHUTILS_H_ #define _ETHUTILS_H_
@@ -34,42 +34,47 @@
* string * string
* @return true if the RLP header is consistent * @return true if the RLP header is consistent
*/ */
bool rlpDecodeLength(uint8_t *buffer, uint32_t bufferLength, bool rlpDecodeLength(uint8_t *buffer,
uint32_t *fieldLength, uint32_t *offset, bool *list); uint32_t bufferLength,
uint32_t *fieldLength,
uint32_t *offset,
bool *list);
bool rlpCanDecode(uint8_t *buffer, uint32_t bufferLength, bool *valid); bool rlpCanDecode(uint8_t *buffer, uint32_t bufferLength, bool *valid);
void getEthAddressFromKey(cx_ecfp_public_key_t *publicKey, uint8_t *out, void getEthAddressFromKey(cx_ecfp_public_key_t *publicKey, uint8_t *out, cx_sha3_t *sha3Context);
cx_sha3_t *sha3Context);
void getEthAddressStringFromKey(cx_ecfp_public_key_t *publicKey, uint8_t *out, void getEthAddressStringFromKey(cx_ecfp_public_key_t *publicKey,
uint8_t *out,
cx_sha3_t *sha3Context, cx_sha3_t *sha3Context,
chain_config_t* chain_config); chain_config_t *chain_config);
void getEthAddressStringFromBinary(uint8_t *address, uint8_t *out, void getEthAddressStringFromBinary(uint8_t *address,
cx_sha3_t *sha3Context, uint8_t *out,
chain_config_t* chain_config); cx_sha3_t *sha3Context,
chain_config_t *chain_config);
bool adjustDecimals(char *src, uint32_t srcLength, char *target, bool adjustDecimals(char *src,
uint32_t targetLength, uint8_t decimals); uint32_t srcLength,
char *target,
uint32_t targetLength,
uint8_t decimals);
__attribute__((no_instrument_function)) __attribute__((no_instrument_function)) inline int allzeroes(uint8_t *buf, int n) {
inline int allzeroes(uint8_t *buf, int n) { for (int i = 0; i < n; ++i) {
for (int i = 0; i < n; ++i) { if (buf[i]) {
if (buf[i]) { return 0;
return 0; }
} }
} return 1;
return 1;
} }
__attribute__((no_instrument_function)) __attribute__((no_instrument_function)) inline int ismaxint(uint8_t *buf, int n) {
inline int ismaxint(uint8_t *buf, int n) { for (int i = 0; i < n; ++i) {
for (int i = 0; i < n; ++i) { if (buf[i] != 0xff) {
if (buf[i] != 0xff) { return 0;
return 0; }
} }
} return 1;
return 1;
} }
#endif /* _ETHUTILS_H_ */ #endif /* _ETHUTILS_H_ */

View File

@@ -1,19 +1,19 @@
/******************************************************************************* /*******************************************************************************
* Ledger Ethereum App * Ledger Ethereum App
* (c) 2016-2019 Ledger * (c) 2016-2019 Ledger
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
********************************************************************************/ ********************************************************************************/
// Adapted from https://github.com/calccrypto/uint256_t // Adapted from https://github.com/calccrypto/uint256_t
@@ -25,10 +25,10 @@
static const char HEXDIGITS[] = "0123456789abcdef"; static const char HEXDIGITS[] = "0123456789abcdef";
static uint64_t readUint64BE(uint8_t *buffer) { static uint64_t readUint64BE(uint8_t *buffer) {
return (((uint64_t)buffer[0]) << 56) | (((uint64_t)buffer[1]) << 48) | return (((uint64_t) buffer[0]) << 56) | (((uint64_t) buffer[1]) << 48) |
(((uint64_t)buffer[2]) << 40) | (((uint64_t)buffer[3]) << 32) | (((uint64_t) buffer[2]) << 40) | (((uint64_t) buffer[3]) << 32) |
(((uint64_t)buffer[4]) << 24) | (((uint64_t)buffer[5]) << 16) | (((uint64_t) buffer[4]) << 24) | (((uint64_t) buffer[5]) << 16) |
(((uint64_t)buffer[6]) << 8) | (((uint64_t)buffer[7])); (((uint64_t) buffer[6]) << 8) | (((uint64_t) buffer[7]));
} }
void readu128BE(uint8_t *buffer, uint128_t *target) { void readu128BE(uint8_t *buffer, uint128_t *target) {
@@ -78,8 +78,7 @@ void shiftl128(uint128_t *number, uint32_t value, uint128_t *target) {
} else if (value == 0) { } else if (value == 0) {
copy128(target, number); copy128(target, number);
} else if (value < 64) { } else if (value < 64) {
UPPER_P(target) = UPPER_P(target) = (UPPER_P(number) << value) + (LOWER_P(number) >> (64 - value));
(UPPER_P(number) << value) + (LOWER_P(number) >> (64 - value));
LOWER_P(target) = (LOWER_P(number) << value); LOWER_P(target) = (LOWER_P(number) << value);
} else if ((128 > value) && (value > 64)) { } else if ((128 > value) && (value > 64)) {
UPPER_P(target) = LOWER_P(number) << (value - 64); UPPER_P(target) = LOWER_P(number) << (value - 64);
@@ -125,8 +124,7 @@ void shiftr128(uint128_t *number, uint32_t value, uint128_t *target) {
} else if (value < 64) { } else if (value < 64) {
uint128_t result; uint128_t result;
UPPER(result) = UPPER_P(number) >> value; UPPER(result) = UPPER_P(number) >> value;
LOWER(result) = LOWER(result) = (UPPER_P(number) << (64 - value)) + (LOWER_P(number) >> value);
(UPPER_P(number) << (64 - value)) + (LOWER_P(number) >> value);
copy128(target, &result); copy128(target, &result);
} else if ((128 > value) && (value > 64)) { } else if ((128 > value) && (value > 64)) {
LOWER_P(target) = UPPER_P(number) >> (value - 64); LOWER_P(target) = UPPER_P(number) >> (value - 64);
@@ -202,8 +200,7 @@ uint32_t bits256(uint256_t *number) {
} }
bool equal128(uint128_t *number1, uint128_t *number2) { bool equal128(uint128_t *number1, uint128_t *number2) {
return (UPPER_P(number1) == UPPER_P(number2)) && return (UPPER_P(number1) == UPPER_P(number2)) && (LOWER_P(number1) == LOWER_P(number2));
(LOWER_P(number1) == LOWER_P(number2));
} }
bool equal256(uint256_t *number1, uint256_t *number2) { bool equal256(uint256_t *number1, uint256_t *number2) {
@@ -234,9 +231,8 @@ bool gte256(uint256_t *number1, uint256_t *number2) {
} }
void add128(uint128_t *number1, uint128_t *number2, uint128_t *target) { void add128(uint128_t *number1, uint128_t *number2, uint128_t *target) {
UPPER_P(target) = UPPER_P(target) = UPPER_P(number1) + UPPER_P(number2) +
UPPER_P(number1) + UPPER_P(number2) + ((LOWER_P(number1) + LOWER_P(number2)) < LOWER_P(number1));
((LOWER_P(number1) + LOWER_P(number2)) < LOWER_P(number1));
LOWER_P(target) = LOWER_P(number1) + LOWER_P(number2); LOWER_P(target) = LOWER_P(number1) + LOWER_P(number2);
} }
@@ -254,9 +250,8 @@ void add256(uint256_t *number1, uint256_t *number2, uint256_t *target) {
} }
void minus128(uint128_t *number1, uint128_t *number2, uint128_t *target) { void minus128(uint128_t *number1, uint128_t *number2, uint128_t *target) {
UPPER_P(target) = UPPER_P(target) = UPPER_P(number1) - UPPER_P(number2) -
UPPER_P(number1) - UPPER_P(number2) - ((LOWER_P(number1) - LOWER_P(number2)) > LOWER_P(number1));
((LOWER_P(number1) - LOWER_P(number2)) > LOWER_P(number1));
LOWER_P(target) = LOWER_P(number1) - LOWER_P(number2); LOWER_P(target) = LOWER_P(number1) - LOWER_P(number2);
} }
@@ -284,9 +279,12 @@ void or256(uint256_t *number1, uint256_t *number2, uint256_t *target) {
} }
void mul128(uint128_t *number1, uint128_t *number2, uint128_t *target) { void mul128(uint128_t *number1, uint128_t *number2, uint128_t *target) {
uint64_t top[4] = {UPPER_P(number1) >> 32, UPPER_P(number1) & 0xffffffff, uint64_t top[4] = {UPPER_P(number1) >> 32,
LOWER_P(number1) >> 32, LOWER_P(number1) & 0xffffffff}; UPPER_P(number1) & 0xffffffff,
uint64_t bottom[4] = {UPPER_P(number2) >> 32, UPPER_P(number2) & 0xffffffff, LOWER_P(number1) >> 32,
LOWER_P(number1) & 0xffffffff};
uint64_t bottom[4] = {UPPER_P(number2) >> 32,
UPPER_P(number2) & 0xffffffff,
LOWER_P(number2) >> 32, LOWER_P(number2) >> 32,
LOWER_P(number2) & 0xffffffff}; LOWER_P(number2) & 0xffffffff};
uint64_t products[4][4]; uint64_t products[4][4];
@@ -337,7 +335,7 @@ void write_u64_be(uint8_t *buffer, uint64_t value) {
} }
void read_u64_be(uint8_t *in, uint64_t *out) { void read_u64_be(uint8_t *in, uint64_t *out) {
uint8_t *out_ptr = (uint8_t*)out; uint8_t *out_ptr = (uint8_t *) out;
*out_ptr++ = in[7]; *out_ptr++ = in[7];
*out_ptr++ = in[6]; *out_ptr++ = in[6];
*out_ptr++ = in[5]; *out_ptr++ = in[5];
@@ -351,18 +349,17 @@ void read_u64_be(uint8_t *in, uint64_t *out) {
void mul256(uint256_t *number1, uint256_t *number2, uint256_t *target) { void mul256(uint256_t *number1, uint256_t *number2, uint256_t *target) {
uint8_t num1[32], num2[32], result[64]; uint8_t num1[32], num2[32], result[64];
memset(&result, 0, sizeof(result)); memset(&result, 0, sizeof(result));
for(uint8_t i = 0; i<4; i++){ for (uint8_t i = 0; i < 4; i++) {
write_u64_be(num1+i*sizeof(uint64_t), number1->elements[i/2].elements[i%2]); write_u64_be(num1 + i * sizeof(uint64_t), number1->elements[i / 2].elements[i % 2]);
write_u64_be(num2+i*sizeof(uint64_t), number2->elements[i/2].elements[i%2]); write_u64_be(num2 + i * sizeof(uint64_t), number2->elements[i / 2].elements[i % 2]);
} }
cx_math_mult(result, num1, num2, sizeof(num1)); cx_math_mult(result, num1, num2, sizeof(num1));
for(uint8_t i = 0; i<4; i++){ for (uint8_t i = 0; i < 4; i++) {
read_u64_be(result+32+i*sizeof(uint64_t), &target->elements[i/2].elements[i%2]); read_u64_be(result + 32 + i * sizeof(uint64_t), &target->elements[i / 2].elements[i % 2]);
} }
} }
void divmod128(uint128_t *l, uint128_t *r, uint128_t *retDiv, void divmod128(uint128_t *l, uint128_t *r, uint128_t *retDiv, uint128_t *retMod) {
uint128_t *retMod) {
uint128_t copyd, adder, resDiv, resMod; uint128_t copyd, adder, resDiv, resMod;
uint128_t one; uint128_t one;
UPPER(one) = 0; UPPER(one) = 0;
@@ -393,8 +390,7 @@ void divmod128(uint128_t *l, uint128_t *r, uint128_t *retDiv,
} }
} }
void divmod256(uint256_t *l, uint256_t *r, uint256_t *retDiv, void divmod256(uint256_t *l, uint256_t *r, uint256_t *retDiv, uint256_t *retMod) {
uint256_t *retMod) {
uint256_t copyd, adder, resDiv, resMod; uint256_t copyd, adder, resDiv, resMod;
uint256_t one; uint256_t one;
clear256(&one); clear256(&one);
@@ -436,8 +432,7 @@ static void reverseString(char *str, uint32_t length) {
} }
} }
bool tostring128(uint128_t *number, uint32_t baseParam, char *out, bool tostring128(uint128_t *number, uint32_t baseParam, char *out, uint32_t outLength) {
uint32_t outLength) {
uint128_t rDiv; uint128_t rDiv;
uint128_t rMod; uint128_t rMod;
uint128_t base; uint128_t base;
@@ -454,15 +449,14 @@ bool tostring128(uint128_t *number, uint32_t baseParam, char *out,
return false; return false;
} }
divmod128(&rDiv, &base, &rDiv, &rMod); divmod128(&rDiv, &base, &rDiv, &rMod);
out[offset++] = HEXDIGITS[(uint8_t)LOWER(rMod)]; out[offset++] = HEXDIGITS[(uint8_t) LOWER(rMod)];
} while (!zero128(&rDiv)); } while (!zero128(&rDiv));
out[offset] = '\0'; out[offset] = '\0';
reverseString(out, offset); reverseString(out, offset);
return true; return true;
} }
bool tostring256(uint256_t *number, uint32_t baseParam, char *out, bool tostring256(uint256_t *number, uint32_t baseParam, char *out, uint32_t outLength) {
uint32_t outLength) {
uint256_t rDiv; uint256_t rDiv;
uint256_t rMod; uint256_t rMod;
uint256_t base; uint256_t base;
@@ -480,7 +474,7 @@ bool tostring256(uint256_t *number, uint32_t baseParam, char *out,
return false; return false;
} }
divmod256(&rDiv, &base, &rDiv, &rMod); divmod256(&rDiv, &base, &rDiv, &rMod);
out[offset++] = HEXDIGITS[(uint8_t)LOWER(LOWER(rMod))]; out[offset++] = HEXDIGITS[(uint8_t) LOWER(LOWER(rMod))];
} while (!zero256(&rDiv)); } while (!zero256(&rDiv));
out[offset] = '\0'; out[offset] = '\0';
reverseString(out, offset); reverseString(out, offset);

View File

@@ -1,19 +1,19 @@
/******************************************************************************* /*******************************************************************************
* Ledger Ethereum App * Ledger Ethereum App
* (c) 2016-2019 Ledger * (c) 2016-2019 Ledger
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
********************************************************************************/ ********************************************************************************/
// Adapted from https://github.com/calccrypto/uint256_t // Adapted from https://github.com/calccrypto/uint256_t
@@ -25,14 +25,18 @@
#include "os.h" #include "os.h"
#include "cx.h" #include "cx.h"
typedef struct uint128_t { uint64_t elements[2]; } uint128_t; typedef struct uint128_t {
uint64_t elements[2];
} uint128_t;
typedef struct uint256_t { uint128_t elements[2]; } uint256_t; typedef struct uint256_t {
uint128_t elements[2];
} uint256_t;
#define UPPER_P(x) x->elements[0] #define UPPER_P(x) x->elements[0]
#define LOWER_P(x) x->elements[1] #define LOWER_P(x) x->elements[1]
#define UPPER(x) x.elements[0] #define UPPER(x) x.elements[0]
#define LOWER(x) x.elements[1] #define LOWER(x) x.elements[1]
void readu128BE(uint8_t *buffer, uint128_t *target); void readu128BE(uint8_t *buffer, uint128_t *target);
void readu256BE(uint8_t *buffer, uint256_t *target); void readu256BE(uint8_t *buffer, uint256_t *target);
@@ -64,9 +68,7 @@ void mul128(uint128_t *number1, uint128_t *number2, uint128_t *target);
void mul256(uint256_t *number1, uint256_t *number2, uint256_t *target); void mul256(uint256_t *number1, uint256_t *number2, uint256_t *target);
void divmod128(uint128_t *l, uint128_t *r, uint128_t *div, uint128_t *mod); void divmod128(uint128_t *l, uint128_t *r, uint128_t *div, uint128_t *mod);
void divmod256(uint256_t *l, uint256_t *r, uint256_t *div, uint256_t *mod); void divmod256(uint256_t *l, uint256_t *r, uint256_t *div, uint256_t *mod);
bool tostring128(uint128_t *number, uint32_t base, char *out, bool tostring128(uint128_t *number, uint32_t base, char *out, uint32_t outLength);
uint32_t outLength); bool tostring256(uint256_t *number, uint32_t base, char *out, uint32_t outLength);
bool tostring256(uint256_t *number, uint32_t base, char *out,
uint32_t outLength);
#endif /* _UINT256_H_ */ #endif /* _UINT256_H_ */

View File

@@ -1,6 +1,7 @@
#include "shared_context.h" #include "shared_context.h"
#include "ui_callbacks.h" #include "ui_callbacks.h"
// clang-format off
UX_STEP_NOCB(ux_approval_allowance_1_step, UX_STEP_NOCB(ux_approval_allowance_1_step,
pnn, pnn,
{ {
@@ -59,14 +60,13 @@ UX_STEP_CB(
&C_icon_crossmark, &C_icon_crossmark,
"Reject", "Reject",
}); });
// clang-format on
UX_FLOW(ux_approval_allowance_flow, UX_FLOW(ux_approval_allowance_flow,
&ux_approval_allowance_1_step, &ux_approval_allowance_1_step,
&ux_approval_allowance_2_step, &ux_approval_allowance_2_step,
&ux_approval_allowance_3_step, &ux_approval_allowance_3_step,
&ux_approval_allowance_4_step, &ux_approval_allowance_4_step,
&ux_approval_allowance_5_step, &ux_approval_allowance_5_step,
&ux_approval_allowance_6_step, &ux_approval_allowance_6_step,
&ux_approval_allowance_7_step &ux_approval_allowance_7_step);
);

View File

@@ -3,24 +3,28 @@
#include "ui_flow.h" #include "ui_flow.h"
void handleGetAppConfiguration(uint8_t p1, uint8_t p2, uint8_t *workBuffer, uint16_t dataLength, unsigned int *flags, unsigned int *tx) { void handleGetAppConfiguration(uint8_t p1,
UNUSED(p1); uint8_t p2,
UNUSED(p2); uint8_t *workBuffer,
UNUSED(workBuffer); uint16_t dataLength,
UNUSED(dataLength); unsigned int *flags,
UNUSED(flags); unsigned int *tx) {
G_io_apdu_buffer[0] = (N_storage.dataAllowed ? APP_FLAG_DATA_ALLOWED : 0x00); UNUSED(p1);
UNUSED(p2);
UNUSED(workBuffer);
UNUSED(dataLength);
UNUSED(flags);
G_io_apdu_buffer[0] = (N_storage.dataAllowed ? APP_FLAG_DATA_ALLOWED : 0x00);
#ifndef HAVE_TOKENS_LIST #ifndef HAVE_TOKENS_LIST
G_io_apdu_buffer[0] |= APP_FLAG_EXTERNAL_TOKEN_NEEDED; G_io_apdu_buffer[0] |= APP_FLAG_EXTERNAL_TOKEN_NEEDED;
#endif #endif
#ifdef HAVE_STARKWARE #ifdef HAVE_STARKWARE
G_io_apdu_buffer[0] |= APP_FLAG_STARKWARE; G_io_apdu_buffer[0] |= APP_FLAG_STARKWARE;
G_io_apdu_buffer[0] |= APP_FLAG_STARKWARE_V2; G_io_apdu_buffer[0] |= APP_FLAG_STARKWARE_V2;
#endif #endif
G_io_apdu_buffer[1] = LEDGER_MAJOR_VERSION; G_io_apdu_buffer[1] = LEDGER_MAJOR_VERSION;
G_io_apdu_buffer[2] = LEDGER_MINOR_VERSION; G_io_apdu_buffer[2] = LEDGER_MINOR_VERSION;
G_io_apdu_buffer[3] = LEDGER_PATCH_VERSION; G_io_apdu_buffer[3] = LEDGER_PATCH_VERSION;
*tx = 4; *tx = 4;
THROW(0x9000); THROW(0x9000);
} }

View File

@@ -6,75 +6,81 @@
#include "ui_flow.h" #include "ui_flow.h"
#include "feature_getEth2PublicKey.h" #include "feature_getEth2PublicKey.h"
static const uint8_t BLS12_381_FIELD_MODULUS[] = { 0x1a, 0x01, 0x11, 0xea, 0x39, 0x7f, 0xe6, 0x9a, 0x4b, 0x1b, 0xa7, 0xb6, 0x43, 0x4b, 0xac, 0xd7, 0x64, 0x77, 0x4b, 0x84, 0xf3, 0x85, 0x12, 0xbf, 0x67, 0x30, 0xd2, 0xa0, 0xf6, 0xb0, 0xf6, 0x24, 0x1e, 0xab, 0xff, 0xfe, 0xb1, 0x53, 0xff, 0xff, 0xb9, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xaa, 0xab }; static const uint8_t BLS12_381_FIELD_MODULUS[] = {
0x1a, 0x01, 0x11, 0xea, 0x39, 0x7f, 0xe6, 0x9a, 0x4b, 0x1b, 0xa7, 0xb6, 0x43, 0x4b, 0xac, 0xd7,
0x64, 0x77, 0x4b, 0x84, 0xf3, 0x85, 0x12, 0xbf, 0x67, 0x30, 0xd2, 0xa0, 0xf6, 0xb0, 0xf6, 0x24,
0x1e, 0xab, 0xff, 0xfe, 0xb1, 0x53, 0xff, 0xff, 0xb9, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xaa, 0xab};
void getEth2PublicKey(uint32_t *bip32Path, uint8_t bip32PathLength, uint8_t *out) { void getEth2PublicKey(uint32_t *bip32Path, uint8_t bip32PathLength, uint8_t *out) {
uint8_t privateKeyData[32]; uint8_t privateKeyData[32];
cx_ecfp_256_extended_private_key_t privateKey; cx_ecfp_256_extended_private_key_t privateKey;
cx_ecfp_384_public_key_t publicKey; cx_ecfp_384_public_key_t publicKey;
uint8_t yFlag = 0; uint8_t yFlag = 0;
uint8_t tmp[96]; uint8_t tmp[96];
io_seproxyhal_io_heartbeat(); io_seproxyhal_io_heartbeat();
os_perso_derive_eip2333(CX_CURVE_BLS12_381_G1, bip32Path, bip32PathLength, privateKeyData); os_perso_derive_eip2333(CX_CURVE_BLS12_381_G1, bip32Path, bip32PathLength, privateKeyData);
io_seproxyhal_io_heartbeat(); io_seproxyhal_io_heartbeat();
memset(tmp, 0, 48); memset(tmp, 0, 48);
memmove(tmp + 16, privateKeyData, 32); memmove(tmp + 16, privateKeyData, 32);
cx_ecfp_init_private_key(CX_CURVE_BLS12_381_G1, tmp, 48, &privateKey); cx_ecfp_init_private_key(CX_CURVE_BLS12_381_G1, tmp, 48, &privateKey);
cx_ecfp_generate_pair(CX_CURVE_BLS12_381_G1, &publicKey, &privateKey, 1); cx_ecfp_generate_pair(CX_CURVE_BLS12_381_G1, &publicKey, &privateKey, 1);
explicit_bzero(tmp, 96); explicit_bzero(tmp, 96);
explicit_bzero((void*)&privateKey, sizeof(cx_ecfp_256_extended_private_key_t)); explicit_bzero((void *) &privateKey, sizeof(cx_ecfp_256_extended_private_key_t));
tmp[47] = 2; tmp[47] = 2;
cx_math_mult(tmp, publicKey.W + 1 + 48, tmp, 48); cx_math_mult(tmp, publicKey.W + 1 + 48, tmp, 48);
if (cx_math_cmp(tmp + 48, BLS12_381_FIELD_MODULUS, 48) > 0) { if (cx_math_cmp(tmp + 48, BLS12_381_FIELD_MODULUS, 48) > 0) {
yFlag = 0x20; yFlag = 0x20;
} }
publicKey.W[1] &= 0x1f; publicKey.W[1] &= 0x1f;
publicKey.W[1] |= 0x80 | yFlag; publicKey.W[1] |= 0x80 | yFlag;
memmove(out, publicKey.W + 1, 48); memmove(out, publicKey.W + 1, 48);
} }
void handleGetEth2PublicKey(uint8_t p1, uint8_t p2, uint8_t *dataBuffer, uint16_t dataLength, unsigned int *flags, unsigned int *tx) { void handleGetEth2PublicKey(uint8_t p1,
UNUSED(dataLength); uint8_t p2,
uint32_t bip32Path[MAX_BIP32_PATH]; uint8_t *dataBuffer,
uint32_t i; uint16_t dataLength,
uint8_t bip32PathLength = *(dataBuffer++); unsigned int *flags,
unsigned int *tx) {
UNUSED(dataLength);
uint32_t bip32Path[MAX_BIP32_PATH];
uint32_t i;
uint8_t bip32PathLength = *(dataBuffer++);
if(!called_from_swap){ if (!called_from_swap) {
reset_app_context(); reset_app_context();
} }
if ((bip32PathLength < 0x01) || if ((bip32PathLength < 0x01) || (bip32PathLength > MAX_BIP32_PATH)) {
(bip32PathLength > MAX_BIP32_PATH)) { PRINTF("Invalid path\n");
PRINTF("Invalid path\n"); THROW(0x6a80);
THROW(0x6a80); }
} if ((p1 != P1_CONFIRM) && (p1 != P1_NON_CONFIRM)) {
if ((p1 != P1_CONFIRM) && (p1 != P1_NON_CONFIRM)) { THROW(0x6B00);
THROW(0x6B00); }
} if (p2 != 0) {
if (p2 != 0) { THROW(0x6B00);
THROW(0x6B00); }
} for (i = 0; i < bip32PathLength; i++) {
for (i = 0; i < bip32PathLength; i++) { bip32Path[i] = U4BE(dataBuffer, 0);
bip32Path[i] = U4BE(dataBuffer, 0); dataBuffer += 4;
dataBuffer += 4; }
} getEth2PublicKey(bip32Path, bip32PathLength, tmpCtx.publicKeyContext.publicKey.W);
getEth2PublicKey(bip32Path, bip32PathLength, tmpCtx.publicKeyContext.publicKey.W);
#ifndef NO_CONSENT #ifndef NO_CONSENT
if (p1 == P1_NON_CONFIRM) if (p1 == P1_NON_CONFIRM)
#endif // NO_CONSENT #endif // NO_CONSENT
{ {
*tx = set_result_get_eth2_publicKey(); *tx = set_result_get_eth2_publicKey();
THROW(0x9000); THROW(0x9000);
} }
#ifndef NO_CONSENT #ifndef NO_CONSENT
else else {
{ ux_flow_init(0, ux_display_public_eth2_flow, NULL);
ux_flow_init(0, ux_display_public_eth2_flow, NULL);
*flags |= IO_ASYNCH_REPLY; *flags |= IO_ASYNCH_REPLY;
} }
#endif // NO_CONSENT #endif // NO_CONSENT
} }
#endif #endif

View File

@@ -1,4 +1,3 @@
#include "shared_context.h" #include "shared_context.h"
uint32_t set_result_get_eth2_publicKey(void); uint32_t set_result_get_eth2_publicKey(void);

View File

@@ -10,4 +10,3 @@ uint32_t set_result_get_eth2_publicKey() {
} }
#endif #endif

View File

@@ -13,7 +13,7 @@ unsigned int io_seproxyhal_touch_eth2_address_ok(const bagl_element_t *e) {
io_exchange(CHANNEL_APDU | IO_RETURN_AFTER_TX, tx); io_exchange(CHANNEL_APDU | IO_RETURN_AFTER_TX, tx);
// Display back the original UX // Display back the original UX
ui_idle(); ui_idle();
return 0; // do not redraw the widget return 0; // do not redraw the widget
} }
#if 0 #if 0

View File

@@ -4,9 +4,10 @@
#include "ui_callbacks.h" #include "ui_callbacks.h"
void prepare_eth2_public_key() { void prepare_eth2_public_key() {
snprintf(strings.tmp.tmp, 100, "0x%.*H", 48, tmpCtx.publicKeyContext.publicKey.W); snprintf(strings.tmp.tmp, 100, "0x%.*H", 48, tmpCtx.publicKeyContext.publicKey.W);
} }
// clang-format off
UX_STEP_NOCB( UX_STEP_NOCB(
ux_display_public_eth2_flow_1_step, ux_display_public_eth2_flow_1_step,
pnn, pnn,
@@ -39,12 +40,12 @@ UX_STEP_CB(
&C_icon_crossmark, &C_icon_crossmark,
"Reject", "Reject",
}); });
// clang-format on
UX_FLOW(ux_display_public_eth2_flow, UX_FLOW(ux_display_public_eth2_flow,
&ux_display_public_eth2_flow_1_step, &ux_display_public_eth2_flow_1_step,
&ux_display_public_eth2_flow_2_step, &ux_display_public_eth2_flow_2_step,
&ux_display_public_eth2_flow_3_step, &ux_display_public_eth2_flow_3_step,
&ux_display_public_eth2_flow_4_step &ux_display_public_eth2_flow_4_step);
);
#endif #endif

View File

@@ -4,56 +4,70 @@
#include "ui_flow.h" #include "ui_flow.h"
#include "feature_getPublicKey.h" #include "feature_getPublicKey.h"
void handleGetPublicKey(uint8_t p1, uint8_t p2, uint8_t *dataBuffer, uint16_t dataLength, unsigned int *flags, unsigned int *tx) { void handleGetPublicKey(uint8_t p1,
UNUSED(dataLength); uint8_t p2,
uint8_t privateKeyData[32]; uint8_t *dataBuffer,
uint32_t bip32Path[MAX_BIP32_PATH]; uint16_t dataLength,
uint32_t i; unsigned int *flags,
uint8_t bip32PathLength = *(dataBuffer++); unsigned int *tx) {
cx_ecfp_private_key_t privateKey; UNUSED(dataLength);
if(!called_from_swap){ uint8_t privateKeyData[32];
reset_app_context(); uint32_t bip32Path[MAX_BIP32_PATH];
} uint32_t i;
if ((bip32PathLength < 0x01) || uint8_t bip32PathLength = *(dataBuffer++);
(bip32PathLength > MAX_BIP32_PATH)) { cx_ecfp_private_key_t privateKey;
PRINTF("Invalid path\n"); if (!called_from_swap) {
THROW(0x6a80); reset_app_context();
} }
if ((p1 != P1_CONFIRM) && (p1 != P1_NON_CONFIRM)) { if ((bip32PathLength < 0x01) || (bip32PathLength > MAX_BIP32_PATH)) {
THROW(0x6B00); PRINTF("Invalid path\n");
} THROW(0x6a80);
if ((p2 != P2_CHAINCODE) && (p2 != P2_NO_CHAINCODE)) { }
THROW(0x6B00); if ((p1 != P1_CONFIRM) && (p1 != P1_NON_CONFIRM)) {
} THROW(0x6B00);
for (i = 0; i < bip32PathLength; i++) { }
bip32Path[i] = U4BE(dataBuffer, 0); if ((p2 != P2_CHAINCODE) && (p2 != P2_NO_CHAINCODE)) {
dataBuffer += 4; THROW(0x6B00);
} }
tmpCtx.publicKeyContext.getChaincode = (p2 == P2_CHAINCODE); for (i = 0; i < bip32PathLength; i++) {
io_seproxyhal_io_heartbeat(); bip32Path[i] = U4BE(dataBuffer, 0);
os_perso_derive_node_bip32(CX_CURVE_256K1, bip32Path, bip32PathLength, privateKeyData, (tmpCtx.publicKeyContext.getChaincode ? tmpCtx.publicKeyContext.chainCode : NULL)); dataBuffer += 4;
cx_ecfp_init_private_key(CX_CURVE_256K1, privateKeyData, 32, &privateKey); }
io_seproxyhal_io_heartbeat(); tmpCtx.publicKeyContext.getChaincode = (p2 == P2_CHAINCODE);
cx_ecfp_generate_pair(CX_CURVE_256K1, &tmpCtx.publicKeyContext.publicKey, &privateKey, 1); io_seproxyhal_io_heartbeat();
explicit_bzero(&privateKey, sizeof(privateKey)); os_perso_derive_node_bip32(
explicit_bzero(privateKeyData, sizeof(privateKeyData)); CX_CURVE_256K1,
io_seproxyhal_io_heartbeat(); bip32Path,
getEthAddressStringFromKey(&tmpCtx.publicKeyContext.publicKey, tmpCtx.publicKeyContext.address, &global_sha3, chainConfig); bip32PathLength,
privateKeyData,
(tmpCtx.publicKeyContext.getChaincode ? tmpCtx.publicKeyContext.chainCode : NULL));
cx_ecfp_init_private_key(CX_CURVE_256K1, privateKeyData, 32, &privateKey);
io_seproxyhal_io_heartbeat();
cx_ecfp_generate_pair(CX_CURVE_256K1, &tmpCtx.publicKeyContext.publicKey, &privateKey, 1);
explicit_bzero(&privateKey, sizeof(privateKey));
explicit_bzero(privateKeyData, sizeof(privateKeyData));
io_seproxyhal_io_heartbeat();
getEthAddressStringFromKey(&tmpCtx.publicKeyContext.publicKey,
tmpCtx.publicKeyContext.address,
&global_sha3,
chainConfig);
#ifndef NO_CONSENT #ifndef NO_CONSENT
if (p1 == P1_NON_CONFIRM) if (p1 == P1_NON_CONFIRM)
#endif // NO_CONSENT #endif // NO_CONSENT
{ {
*tx = set_result_get_publicKey(); *tx = set_result_get_publicKey();
THROW(0x9000); THROW(0x9000);
} }
#ifndef NO_CONSENT #ifndef NO_CONSENT
else else {
{ snprintf(strings.common.fullAddress,
snprintf(strings.common.fullAddress, sizeof(strings.common.fullAddress), "0x%.*s", 40, tmpCtx.publicKeyContext.address); sizeof(strings.common.fullAddress),
ux_flow_init(0, ux_display_public_flow, NULL); "0x%.*s",
40,
tmpCtx.publicKeyContext.address);
ux_flow_init(0, ux_display_public_flow, NULL);
*flags |= IO_ASYNCH_REPLY; *flags |= IO_ASYNCH_REPLY;
} }
#endif // NO_CONSENT #endif // NO_CONSENT
} }

View File

@@ -1,4 +1,3 @@
#include "shared_context.h" #include "shared_context.h"
uint32_t set_result_get_publicKey(void); uint32_t set_result_get_publicKey(void);

View File

@@ -9,9 +9,8 @@ uint32_t set_result_get_publicKey() {
memmove(G_io_apdu_buffer + tx, tmpCtx.publicKeyContext.address, 40); memmove(G_io_apdu_buffer + tx, tmpCtx.publicKeyContext.address, 40);
tx += 40; tx += 40;
if (tmpCtx.publicKeyContext.getChaincode) { if (tmpCtx.publicKeyContext.getChaincode) {
memmove(G_io_apdu_buffer + tx, tmpCtx.publicKeyContext.chainCode, 32); memmove(G_io_apdu_buffer + tx, tmpCtx.publicKeyContext.chainCode, 32);
tx += 32; tx += 32;
} }
return tx; return tx;
} }

View File

@@ -11,7 +11,7 @@ unsigned int io_seproxyhal_touch_address_ok(const bagl_element_t *e) {
io_exchange(CHANNEL_APDU | IO_RETURN_AFTER_TX, tx); io_exchange(CHANNEL_APDU | IO_RETURN_AFTER_TX, tx);
// Display back the original UX // Display back the original UX
ui_idle(); ui_idle();
return 0; // do not redraw the widget return 0; // do not redraw the widget
} }
unsigned int io_seproxyhal_touch_address_cancel(const bagl_element_t *e) { unsigned int io_seproxyhal_touch_address_cancel(const bagl_element_t *e) {
@@ -22,6 +22,5 @@ unsigned int io_seproxyhal_touch_address_cancel(const bagl_element_t *e) {
io_exchange(CHANNEL_APDU | IO_RETURN_AFTER_TX, 2); io_exchange(CHANNEL_APDU | IO_RETURN_AFTER_TX, 2);
// Display back the original UX // Display back the original UX
ui_idle(); ui_idle();
return 0; // do not redraw the widget return 0; // do not redraw the widget
} }

View File

@@ -1,6 +1,7 @@
#include "shared_context.h" #include "shared_context.h"
#include "ui_callbacks.h" #include "ui_callbacks.h"
// clang-format off
UX_STEP_NOCB( UX_STEP_NOCB(
ux_display_public_flow_1_step, ux_display_public_flow_1_step,
pnn, pnn,
@@ -32,10 +33,10 @@ UX_STEP_CB(
&C_icon_crossmark, &C_icon_crossmark,
"Reject", "Reject",
}); });
// clang-format on
UX_FLOW(ux_display_public_flow, UX_FLOW(ux_display_public_flow,
&ux_display_public_flow_1_step, &ux_display_public_flow_1_step,
&ux_display_public_flow_2_step, &ux_display_public_flow_2_step,
&ux_display_public_flow_3_step, &ux_display_public_flow_3_step,
&ux_display_public_flow_4_step &ux_display_public_flow_4_step);
);

View File

@@ -3,172 +3,212 @@
#include "ui_flow.h" #include "ui_flow.h"
static const uint8_t const TOKEN_SIGNATURE_PUBLIC_KEY[] = { static const uint8_t const TOKEN_SIGNATURE_PUBLIC_KEY[] = {
// production key 2019-01-11 03:07PM (erc20signer) // production key 2019-01-11 03:07PM (erc20signer)
0x04, 0x04,
0x5e,0x6c,0x10,0x20,0xc1,0x4d,0xc4,0x64, 0x5e, 0x6c, 0x10, 0x20, 0xc1, 0x4d, 0xc4, 0x64, 0x42, 0xfe, 0x89, 0xf9, 0x7c, 0x0b, 0x68, 0xcd,
0x42,0xfe,0x89,0xf9,0x7c,0x0b,0x68,0xcd, 0xb1, 0x59, 0x76, 0xdc, 0x24, 0xf2, 0x4c, 0x31, 0x6e, 0x7b, 0x30, 0xfe, 0x4e, 0x8c, 0xc7, 0x6b,
0xb1,0x59,0x76,0xdc,0x24,0xf2,0x4c,0x31,
0x6e,0x7b,0x30,0xfe,0x4e,0x8c,0xc7,0x6b,
0x14,0x89,0x15,0x0c,0x21,0x51,0x4e,0xbf, 0x14, 0x89, 0x15, 0x0c, 0x21, 0x51, 0x4e, 0xbf, 0x44, 0x0f, 0xf5, 0xde, 0xa5, 0x39, 0x3d, 0x83,
0x44,0x0f,0xf5,0xde,0xa5,0x39,0x3d,0x83, 0xde, 0x53, 0x58, 0xcd, 0x09, 0x8f, 0xce, 0x8f, 0xd0, 0xf8, 0x1d, 0xaa, 0x94, 0x97, 0x91, 0x83};
0xde,0x53,0x58,0xcd,0x09,0x8f,0xce,0x8f,
0xd0,0xf8,0x1d,0xaa,0x94,0x97,0x91,0x83
};
#ifdef HAVE_CONTRACT_NAME_IN_DESCRIPTOR #ifdef HAVE_CONTRACT_NAME_IN_DESCRIPTOR
void handleProvideErc20TokenInformation(uint8_t p1, uint8_t p2, uint8_t *workBuffer, uint16_t dataLength, unsigned int *flags, unsigned int *tx) { void handleProvideErc20TokenInformation(uint8_t p1,
UNUSED(p1); uint8_t p2,
UNUSED(p2); uint8_t *workBuffer,
UNUSED(flags); uint16_t dataLength,
uint32_t offset = 0; unsigned int *flags,
uint8_t tickerLength, contractNameLength; unsigned int *tx) {
uint32_t chainId; UNUSED(p1);
uint8_t hash[32]; UNUSED(p2);
cx_sha256_t sha256; UNUSED(flags);
cx_ecfp_public_key_t tokenKey; uint32_t offset = 0;
uint8_t tickerLength, contractNameLength;
uint32_t chainId;
uint8_t hash[32];
cx_sha256_t sha256;
cx_ecfp_public_key_t tokenKey;
cx_sha256_init(&sha256); cx_sha256_init(&sha256);
tmpCtx.transactionContext.currentTokenIndex = (tmpCtx.transactionContext.currentTokenIndex + 1) % MAX_TOKEN; tmpCtx.transactionContext.currentTokenIndex =
tokenDefinition_t* token = &tmpCtx.transactionContext.tokens[tmpCtx.transactionContext.currentTokenIndex]; (tmpCtx.transactionContext.currentTokenIndex + 1) % MAX_TOKEN;
tokenDefinition_t *token =
&tmpCtx.transactionContext.tokens[tmpCtx.transactionContext.currentTokenIndex];
if (dataLength < 1) { if (dataLength < 1) {
THROW(0x6A80); THROW(0x6A80);
} }
tickerLength = workBuffer[offset++]; tickerLength = workBuffer[offset++];
dataLength--; dataLength--;
if ((tickerLength + 2) >= sizeof(token->ticker)) { // +2 because ' \0' is appended to ticker if ((tickerLength + 2) >= sizeof(token->ticker)) { // +2 because ' \0' is appended to ticker
THROW(0x6A80); THROW(0x6A80);
} }
if (dataLength < tickerLength + 1) { if (dataLength < tickerLength + 1) {
THROW(0x6A80); THROW(0x6A80);
} }
cx_hash((cx_hash_t*)&sha256, 0, workBuffer + offset, tickerLength, NULL, 0); cx_hash((cx_hash_t *) &sha256, 0, workBuffer + offset, tickerLength, NULL, 0);
memmove(token->ticker, workBuffer + offset, tickerLength); memmove(token->ticker, workBuffer + offset, tickerLength);
token->ticker[tickerLength] = ' '; token->ticker[tickerLength] = ' ';
token->ticker[tickerLength + 1] = '\0'; token->ticker[tickerLength + 1] = '\0';
offset += tickerLength; offset += tickerLength;
dataLength -= tickerLength; dataLength -= tickerLength;
contractNameLength = workBuffer[offset++]; contractNameLength = workBuffer[offset++];
dataLength--; dataLength--;
if (dataLength < contractNameLength + 20 + 4 + 4) { if (dataLength < contractNameLength + 20 + 4 + 4) {
THROW(0x6A80); THROW(0x6A80);
} }
cx_hash((cx_hash_t*)&sha256, CX_LAST, workBuffer + offset, contractNameLength + 20 + 4 + 4, hash, 32); cx_hash((cx_hash_t *) &sha256,
memmove(token->contractName, workBuffer + offset, MIN(contractNameLength, sizeof(token->contractName)-1)); CX_LAST,
token->contractName[MIN(contractNameLength, sizeof(token->contractName)-1)] = '\0'; workBuffer + offset,
offset += contractNameLength; contractNameLength + 20 + 4 + 4,
dataLength -= contractNameLength; hash,
32);
memmove(token->contractName,
workBuffer + offset,
MIN(contractNameLength, sizeof(token->contractName) - 1));
token->contractName[MIN(contractNameLength, sizeof(token->contractName) - 1)] = '\0';
offset += contractNameLength;
dataLength -= contractNameLength;
memmove(token->address, workBuffer + offset, 20); memmove(token->address, workBuffer + offset, 20);
offset += 20; offset += 20;
dataLength -= 20; dataLength -= 20;
token->decimals = U4BE(workBuffer, offset); token->decimals = U4BE(workBuffer, offset);
offset += 4; offset += 4;
dataLength -= 4; dataLength -= 4;
chainId = U4BE(workBuffer, offset); chainId = U4BE(workBuffer, offset);
if ((chainConfig->chainId != 0) && (chainConfig->chainId != chainId)) { if ((chainConfig->chainId != 0) && (chainConfig->chainId != chainId)) {
PRINTF("ChainId token mismatch\n"); PRINTF("ChainId token mismatch\n");
THROW(0x6A80); THROW(0x6A80);
} }
offset += 4; offset += 4;
dataLength -= 4; dataLength -= 4;
cx_ecfp_init_public_key(CX_CURVE_256K1, TOKEN_SIGNATURE_PUBLIC_KEY, sizeof(TOKEN_SIGNATURE_PUBLIC_KEY), &tokenKey); cx_ecfp_init_public_key(CX_CURVE_256K1,
if (!cx_ecdsa_verify(&tokenKey, CX_LAST, CX_SHA256, hash, 32, workBuffer + offset, dataLength)) { TOKEN_SIGNATURE_PUBLIC_KEY,
PRINTF("Invalid token signature\n"); sizeof(TOKEN_SIGNATURE_PUBLIC_KEY),
THROW(0x6A80); &tokenKey);
} if (!cx_ecdsa_verify(&tokenKey,
tmpCtx.transactionContext.tokenSet[tmpCtx.transactionContext.currentTokenIndex] = 1; CX_LAST,
THROW(0x9000); CX_SHA256,
hash,
32,
workBuffer + offset,
dataLength)) {
PRINTF("Invalid token signature\n");
THROW(0x6A80);
}
tmpCtx.transactionContext.tokenSet[tmpCtx.transactionContext.currentTokenIndex] = 1;
THROW(0x9000);
} }
#else #else
void handleProvideErc20TokenInformation(uint8_t p1, uint8_t p2, uint8_t *workBuffer, uint16_t dataLength, unsigned int *flags, unsigned int *tx) { void handleProvideErc20TokenInformation(uint8_t p1,
UNUSED(p1); uint8_t p2,
UNUSED(p2); uint8_t *workBuffer,
UNUSED(flags); uint16_t dataLength,
uint32_t offset = 0; unsigned int *flags,
uint8_t tickerLength; unsigned int *tx) {
uint32_t chainId; UNUSED(p1);
uint8_t hash[32]; UNUSED(p2);
cx_ecfp_public_key_t tokenKey; UNUSED(flags);
uint32_t offset = 0;
uint8_t tickerLength;
uint32_t chainId;
uint8_t hash[32];
cx_ecfp_public_key_t tokenKey;
tmpCtx.transactionContext.currentTokenIndex =
(tmpCtx.transactionContext.currentTokenIndex + 1) % MAX_TOKEN;
tokenDefinition_t *token =
&tmpCtx.transactionContext.tokens[tmpCtx.transactionContext.currentTokenIndex];
tmpCtx.transactionContext.currentTokenIndex = (tmpCtx.transactionContext.currentTokenIndex + 1) % MAX_TOKEN; PRINTF("Provisioning currentTokenIndex %d\n", tmpCtx.transactionContext.currentTokenIndex);
tokenDefinition_t* token = &tmpCtx.transactionContext.tokens[tmpCtx.transactionContext.currentTokenIndex];
PRINTF("Provisioning currentTokenIndex %d\n", tmpCtx.transactionContext.currentTokenIndex); if (dataLength < 1) {
THROW(0x6A80);
if (dataLength < 1) { }
THROW(0x6A80); tickerLength = workBuffer[offset++];
} dataLength--;
tickerLength = workBuffer[offset++]; if ((tickerLength + 1) >= sizeof(token->ticker)) {
dataLength--; THROW(0x6A80);
if ((tickerLength + 1) >= sizeof(token->ticker)) { }
THROW(0x6A80); if (dataLength < tickerLength + 20 + 4 + 4) {
} THROW(0x6A80);
if (dataLength < tickerLength + 20 + 4 + 4) { }
THROW(0x6A80); cx_hash_sha256(workBuffer + offset, tickerLength + 20 + 4 + 4, hash, 32);
} memmove(token->ticker, workBuffer + offset, tickerLength);
cx_hash_sha256(workBuffer + offset, tickerLength + 20 + 4 + 4, hash, 32); token->ticker[tickerLength] = ' ';
memmove(token->ticker, workBuffer + offset, tickerLength); token->ticker[tickerLength + 1] = '\0';
token->ticker[tickerLength] = ' '; offset += tickerLength;
token->ticker[tickerLength + 1] = '\0'; dataLength -= tickerLength;
offset += tickerLength; memmove(token->address, workBuffer + offset, 20);
dataLength -= tickerLength; offset += 20;
memmove(token->address, workBuffer + offset, 20); dataLength -= 20;
offset += 20; token->decimals = U4BE(workBuffer, offset);
dataLength -= 20; offset += 4;
token->decimals = U4BE(workBuffer, offset); dataLength -= 4;
offset += 4; chainId = U4BE(workBuffer, offset);
dataLength -= 4; if ((chainConfig->chainId != 0) && (chainConfig->chainId != chainId)) {
chainId = U4BE(workBuffer, offset); PRINTF("ChainId token mismatch\n");
if ((chainConfig->chainId != 0) && (chainConfig->chainId != chainId)) { THROW(0x6A80);
PRINTF("ChainId token mismatch\n"); }
THROW(0x6A80); offset += 4;
} dataLength -= 4;
offset += 4;
dataLength -= 4;
#ifdef HAVE_TOKENS_EXTRA_LIST #ifdef HAVE_TOKENS_EXTRA_LIST
tokenDefinition_t *currentToken = NULL; tokenDefinition_t *currentToken = NULL;
uint32_t index; uint32_t index;
for (index=0; index < NUM_TOKENS_EXTRA; index++) { for (index = 0; index < NUM_TOKENS_EXTRA; index++) {
currentToken = (tokenDefinition_t *)PIC(&TOKENS_EXTRA[index]); currentToken = (tokenDefinition_t *) PIC(&TOKENS_EXTRA[index]);
if (memcmp(currentToken->address, token->address, 20) == 0) { if (memcmp(currentToken->address, token->address, 20) == 0) {
strcpy((char*)token->ticker, (char*)currentToken->ticker); strcpy((char *) token->ticker, (char *) currentToken->ticker);
token->decimals = currentToken->decimals; token->decimals = currentToken->decimals;
break; break;
} }
} }
if (index < NUM_TOKENS_EXTRA) { if (index < NUM_TOKENS_EXTRA) {
PRINTF("Descriptor whitelisted\n"); PRINTF("Descriptor whitelisted\n");
} } else {
else { cx_ecfp_init_public_key(CX_CURVE_256K1,
cx_ecfp_init_public_key(CX_CURVE_256K1, TOKEN_SIGNATURE_PUBLIC_KEY, sizeof(TOKEN_SIGNATURE_PUBLIC_KEY), &tokenKey); TOKEN_SIGNATURE_PUBLIC_KEY,
if (!cx_ecdsa_verify(&tokenKey, CX_LAST, CX_SHA256, hash, 32, workBuffer + offset, dataLength)) { sizeof(TOKEN_SIGNATURE_PUBLIC_KEY),
PRINTF("Invalid token signature\n"); &tokenKey);
THROW(0x6A80); if (!cx_ecdsa_verify(&tokenKey,
} CX_LAST,
CX_SHA256,
hash,
32,
workBuffer + offset,
dataLength)) {
PRINTF("Invalid token signature\n");
THROW(0x6A80);
}
} }
#else #else
cx_ecfp_init_public_key(CX_CURVE_256K1, TOKEN_SIGNATURE_PUBLIC_KEY, sizeof(TOKEN_SIGNATURE_PUBLIC_KEY), &tokenKey); cx_ecfp_init_public_key(CX_CURVE_256K1,
if (!cx_ecdsa_verify(&tokenKey, CX_LAST, CX_SHA256, hash, 32, workBuffer + offset, dataLength)) { TOKEN_SIGNATURE_PUBLIC_KEY,
PRINTF("Invalid token signature\n"); sizeof(TOKEN_SIGNATURE_PUBLIC_KEY),
THROW(0x6A80); &tokenKey);
} if (!cx_ecdsa_verify(&tokenKey,
CX_LAST,
CX_SHA256,
hash,
32,
workBuffer + offset,
dataLength)) {
PRINTF("Invalid token signature\n");
THROW(0x6A80);
}
#endif #endif
tmpCtx.transactionContext.tokenSet[tmpCtx.transactionContext.currentTokenIndex] = 1; tmpCtx.transactionContext.tokenSet[tmpCtx.transactionContext.currentTokenIndex] = 1;
THROW(0x9000); THROW(0x9000);
} }
#endif #endif

View File

@@ -3,19 +3,23 @@
#include "shared_context.h" #include "shared_context.h"
#include "apdu_constants.h" #include "apdu_constants.h"
void handleSetEth2WithdrawalIndex(uint8_t p1,
uint8_t p2,
uint8_t *dataBuffer,
uint16_t dataLength,
unsigned int *flags,
unsigned int *tx) {
if (dataLength != 4) {
THROW(0x6700);
}
void handleSetEth2WithdrawalIndex(uint8_t p1, uint8_t p2, uint8_t *dataBuffer, uint16_t dataLength, unsigned int *flags, unsigned int *tx) { if ((p1 != 0) || (p2 != 0)) {
if (dataLength != 4) { THROW(0x6B00);
THROW(0x6700); }
}
if ((p1 != 0) || (p2 != 0)) { eth2WithdrawalIndex = U4BE(dataBuffer, 0);
THROW(0x6B00);
}
eth2WithdrawalIndex = U4BE(dataBuffer, 0); THROW(0x9000);
THROW(0x9000);
} }
#endif #endif

View File

@@ -3,94 +3,113 @@
#include "utils.h" #include "utils.h"
#include "ui_flow.h" #include "ui_flow.h"
static const char const SIGN_MAGIC[] = "\x19" static const char const SIGN_MAGIC[] =
"Ethereum Signed Message:\n"; "\x19"
"Ethereum Signed Message:\n";
void handleSignPersonalMessage(uint8_t p1, uint8_t p2, uint8_t *workBuffer, uint16_t dataLength, unsigned int *flags, unsigned int *tx) { void handleSignPersonalMessage(uint8_t p1,
UNUSED(tx); uint8_t p2,
uint8_t hashMessage[32]; uint8_t *workBuffer,
if (p1 == P1_FIRST) { uint16_t dataLength,
char tmp[11]; unsigned int *flags,
uint32_t index; unsigned int *tx) {
uint32_t base = 10; UNUSED(tx);
uint8_t pos = 0; uint8_t hashMessage[32];
uint32_t i; if (p1 == P1_FIRST) {
if (dataLength < 1) { char tmp[11];
PRINTF("Invalid data\n"); uint32_t index;
THROW(0x6a80); uint32_t base = 10;
} uint8_t pos = 0;
if (appState != APP_STATE_IDLE) { uint32_t i;
reset_app_context(); if (dataLength < 1) {
} PRINTF("Invalid data\n");
appState = APP_STATE_SIGNING_MESSAGE; THROW(0x6a80);
tmpCtx.messageSigningContext.pathLength = workBuffer[0];
if ((tmpCtx.messageSigningContext.pathLength < 0x01) ||
(tmpCtx.messageSigningContext.pathLength > MAX_BIP32_PATH)) {
PRINTF("Invalid path\n");
THROW(0x6a80);
}
workBuffer++;
dataLength--;
for (i = 0; i < tmpCtx.messageSigningContext.pathLength; i++) {
if (dataLength < 4) {
PRINTF("Invalid data\n");
THROW(0x6a80);
} }
tmpCtx.messageSigningContext.bip32Path[i] = U4BE(workBuffer, 0); if (appState != APP_STATE_IDLE) {
reset_app_context();
}
appState = APP_STATE_SIGNING_MESSAGE;
tmpCtx.messageSigningContext.pathLength = workBuffer[0];
if ((tmpCtx.messageSigningContext.pathLength < 0x01) ||
(tmpCtx.messageSigningContext.pathLength > MAX_BIP32_PATH)) {
PRINTF("Invalid path\n");
THROW(0x6a80);
}
workBuffer++;
dataLength--;
for (i = 0; i < tmpCtx.messageSigningContext.pathLength; i++) {
if (dataLength < 4) {
PRINTF("Invalid data\n");
THROW(0x6a80);
}
tmpCtx.messageSigningContext.bip32Path[i] = U4BE(workBuffer, 0);
workBuffer += 4;
dataLength -= 4;
}
if (dataLength < 4) {
PRINTF("Invalid data\n");
THROW(0x6a80);
}
tmpCtx.messageSigningContext.remainingLength = U4BE(workBuffer, 0);
workBuffer += 4; workBuffer += 4;
dataLength -= 4; dataLength -= 4;
} // Initialize message header + length
if (dataLength < 4) { cx_keccak_init(&global_sha3, 256);
PRINTF("Invalid data\n"); cx_hash((cx_hash_t *) &global_sha3,
THROW(0x6a80); 0,
} (uint8_t *) SIGN_MAGIC,
tmpCtx.messageSigningContext.remainingLength = U4BE(workBuffer, 0); sizeof(SIGN_MAGIC) - 1,
workBuffer += 4; NULL,
dataLength -= 4; 0);
// Initialize message header + length for (index = 1; (((index * base) <= tmpCtx.messageSigningContext.remainingLength) &&
cx_keccak_init(&global_sha3, 256);
cx_hash((cx_hash_t *)&global_sha3, 0, (uint8_t*)SIGN_MAGIC, sizeof(SIGN_MAGIC) - 1, NULL, 0);
for (index = 1; (((index * base) <= tmpCtx.messageSigningContext.remainingLength) &&
(((index * base) / base) == index)); (((index * base) / base) == index));
index *= base); index *= base)
for (; index; index /= base) { ;
tmp[pos++] = '0' + ((tmpCtx.messageSigningContext.remainingLength / index) % base); for (; index; index /= base) {
tmp[pos++] = '0' + ((tmpCtx.messageSigningContext.remainingLength / index) % base);
}
tmp[pos] = '\0';
cx_hash((cx_hash_t *) &global_sha3, 0, (uint8_t *) tmp, pos, NULL, 0);
cx_sha256_init(&tmpContent.sha2);
} else if (p1 != P1_MORE) {
THROW(0x6B00);
} }
tmp[pos] = '\0'; if (p2 != 0) {
cx_hash((cx_hash_t *)&global_sha3, 0, (uint8_t*)tmp, pos, NULL, 0); THROW(0x6B00);
cx_sha256_init(&tmpContent.sha2); }
} if ((p1 == P1_MORE) && (appState != APP_STATE_SIGNING_MESSAGE)) {
else if (p1 != P1_MORE) { PRINTF("Signature not initialized\n");
THROW(0x6B00); THROW(0x6985);
} }
if (p2 != 0) { if (dataLength > tmpCtx.messageSigningContext.remainingLength) {
THROW(0x6B00); THROW(0x6A80);
} }
if ((p1 == P1_MORE) && (appState != APP_STATE_SIGNING_MESSAGE)) { cx_hash((cx_hash_t *) &global_sha3, 0, workBuffer, dataLength, NULL, 0);
PRINTF("Signature not initialized\n"); cx_hash((cx_hash_t *) &tmpContent.sha2, 0, workBuffer, dataLength, NULL, 0);
THROW(0x6985); tmpCtx.messageSigningContext.remainingLength -= dataLength;
} if (tmpCtx.messageSigningContext.remainingLength == 0) {
if (dataLength > tmpCtx.messageSigningContext.remainingLength) { cx_hash((cx_hash_t *) &global_sha3,
THROW(0x6A80); CX_LAST,
} workBuffer,
cx_hash((cx_hash_t *)&global_sha3, 0, workBuffer, dataLength, NULL, 0); 0,
cx_hash((cx_hash_t *)&tmpContent.sha2, 0, workBuffer, dataLength, NULL, 0); tmpCtx.messageSigningContext.hash,
tmpCtx.messageSigningContext.remainingLength -= dataLength; 32);
if (tmpCtx.messageSigningContext.remainingLength == 0) { cx_hash((cx_hash_t *) &tmpContent.sha2, CX_LAST, workBuffer, 0, hashMessage, 32);
cx_hash((cx_hash_t *)&global_sha3, CX_LAST, workBuffer, 0, tmpCtx.messageSigningContext.hash, 32); snprintf(strings.tmp.tmp,
cx_hash((cx_hash_t *)&tmpContent.sha2, CX_LAST, workBuffer, 0, hashMessage, 32); sizeof(strings.tmp.tmp),
snprintf(strings.tmp.tmp, sizeof(strings.tmp.tmp), "%.*H", sizeof(hashMessage), hashMessage); "%.*H",
sizeof(hashMessage),
hashMessage);
#ifdef NO_CONSENT #ifdef NO_CONSENT
io_seproxyhal_touch_signMessage_ok(NULL); io_seproxyhal_touch_signMessage_ok(NULL);
#else //NO_CONSENT #else // NO_CONSENT
ux_flow_init(0, ux_sign_flow, NULL); ux_flow_init(0, ux_sign_flow, NULL);
#endif // NO_CONSENT #endif // NO_CONSENT
*flags |= IO_ASYNCH_REPLY; *flags |= IO_ASYNCH_REPLY;
} else { } else {
THROW(0x9000); THROW(0x9000);
} }
} }

View File

@@ -8,25 +8,31 @@ unsigned int io_seproxyhal_touch_signMessage_ok(const bagl_element_t *e) {
cx_ecfp_private_key_t privateKey; cx_ecfp_private_key_t privateKey;
uint32_t tx = 0; uint32_t tx = 0;
io_seproxyhal_io_heartbeat(); io_seproxyhal_io_heartbeat();
os_perso_derive_node_bip32( os_perso_derive_node_bip32(CX_CURVE_256K1,
CX_CURVE_256K1, tmpCtx.messageSigningContext.bip32Path, tmpCtx.messageSigningContext.bip32Path,
tmpCtx.messageSigningContext.pathLength, privateKeyData, NULL); tmpCtx.messageSigningContext.pathLength,
privateKeyData,
NULL);
io_seproxyhal_io_heartbeat(); io_seproxyhal_io_heartbeat();
cx_ecfp_init_private_key(CX_CURVE_256K1, privateKeyData, 32, &privateKey); cx_ecfp_init_private_key(CX_CURVE_256K1, privateKeyData, 32, &privateKey);
explicit_bzero(privateKeyData, sizeof(privateKeyData)); explicit_bzero(privateKeyData, sizeof(privateKeyData));
unsigned int info = 0; unsigned int info = 0;
io_seproxyhal_io_heartbeat(); io_seproxyhal_io_heartbeat();
signatureLength = signatureLength = cx_ecdsa_sign(&privateKey,
cx_ecdsa_sign(&privateKey, CX_RND_RFC6979 | CX_LAST, CX_SHA256, CX_RND_RFC6979 | CX_LAST,
tmpCtx.messageSigningContext.hash, CX_SHA256,
sizeof(tmpCtx.messageSigningContext.hash), signature, sizeof(signature), &info); tmpCtx.messageSigningContext.hash,
sizeof(tmpCtx.messageSigningContext.hash),
signature,
sizeof(signature),
&info);
explicit_bzero(&privateKey, sizeof(privateKey)); explicit_bzero(&privateKey, sizeof(privateKey));
G_io_apdu_buffer[0] = 27; G_io_apdu_buffer[0] = 27;
if (info & CX_ECCINFO_PARITY_ODD) { if (info & CX_ECCINFO_PARITY_ODD) {
G_io_apdu_buffer[0]++; G_io_apdu_buffer[0]++;
} }
if (info & CX_ECCINFO_xGTn) { if (info & CX_ECCINFO_xGTn) {
G_io_apdu_buffer[0] += 2; G_io_apdu_buffer[0] += 2;
} }
format_signature_out(signature); format_signature_out(signature);
tx = 65; tx = 65;
@@ -37,7 +43,7 @@ unsigned int io_seproxyhal_touch_signMessage_ok(const bagl_element_t *e) {
io_exchange(CHANNEL_APDU | IO_RETURN_AFTER_TX, tx); io_exchange(CHANNEL_APDU | IO_RETURN_AFTER_TX, tx);
// Display back the original UX // Display back the original UX
ui_idle(); ui_idle();
return 0; // do not redraw the widget return 0; // do not redraw the widget
} }
unsigned int io_seproxyhal_touch_signMessage_cancel(const bagl_element_t *e) { unsigned int io_seproxyhal_touch_signMessage_cancel(const bagl_element_t *e) {
@@ -48,6 +54,5 @@ unsigned int io_seproxyhal_touch_signMessage_cancel(const bagl_element_t *e) {
io_exchange(CHANNEL_APDU | IO_RETURN_AFTER_TX, 2); io_exchange(CHANNEL_APDU | IO_RETURN_AFTER_TX, 2);
// Display back the original UX // Display back the original UX
ui_idle(); ui_idle();
return 0; // do not redraw the widget return 0; // do not redraw the widget
} }

View File

@@ -1,6 +1,7 @@
#include "shared_context.h" #include "shared_context.h"
#include "ui_callbacks.h" #include "ui_callbacks.h"
// clang-format off
UX_STEP_NOCB( UX_STEP_NOCB(
ux_sign_flow_1_step, ux_sign_flow_1_step,
pnn, pnn,
@@ -34,11 +35,10 @@ UX_STEP_CB(
"Cancel", "Cancel",
"signature", "signature",
}); });
// clang-format on
UX_FLOW(ux_sign_flow, UX_FLOW(ux_sign_flow,
&ux_sign_flow_1_step, &ux_sign_flow_1_step,
&ux_sign_flow_2_step, &ux_sign_flow_2_step,
&ux_sign_flow_3_step, &ux_sign_flow_3_step,
&ux_sign_flow_4_step &ux_sign_flow_4_step);
);

View File

@@ -3,52 +3,58 @@
#include "utils.h" #include "utils.h"
#include "ui_flow.h" #include "ui_flow.h"
static const char const SIGN_MAGIC[] = "\x19" static const char const SIGN_MAGIC[] =
"Ethereum Signed Message:\n"; "\x19"
"Ethereum Signed Message:\n";
void handleSignEIP712Message(uint8_t p1, uint8_t p2, uint8_t *workBuffer, uint16_t dataLength, unsigned int *flags, unsigned int *tx) { void handleSignEIP712Message(uint8_t p1,
uint8_t i; uint8_t p2,
uint8_t *workBuffer,
uint16_t dataLength,
unsigned int *flags,
unsigned int *tx) {
uint8_t i;
UNUSED(tx); UNUSED(tx);
if ((p1 != 00) || (p2 != 00)) { if ((p1 != 00) || (p2 != 00)) {
THROW(0x6B00); THROW(0x6B00);
}
if (appState != APP_STATE_IDLE) {
reset_app_context();
}
if (dataLength < 1) {
PRINTF("Invalid data\n");
THROW(0x6a80);
}
tmpCtx.messageSigningContext712.pathLength = workBuffer[0];
if ((tmpCtx.messageSigningContext712.pathLength < 0x01) ||
(tmpCtx.messageSigningContext712.pathLength > MAX_BIP32_PATH)) {
PRINTF("Invalid path\n");
THROW(0x6a80);
}
workBuffer++;
dataLength--;
for (i = 0; i < tmpCtx.messageSigningContext712.pathLength; i++) {
if (dataLength < 4) {
PRINTF("Invalid data\n");
THROW(0x6a80);
} }
tmpCtx.messageSigningContext712.bip32Path[i] = U4BE(workBuffer, 0); if (appState != APP_STATE_IDLE) {
workBuffer += 4; reset_app_context();
dataLength -= 4; }
} if (dataLength < 1) {
if (dataLength < 32 + 32) { PRINTF("Invalid data\n");
PRINTF("Invalid data\n"); THROW(0x6a80);
THROW(0x6a80); }
} tmpCtx.messageSigningContext712.pathLength = workBuffer[0];
memmove(tmpCtx.messageSigningContext712.domainHash, workBuffer, 32); if ((tmpCtx.messageSigningContext712.pathLength < 0x01) ||
memmove(tmpCtx.messageSigningContext712.messageHash, workBuffer + 32, 32); (tmpCtx.messageSigningContext712.pathLength > MAX_BIP32_PATH)) {
PRINTF("Invalid path\n");
THROW(0x6a80);
}
workBuffer++;
dataLength--;
for (i = 0; i < tmpCtx.messageSigningContext712.pathLength; i++) {
if (dataLength < 4) {
PRINTF("Invalid data\n");
THROW(0x6a80);
}
tmpCtx.messageSigningContext712.bip32Path[i] = U4BE(workBuffer, 0);
workBuffer += 4;
dataLength -= 4;
}
if (dataLength < 32 + 32) {
PRINTF("Invalid data\n");
THROW(0x6a80);
}
memmove(tmpCtx.messageSigningContext712.domainHash, workBuffer, 32);
memmove(tmpCtx.messageSigningContext712.messageHash, workBuffer + 32, 32);
#ifdef NO_CONSENT #ifdef NO_CONSENT
io_seproxyhal_touch_signMessage_ok(NULL); io_seproxyhal_touch_signMessage_ok(NULL);
#else //NO_CONSENT #else // NO_CONSENT
ux_flow_init(0, ux_sign_712_v0_flow, NULL); ux_flow_init(0, ux_sign_712_v0_flow, NULL);
#endif // NO_CONSENT #endif // NO_CONSENT
*flags |= IO_ASYNCH_REPLY; *flags |= IO_ASYNCH_REPLY;
} }

View File

@@ -1,7 +1,7 @@
#include "shared_context.h" #include "shared_context.h"
#include "ui_callbacks.h" #include "ui_callbacks.h"
static const uint8_t const EIP_712_MAGIC[] = { 0x19, 0x01 }; static const uint8_t const EIP_712_MAGIC[] = {0x19, 0x01};
unsigned int io_seproxyhal_touch_signMessage712_v0_ok(const bagl_element_t *e) { unsigned int io_seproxyhal_touch_signMessage712_v0_ok(const bagl_element_t *e) {
uint8_t privateKeyData[32]; uint8_t privateKeyData[32];
@@ -12,32 +12,51 @@ unsigned int io_seproxyhal_touch_signMessage712_v0_ok(const bagl_element_t *e) {
uint32_t tx = 0; uint32_t tx = 0;
io_seproxyhal_io_heartbeat(); io_seproxyhal_io_heartbeat();
cx_keccak_init(&global_sha3, 256); cx_keccak_init(&global_sha3, 256);
cx_hash((cx_hash_t *)&global_sha3, 0, (uint8_t*)EIP_712_MAGIC, sizeof(EIP_712_MAGIC), NULL, 0); cx_hash((cx_hash_t *) &global_sha3,
cx_hash((cx_hash_t *)&global_sha3, 0, tmpCtx.messageSigningContext712.domainHash, 0,
sizeof(tmpCtx.messageSigningContext712.domainHash), NULL, 0); (uint8_t *) EIP_712_MAGIC,
cx_hash((cx_hash_t *)&global_sha3, CX_LAST, tmpCtx.messageSigningContext712.messageHash, sizeof(EIP_712_MAGIC),
sizeof(tmpCtx.messageSigningContext712.messageHash), hash, sizeof(hash)); NULL,
0);
cx_hash((cx_hash_t *) &global_sha3,
0,
tmpCtx.messageSigningContext712.domainHash,
sizeof(tmpCtx.messageSigningContext712.domainHash),
NULL,
0);
cx_hash((cx_hash_t *) &global_sha3,
CX_LAST,
tmpCtx.messageSigningContext712.messageHash,
sizeof(tmpCtx.messageSigningContext712.messageHash),
hash,
sizeof(hash));
PRINTF("EIP712 hash to sign %.*H\n", 32, hash); PRINTF("EIP712 hash to sign %.*H\n", 32, hash);
io_seproxyhal_io_heartbeat(); io_seproxyhal_io_heartbeat();
os_perso_derive_node_bip32( os_perso_derive_node_bip32(CX_CURVE_256K1,
CX_CURVE_256K1, tmpCtx.messageSigningContext712.bip32Path, tmpCtx.messageSigningContext712.bip32Path,
tmpCtx.messageSigningContext712.pathLength, privateKeyData, NULL); tmpCtx.messageSigningContext712.pathLength,
privateKeyData,
NULL);
io_seproxyhal_io_heartbeat(); io_seproxyhal_io_heartbeat();
cx_ecfp_init_private_key(CX_CURVE_256K1, privateKeyData, 32, &privateKey); cx_ecfp_init_private_key(CX_CURVE_256K1, privateKeyData, 32, &privateKey);
explicit_bzero(privateKeyData, sizeof(privateKeyData)); explicit_bzero(privateKeyData, sizeof(privateKeyData));
unsigned int info = 0; unsigned int info = 0;
io_seproxyhal_io_heartbeat(); io_seproxyhal_io_heartbeat();
signatureLength = signatureLength = cx_ecdsa_sign(&privateKey,
cx_ecdsa_sign(&privateKey, CX_RND_RFC6979 | CX_LAST, CX_SHA256, CX_RND_RFC6979 | CX_LAST,
hash, CX_SHA256,
sizeof(hash), signature, sizeof(signature), &info); hash,
sizeof(hash),
signature,
sizeof(signature),
&info);
explicit_bzero(&privateKey, sizeof(privateKey)); explicit_bzero(&privateKey, sizeof(privateKey));
G_io_apdu_buffer[0] = 27; G_io_apdu_buffer[0] = 27;
if (info & CX_ECCINFO_PARITY_ODD) { if (info & CX_ECCINFO_PARITY_ODD) {
G_io_apdu_buffer[0]++; G_io_apdu_buffer[0]++;
} }
if (info & CX_ECCINFO_xGTn) { if (info & CX_ECCINFO_xGTn) {
G_io_apdu_buffer[0] += 2; G_io_apdu_buffer[0] += 2;
} }
format_signature_out(signature); format_signature_out(signature);
tx = 65; tx = 65;
@@ -48,7 +67,7 @@ unsigned int io_seproxyhal_touch_signMessage712_v0_ok(const bagl_element_t *e) {
io_exchange(CHANNEL_APDU | IO_RETURN_AFTER_TX, tx); io_exchange(CHANNEL_APDU | IO_RETURN_AFTER_TX, tx);
// Display back the original UX // Display back the original UX
ui_idle(); ui_idle();
return 0; // do not redraw the widget return 0; // do not redraw the widget
} }
unsigned int io_seproxyhal_touch_signMessage712_v0_cancel(const bagl_element_t *e) { unsigned int io_seproxyhal_touch_signMessage712_v0_cancel(const bagl_element_t *e) {
@@ -59,6 +78,5 @@ unsigned int io_seproxyhal_touch_signMessage712_v0_cancel(const bagl_element_t *
io_exchange(CHANNEL_APDU | IO_RETURN_AFTER_TX, 2); io_exchange(CHANNEL_APDU | IO_RETURN_AFTER_TX, 2);
// Display back the original UX // Display back the original UX
ui_idle(); ui_idle();
return 0; // do not redraw the widget return 0; // do not redraw the widget
} }

View File

@@ -2,13 +2,14 @@
#include "ui_callbacks.h" #include "ui_callbacks.h"
void prepare_domain_hash_v0() { void prepare_domain_hash_v0() {
snprintf(strings.tmp.tmp, 70, "0x%.*H", 32, tmpCtx.messageSigningContext712.domainHash); snprintf(strings.tmp.tmp, 70, "0x%.*H", 32, tmpCtx.messageSigningContext712.domainHash);
} }
void prepare_message_hash_v0() { void prepare_message_hash_v0() {
snprintf(strings.tmp.tmp, 70, "0x%.*H", 32, tmpCtx.messageSigningContext712.messageHash); snprintf(strings.tmp.tmp, 70, "0x%.*H", 32, tmpCtx.messageSigningContext712.messageHash);
} }
// clang-format off
UX_STEP_NOCB( UX_STEP_NOCB(
ux_sign_712_v0_flow_1_step, ux_sign_712_v0_flow_1_step,
pnn, pnn,
@@ -51,12 +52,11 @@ UX_STEP_CB(
"Cancel", "Cancel",
"signature", "signature",
}); });
// clang-format on
UX_FLOW(ux_sign_712_v0_flow, UX_FLOW(ux_sign_712_v0_flow,
&ux_sign_712_v0_flow_1_step, &ux_sign_712_v0_flow_1_step,
&ux_sign_712_v0_flow_2_step, &ux_sign_712_v0_flow_2_step,
&ux_sign_712_v0_flow_3_step, &ux_sign_712_v0_flow_3_step,
&ux_sign_712_v0_flow_4_step, &ux_sign_712_v0_flow_4_step,
&ux_sign_712_v0_flow_5_step &ux_sign_712_v0_flow_5_step);
);

View File

@@ -3,74 +3,79 @@
#include "ui_flow.h" #include "ui_flow.h"
#include "feature_signTx.h" #include "feature_signTx.h"
void handleSign(uint8_t p1, uint8_t p2, uint8_t *workBuffer, uint16_t dataLength, unsigned int *flags, unsigned int *tx) { void handleSign(uint8_t p1,
UNUSED(tx); uint8_t p2,
parserStatus_e txResult; uint8_t *workBuffer,
uint32_t i; uint16_t dataLength,
if (p1 == P1_FIRST) { unsigned int *flags,
if (dataLength < 1) { unsigned int *tx) {
PRINTF("Invalid data\n"); UNUSED(tx);
THROW(0x6a80); parserStatus_e txResult;
uint32_t i;
if (p1 == P1_FIRST) {
if (dataLength < 1) {
PRINTF("Invalid data\n");
THROW(0x6a80);
}
if (appState != APP_STATE_IDLE) {
reset_app_context();
}
appState = APP_STATE_SIGNING_TX;
tmpCtx.transactionContext.pathLength = workBuffer[0];
if ((tmpCtx.transactionContext.pathLength < 0x01) ||
(tmpCtx.transactionContext.pathLength > MAX_BIP32_PATH)) {
PRINTF("Invalid path\n");
THROW(0x6a80);
}
workBuffer++;
dataLength--;
for (i = 0; i < tmpCtx.transactionContext.pathLength; i++) {
if (dataLength < 4) {
PRINTF("Invalid data\n");
THROW(0x6a80);
}
tmpCtx.transactionContext.bip32Path[i] = U4BE(workBuffer, 0);
workBuffer += 4;
dataLength -= 4;
}
dataPresent = false;
dataContext.tokenContext.pluginAvailable = 0;
initTx(&txContext, &global_sha3, &tmpContent.txContent, customProcessor, NULL);
} else if (p1 != P1_MORE) {
THROW(0x6B00);
} }
if (appState != APP_STATE_IDLE) { if (p2 != 0) {
reset_app_context(); THROW(0x6B00);
} }
appState = APP_STATE_SIGNING_TX; if ((p1 == P1_MORE) && (appState != APP_STATE_SIGNING_TX)) {
tmpCtx.transactionContext.pathLength = workBuffer[0]; PRINTF("Signature not initialized\n");
if ((tmpCtx.transactionContext.pathLength < 0x01) || THROW(0x6985);
(tmpCtx.transactionContext.pathLength > MAX_BIP32_PATH)) {
PRINTF("Invalid path\n");
THROW(0x6a80);
} }
workBuffer++; if (txContext.currentField == TX_RLP_NONE) {
dataLength--; PRINTF("Parser not initialized\n");
for (i = 0; i < tmpCtx.transactionContext.pathLength; i++) { THROW(0x6985);
if (dataLength < 4) { }
PRINTF("Invalid data\n"); txResult = processTx(&txContext,
THROW(0x6a80); workBuffer,
} dataLength,
tmpCtx.transactionContext.bip32Path[i] = U4BE(workBuffer, 0); (chainConfig->kind == CHAIN_KIND_WANCHAIN ? TX_FLAG_TYPE : 0));
workBuffer += 4; switch (txResult) {
dataLength -= 4; case USTREAM_SUSPENDED:
break;
case USTREAM_FINISHED:
break;
case USTREAM_PROCESSING:
THROW(0x9000);
case USTREAM_FAULT:
THROW(0x6A80);
default:
PRINTF("Unexpected parser status\n");
THROW(0x6A80);
} }
dataPresent = false;
dataContext.tokenContext.pluginAvailable = 0;
initTx(&txContext, &global_sha3, &tmpContent.txContent, customProcessor, NULL);
}
else
if (p1 != P1_MORE) {
THROW(0x6B00);
}
if (p2 != 0) {
THROW(0x6B00);
}
if ((p1 == P1_MORE) && (appState != APP_STATE_SIGNING_TX)) {
PRINTF("Signature not initialized\n");
THROW(0x6985);
}
if (txContext.currentField == TX_RLP_NONE) {
PRINTF("Parser not initialized\n");
THROW(0x6985);
}
txResult = processTx(&txContext, workBuffer, dataLength, (chainConfig->kind == CHAIN_KIND_WANCHAIN ? TX_FLAG_TYPE : 0));
switch (txResult) {
case USTREAM_SUSPENDED:
break;
case USTREAM_FINISHED:
break;
case USTREAM_PROCESSING:
THROW(0x9000);
case USTREAM_FAULT:
THROW(0x6A80);
default:
PRINTF("Unexpected parser status\n");
THROW(0x6A80);
}
if (txResult == USTREAM_FINISHED) { if (txResult == USTREAM_FINISHED) {
finalizeParsing(false); finalizeParsing(false);
} }
*flags |= IO_ASYNCH_REPLY; *flags |= IO_ASYNCH_REPLY;
} }

View File

@@ -2,4 +2,3 @@
customStatus_e customProcessor(txContext_t *context); customStatus_e customProcessor(txContext_t *context);
void finalizeParsing(bool direct); void finalizeParsing(bool direct);

View File

@@ -11,7 +11,7 @@
uint32_t splitBinaryParameterPart(char *result, uint8_t *parameter) { uint32_t splitBinaryParameterPart(char *result, uint8_t *parameter) {
uint32_t i; uint32_t i;
for (i=0; i<8; i++) { for (i = 0; i < 8; i++) {
if (parameter[i] != 0x00) { if (parameter[i] != 0x00) {
break; break;
} }
@@ -21,16 +21,14 @@ uint32_t splitBinaryParameterPart(char *result, uint8_t *parameter) {
result[1] = '0'; result[1] = '0';
result[2] = '\0'; result[2] = '\0';
return 2; return 2;
} } else {
else {
array_hexstr(result, parameter + i, 8 - i); array_hexstr(result, parameter + i, 8 - i);
return ((8 - i) * 2); return ((8 - i) * 2);
} }
} }
customStatus_e customProcessor(txContext_t *context) { customStatus_e customProcessor(txContext_t *context) {
if ((context->currentField == TX_RLP_DATA) && if ((context->currentField == TX_RLP_DATA) && (context->currentFieldLength != 0)) {
(context->currentFieldLength != 0)) {
dataPresent = true; dataPresent = true;
// If handling a new contract rather than a function call, abort immediately // If handling a new contract rather than a function call, abort immediately
if (tmpContent.txContent.destinationLength == 0) { if (tmpContent.txContent.destinationLength == 0) {
@@ -38,320 +36,341 @@ customStatus_e customProcessor(txContext_t *context) {
} }
if (context->currentFieldPos == 0) { if (context->currentFieldPos == 0) {
ethPluginInitContract_t pluginInit; ethPluginInitContract_t pluginInit;
// If handling the beginning of the data field, assume that the function selector is present // If handling the beginning of the data field, assume that the function selector is
// present
if (context->commandLength < 4) { if (context->commandLength < 4) {
PRINTF("Missing function selector\n"); PRINTF("Missing function selector\n");
return CUSTOM_FAULT; return CUSTOM_FAULT;
} }
eth_plugin_prepare_init(&pluginInit, context->workBuffer, context->currentFieldLength); eth_plugin_prepare_init(&pluginInit, context->workBuffer, context->currentFieldLength);
dataContext.tokenContext.pluginAvailable = eth_plugin_perform_init(tmpContent.txContent.destination, &pluginInit); dataContext.tokenContext.pluginAvailable =
eth_plugin_perform_init(tmpContent.txContent.destination, &pluginInit);
PRINTF("pluginAvailable %d\n", dataContext.tokenContext.pluginAvailable); PRINTF("pluginAvailable %d\n", dataContext.tokenContext.pluginAvailable);
if (dataContext.tokenContext.pluginAvailable) { if (dataContext.tokenContext.pluginAvailable) {
dataContext.tokenContext.fieldIndex = 0; dataContext.tokenContext.fieldIndex = 0;
dataContext.tokenContext.fieldOffset = 0; dataContext.tokenContext.fieldOffset = 0;
copyTxData(context, NULL, 4); copyTxData(context, NULL, 4);
if (context->currentFieldLength == 4) { if (context->currentFieldLength == 4) {
return CUSTOM_NOT_HANDLED; return CUSTOM_NOT_HANDLED;
} }
} }
} }
uint32_t blockSize; uint32_t blockSize;
uint32_t copySize; uint32_t copySize;
uint32_t fieldPos = context->currentFieldPos; uint32_t fieldPos = context->currentFieldPos;
if (fieldPos == 0) { // not reached if a plugin is available if (fieldPos == 0) { // not reached if a plugin is available
if (!N_storage.dataAllowed) { if (!N_storage.dataAllowed) {
PRINTF("Data field forbidden\n"); PRINTF("Data field forbidden\n");
return CUSTOM_FAULT; return CUSTOM_FAULT;
} }
if (!N_storage.contractDetails) { if (!N_storage.contractDetails) {
return CUSTOM_NOT_HANDLED; return CUSTOM_NOT_HANDLED;
} }
dataContext.tokenContext.fieldIndex = 0; dataContext.tokenContext.fieldIndex = 0;
dataContext.tokenContext.fieldOffset = 0; dataContext.tokenContext.fieldOffset = 0;
blockSize = 4; blockSize = 4;
} } else {
else { if (!N_storage.contractDetails && !dataContext.tokenContext.pluginAvailable) {
if (!N_storage.contractDetails && !dataContext.tokenContext.pluginAvailable) {
return CUSTOM_NOT_HANDLED; return CUSTOM_NOT_HANDLED;
} }
blockSize = 32 - (dataContext.tokenContext.fieldOffset % 32); blockSize = 32 - (dataContext.tokenContext.fieldOffset % 32);
} }
// Sanity check // Sanity check
if ((context->currentFieldLength - fieldPos) < blockSize) { if ((context->currentFieldLength - fieldPos) < blockSize) {
PRINTF("Unconsistent data\n"); PRINTF("Unconsistent data\n");
return CUSTOM_FAULT; return CUSTOM_FAULT;
} }
copySize = (context->commandLength < blockSize ? context->commandLength : blockSize); copySize = (context->commandLength < blockSize ? context->commandLength : blockSize);
PRINTF("currentFieldPos %d copySize %d\n", context->currentFieldPos, copySize); PRINTF("currentFieldPos %d copySize %d\n", context->currentFieldPos, copySize);
copyTxData(context, copyTxData(context,
dataContext.tokenContext.data + dataContext.tokenContext.fieldOffset, dataContext.tokenContext.data + dataContext.tokenContext.fieldOffset,
copySize); copySize);
if (context->currentFieldPos == context->currentFieldLength) { if (context->currentFieldPos == context->currentFieldLength) {
context->currentField++; context->currentField++;
context->processingField = false; context->processingField = false;
} }
dataContext.tokenContext.fieldOffset += copySize; dataContext.tokenContext.fieldOffset += copySize;
if (copySize == blockSize) { if (copySize == blockSize) {
// Can process or display // Can process or display
if (dataContext.tokenContext.pluginAvailable) { if (dataContext.tokenContext.pluginAvailable) {
ethPluginProvideParameter_t pluginProvideParameter; ethPluginProvideParameter_t pluginProvideParameter;
eth_plugin_prepare_provide_parameter(&pluginProvideParameter, eth_plugin_prepare_provide_parameter(&pluginProvideParameter,
dataContext.tokenContext.data, dataContext.tokenContext.data,
dataContext.tokenContext.fieldIndex * 32 + 4); dataContext.tokenContext.fieldIndex * 32 + 4);
if (!eth_plugin_call(NULL, ETH_PLUGIN_PROVIDE_PARAMETER, (void*)&pluginProvideParameter)) { if (!eth_plugin_call(NULL,
PRINTF("Plugin parameter call failed\n"); ETH_PLUGIN_PROVIDE_PARAMETER,
return CUSTOM_FAULT; (void *) &pluginProvideParameter)) {
PRINTF("Plugin parameter call failed\n");
return CUSTOM_FAULT;
} }
dataContext.tokenContext.fieldIndex++; dataContext.tokenContext.fieldIndex++;
dataContext.tokenContext.fieldOffset = 0; dataContext.tokenContext.fieldOffset = 0;
return CUSTOM_HANDLED; return CUSTOM_HANDLED;
} }
if (fieldPos != 0) { if (fieldPos != 0) {
dataContext.tokenContext.fieldIndex++; dataContext.tokenContext.fieldIndex++;
} }
dataContext.tokenContext.fieldOffset = 0; dataContext.tokenContext.fieldOffset = 0;
if (fieldPos == 0) { if (fieldPos == 0) {
array_hexstr(strings.tmp.tmp, dataContext.tokenContext.data, 4); array_hexstr(strings.tmp.tmp, dataContext.tokenContext.data, 4);
ux_flow_init(0, ux_confirm_selector_flow, NULL); ux_flow_init(0, ux_confirm_selector_flow, NULL);
} } else {
else { uint32_t offset = 0;
uint32_t offset = 0; uint32_t i;
uint32_t i; snprintf(strings.tmp.tmp2,
snprintf(strings.tmp.tmp2, sizeof(strings.tmp.tmp2), "Field %d", dataContext.tokenContext.fieldIndex); sizeof(strings.tmp.tmp2),
for (i=0; i<4; i++) { "Field %d",
offset += splitBinaryParameterPart(strings.tmp.tmp + offset, dataContext.tokenContext.data + 8 * i); dataContext.tokenContext.fieldIndex);
if (i != 3) { for (i = 0; i < 4; i++) {
strings.tmp.tmp[offset++] = ':'; offset += splitBinaryParameterPart(strings.tmp.tmp + offset,
} dataContext.tokenContext.data + 8 * i);
} if (i != 3) {
ux_flow_init(0, ux_confirm_parameter_flow, NULL); strings.tmp.tmp[offset++] = ':';
} }
} }
else { ux_flow_init(0, ux_confirm_parameter_flow, NULL);
return CUSTOM_HANDLED; }
} } else {
return CUSTOM_HANDLED;
}
return CUSTOM_SUSPENDED; return CUSTOM_SUSPENDED;
} }
return CUSTOM_NOT_HANDLED; return CUSTOM_NOT_HANDLED;
} }
void to_uppercase(char *str, unsigned char size) {
void to_uppercase(char* str, unsigned char size){ for (unsigned char i = 0; i < size && str[i] != 0; i++) {
for (unsigned char i = 0; i < size && str[i] != 0; i++)
{
str[i] = str[i] >= 'a' ? str[i] - ('a' - 'A') : str[i]; str[i] = str[i] >= 'a' ? str[i] - ('a' - 'A') : str[i];
} }
} }
void compareOrCopy(char* preapproved_string, char* parsed_string, bool silent_mode){ void compareOrCopy(char *preapproved_string, char *parsed_string, bool silent_mode) {
if(silent_mode){ if (silent_mode) {
/* ETH address are not fundamentally case sensitive but might /* ETH address are not fundamentally case sensitive but might
have some for checksum purpose, so let's get rid of these diffs */ have some for checksum purpose, so let's get rid of these diffs */
to_uppercase(preapproved_string, strlen(preapproved_string)); to_uppercase(preapproved_string, strlen(preapproved_string));
to_uppercase(parsed_string, strlen(parsed_string)); to_uppercase(parsed_string, strlen(parsed_string));
if(memcmp(preapproved_string, parsed_string, strlen(preapproved_string))){ if (memcmp(preapproved_string, parsed_string, strlen(preapproved_string))) {
THROW(ERR_SILENT_MODE_CHECK_FAILED); THROW(ERR_SILENT_MODE_CHECK_FAILED);
}
} else {
strcpy(preapproved_string, parsed_string);
} }
}
else{
strcpy(preapproved_string, parsed_string);
}
} }
void reportFinalizeError(bool direct) { void reportFinalizeError(bool direct) {
reset_app_context(); reset_app_context();
if (direct) { if (direct) {
THROW(0x6A80); THROW(0x6A80);
} } else {
else { io_seproxyhal_send_status(0x6A80);
io_seproxyhal_send_status(0x6A80); ui_idle();
ui_idle(); }
}
} }
void computeFees(char *displayBuffer, uint32_t displayBufferSize) { void computeFees(char *displayBuffer, uint32_t displayBufferSize) {
uint256_t gasPrice, startGas, uint256; uint256_t gasPrice, startGas, uint256;
uint8_t *feeTicker = (uint8_t *)PIC(chainConfig->coinName); uint8_t *feeTicker = (uint8_t *) PIC(chainConfig->coinName);
uint8_t tickerOffset = 0; uint8_t tickerOffset = 0;
uint32_t i; uint32_t i;
PRINTF("Max fee\n"); PRINTF("Max fee\n");
PRINTF("Gasprice %.*H\n", tmpContent.txContent.gasprice.length, tmpContent.txContent.gasprice.value); PRINTF("Gasprice %.*H\n",
PRINTF("Startgas %.*H\n", tmpContent.txContent.startgas.length, tmpContent.txContent.startgas.value); tmpContent.txContent.gasprice.length,
convertUint256BE(tmpContent.txContent.gasprice.value, tmpContent.txContent.gasprice.length, &gasPrice); tmpContent.txContent.gasprice.value);
convertUint256BE(tmpContent.txContent.startgas.value, tmpContent.txContent.startgas.length, &startGas); PRINTF("Startgas %.*H\n",
mul256(&gasPrice, &startGas, &uint256); tmpContent.txContent.startgas.length,
tostring256(&uint256, 10, (char *)(G_io_apdu_buffer + 100), 100); tmpContent.txContent.startgas.value);
i = 0; convertUint256BE(tmpContent.txContent.gasprice.value,
while (G_io_apdu_buffer[100 + i]) { tmpContent.txContent.gasprice.length,
i++; &gasPrice);
} convertUint256BE(tmpContent.txContent.startgas.value,
adjustDecimals((char *)(G_io_apdu_buffer + 100), i, (char *)G_io_apdu_buffer, 100, WEI_TO_ETHER); tmpContent.txContent.startgas.length,
i = 0; &startGas);
tickerOffset=0; mul256(&gasPrice, &startGas, &uint256);
memset(displayBuffer, 0, displayBufferSize); tostring256(&uint256, 10, (char *) (G_io_apdu_buffer + 100), 100);
while (feeTicker[tickerOffset]) { i = 0;
displayBuffer[tickerOffset] = feeTicker[tickerOffset]; while (G_io_apdu_buffer[100 + i]) {
tickerOffset++; i++;
} }
while (G_io_apdu_buffer[i]) { adjustDecimals((char *) (G_io_apdu_buffer + 100),
displayBuffer[tickerOffset + i] = G_io_apdu_buffer[i]; i,
i++; (char *) G_io_apdu_buffer,
} 100,
displayBuffer[tickerOffset + i] = '\0'; WEI_TO_ETHER);
i = 0;
tickerOffset = 0;
memset(displayBuffer, 0, displayBufferSize);
while (feeTicker[tickerOffset]) {
displayBuffer[tickerOffset] = feeTicker[tickerOffset];
tickerOffset++;
}
while (G_io_apdu_buffer[i]) {
displayBuffer[tickerOffset + i] = G_io_apdu_buffer[i];
i++;
}
displayBuffer[tickerOffset + i] = '\0';
} }
void finalizeParsing(bool direct) { void finalizeParsing(bool direct) {
char displayBuffer[50]; char displayBuffer[50];
uint8_t decimals = WEI_TO_ETHER; uint8_t decimals = WEI_TO_ETHER;
uint8_t *ticker = (uint8_t *)PIC(chainConfig->coinName); uint8_t *ticker = (uint8_t *) PIC(chainConfig->coinName);
ethPluginFinalize_t pluginFinalize; ethPluginFinalize_t pluginFinalize;
tokenDefinition_t *token1 = NULL, *token2 = NULL; tokenDefinition_t *token1 = NULL, *token2 = NULL;
bool genericUI = true; bool genericUI = true;
// Verify the chain // Verify the chain
if (chainConfig->chainId != 0) { if (chainConfig->chainId != 0) {
uint32_t v = getV(&tmpContent.txContent); uint32_t v = getV(&tmpContent.txContent);
if (chainConfig->chainId != v) { if (chainConfig->chainId != v) {
reset_app_context(); reset_app_context();
PRINTF("Invalid chainId %d expected %d\n", v, chainConfig->chainId); PRINTF("Invalid chainId %d expected %d\n", v, chainConfig->chainId);
reportFinalizeError(direct);
if (!direct) {
return;
}
}
}
// Store the hash
cx_hash((cx_hash_t *)&global_sha3, CX_LAST, tmpCtx.transactionContext.hash, 0, tmpCtx.transactionContext.hash, 32);
// Finalize the plugin handling
if (dataContext.tokenContext.pluginAvailable) {
genericUI = false;
eth_plugin_prepare_finalize(&pluginFinalize);
if (!eth_plugin_call(NULL, ETH_PLUGIN_FINALIZE, (void*)&pluginFinalize)) {
PRINTF("Plugin finalize call failed\n");
reportFinalizeError(direct);
if (!direct) {
return;
}
}
// Lookup tokens if requested
if (pluginFinalize.tokenLookup1 != NULL) {
ethPluginProvideToken_t pluginProvideToken;
token1 = getKnownToken(pluginFinalize.tokenLookup1);
if (pluginFinalize.tokenLookup2 != NULL) {
token2 = getKnownToken(pluginFinalize.tokenLookup2);
}
eth_plugin_prepare_provide_token(&pluginProvideToken, token1, token2);
if (!eth_plugin_call(NULL, ETH_PLUGIN_PROVIDE_TOKEN, (void*)&pluginProvideToken)) {
PRINTF("Plugin provide token call failed\n");
reportFinalizeError(direct);
if (!direct) {
return;
}
}
pluginFinalize.result = pluginProvideToken.result;
}
if (pluginFinalize.result != ETH_PLUGIN_RESULT_FALLBACK) {
// Handle the right interface
switch(pluginFinalize.uiType) {
case ETH_UI_TYPE_GENERIC:
dataPresent = false;
dataContext.tokenContext.pluginUiMaxItems = pluginFinalize.numScreens;
break;
case ETH_UI_TYPE_AMOUNT_ADDRESS:
genericUI = true;
dataPresent = false;
if ((pluginFinalize.amount == NULL) || (pluginFinalize.address == NULL)) {
PRINTF("Incorrect amount/address set by plugin\n");
reportFinalizeError(direct); reportFinalizeError(direct);
if (!direct) { if (!direct) {
return; return;
} }
} }
memmove(tmpContent.txContent.value.value, pluginFinalize.amount, 32); }
tmpContent.txContent.value.length = 32; // Store the hash
memmove(tmpContent.txContent.destination, pluginFinalize.address, 20); cx_hash((cx_hash_t *) &global_sha3,
tmpContent.txContent.destinationLength = 20; CX_LAST,
if (token1 != NULL) { tmpCtx.transactionContext.hash,
decimals = token1->decimals; 0,
ticker = token1->ticker; tmpCtx.transactionContext.hash,
} 32);
break;
default: // Finalize the plugin handling
PRINTF("ui type %d not supported\n", pluginFinalize.uiType); if (dataContext.tokenContext.pluginAvailable) {
reportFinalizeError(direct); genericUI = false;
if (!direct) { eth_plugin_prepare_finalize(&pluginFinalize);
if (!eth_plugin_call(NULL, ETH_PLUGIN_FINALIZE, (void *) &pluginFinalize)) {
PRINTF("Plugin finalize call failed\n");
reportFinalizeError(direct);
if (!direct) {
return;
}
}
// Lookup tokens if requested
if (pluginFinalize.tokenLookup1 != NULL) {
ethPluginProvideToken_t pluginProvideToken;
token1 = getKnownToken(pluginFinalize.tokenLookup1);
if (pluginFinalize.tokenLookup2 != NULL) {
token2 = getKnownToken(pluginFinalize.tokenLookup2);
}
eth_plugin_prepare_provide_token(&pluginProvideToken, token1, token2);
if (!eth_plugin_call(NULL, ETH_PLUGIN_PROVIDE_TOKEN, (void *) &pluginProvideToken)) {
PRINTF("Plugin provide token call failed\n");
reportFinalizeError(direct);
if (!direct) {
return;
}
}
pluginFinalize.result = pluginProvideToken.result;
}
if (pluginFinalize.result != ETH_PLUGIN_RESULT_FALLBACK) {
// Handle the right interface
switch (pluginFinalize.uiType) {
case ETH_UI_TYPE_GENERIC:
dataPresent = false;
dataContext.tokenContext.pluginUiMaxItems = pluginFinalize.numScreens;
break;
case ETH_UI_TYPE_AMOUNT_ADDRESS:
genericUI = true;
dataPresent = false;
if ((pluginFinalize.amount == NULL) || (pluginFinalize.address == NULL)) {
PRINTF("Incorrect amount/address set by plugin\n");
reportFinalizeError(direct);
if (!direct) {
return;
}
}
memmove(tmpContent.txContent.value.value, pluginFinalize.amount, 32);
tmpContent.txContent.value.length = 32;
memmove(tmpContent.txContent.destination, pluginFinalize.address, 20);
tmpContent.txContent.destinationLength = 20;
if (token1 != NULL) {
decimals = token1->decimals;
ticker = token1->ticker;
}
break;
default:
PRINTF("ui type %d not supported\n", pluginFinalize.uiType);
reportFinalizeError(direct);
if (!direct) {
return;
}
}
} else {
genericUI = true;
}
}
if (dataPresent && !N_storage.dataAllowed) {
PRINTF("Data field forbidden\n");
reportFinalizeError(direct);
if (!direct) {
return; return;
} }
}
} }
else { // Prepare destination address to display
genericUI = true; if (genericUI) {
if (tmpContent.txContent.destinationLength != 0) {
displayBuffer[0] = '0';
displayBuffer[1] = 'x';
getEthAddressStringFromBinary(tmpContent.txContent.destination,
(uint8_t *) displayBuffer + 2,
&global_sha3,
chainConfig);
compareOrCopy(strings.common.fullAddress, displayBuffer, called_from_swap);
} else {
strcpy(strings.common.fullAddress, "Contract");
}
}
// Prepare amount to display
if (genericUI) {
amountToString(tmpContent.txContent.value.value,
tmpContent.txContent.value.length,
decimals,
(char *) ticker,
displayBuffer,
sizeof(displayBuffer));
compareOrCopy(strings.common.fullAmount, displayBuffer, called_from_swap);
}
// Compute maximum fee
if (genericUI) {
computeFees(displayBuffer, sizeof(displayBuffer));
compareOrCopy(strings.common.maxFee, displayBuffer, called_from_swap);
} }
}
if (dataPresent && !N_storage.dataAllowed) { bool no_consent = false;
PRINTF("Data field forbidden\n");
reportFinalizeError(direct);
if (!direct) {
return;
}
}
// Prepare destination address to display
if (genericUI) {
if (tmpContent.txContent.destinationLength != 0) {
displayBuffer[0] = '0';
displayBuffer[1] = 'x';
getEthAddressStringFromBinary(tmpContent.txContent.destination, (uint8_t*)displayBuffer+2, &global_sha3, chainConfig);
compareOrCopy(strings.common.fullAddress, displayBuffer, called_from_swap);
}
else
{
strcpy(strings.common.fullAddress, "Contract");
}
}
// Prepare amount to display
if (genericUI) {
amountToString(tmpContent.txContent.value.value, tmpContent.txContent.value.length, decimals, (char*)ticker, displayBuffer, sizeof(displayBuffer));
compareOrCopy(strings.common.fullAmount, displayBuffer, called_from_swap);
}
// Compute maximum fee
if (genericUI) {
computeFees(displayBuffer, sizeof(displayBuffer));
compareOrCopy(strings.common.maxFee, displayBuffer, called_from_swap);
}
bool no_consent = false; no_consent = called_from_swap;
no_consent = called_from_swap;
#ifdef NO_CONSENT #ifdef NO_CONSENT
no_consent = true; no_consent = true;
#endif // NO_CONSENT #endif // NO_CONSENT
if(no_consent){ if (no_consent) {
io_seproxyhal_touch_tx_ok(NULL); io_seproxyhal_touch_tx_ok(NULL);
} } else {
else{ if (genericUI) {
ux_flow_init(
if (genericUI) { 0,
ux_flow_init(0, ((dataPresent && !N_storage.contractDetails) ? ux_approval_tx_data_warning_flow
((dataPresent && !N_storage.contractDetails) ? ux_approval_tx_data_warning_flow : ux_approval_tx_flow), : ux_approval_tx_flow),
NULL); NULL);
} else {
plugin_ui_start();
}
} }
else {
plugin_ui_start();
}
}
} }

View File

@@ -10,34 +10,38 @@ unsigned int io_seproxyhal_touch_tx_ok(const bagl_element_t *e) {
uint32_t tx = 0; uint32_t tx = 0;
uint32_t v = getV(&tmpContent.txContent); uint32_t v = getV(&tmpContent.txContent);
io_seproxyhal_io_heartbeat(); io_seproxyhal_io_heartbeat();
os_perso_derive_node_bip32(CX_CURVE_256K1, tmpCtx.transactionContext.bip32Path, os_perso_derive_node_bip32(CX_CURVE_256K1,
tmpCtx.transactionContext.bip32Path,
tmpCtx.transactionContext.pathLength, tmpCtx.transactionContext.pathLength,
privateKeyData, NULL); privateKeyData,
cx_ecfp_init_private_key(CX_CURVE_256K1, privateKeyData, 32, NULL);
&privateKey); cx_ecfp_init_private_key(CX_CURVE_256K1, privateKeyData, 32, &privateKey);
explicit_bzero(privateKeyData, sizeof(privateKeyData)); explicit_bzero(privateKeyData, sizeof(privateKeyData));
unsigned int info = 0; unsigned int info = 0;
io_seproxyhal_io_heartbeat(); io_seproxyhal_io_heartbeat();
signatureLength = signatureLength = cx_ecdsa_sign(&privateKey,
cx_ecdsa_sign(&privateKey, CX_RND_RFC6979 | CX_LAST, CX_SHA256, CX_RND_RFC6979 | CX_LAST,
tmpCtx.transactionContext.hash, CX_SHA256,
sizeof(tmpCtx.transactionContext.hash), signature, sizeof(signature), &info); tmpCtx.transactionContext.hash,
sizeof(tmpCtx.transactionContext.hash),
signature,
sizeof(signature),
&info);
explicit_bzero(&privateKey, sizeof(privateKey)); explicit_bzero(&privateKey, sizeof(privateKey));
// Parity is present in the sequence tag in the legacy API // Parity is present in the sequence tag in the legacy API
if (tmpContent.txContent.vLength == 0) { if (tmpContent.txContent.vLength == 0) {
// Legacy API // Legacy API
G_io_apdu_buffer[0] = 27; G_io_apdu_buffer[0] = 27;
} } else {
else { // New API
// New API // Note that this is wrong for a large v, but the client can always recover
// Note that this is wrong for a large v, but the client can always recover G_io_apdu_buffer[0] = (v * 2) + 35;
G_io_apdu_buffer[0] = (v * 2) + 35;
} }
if (info & CX_ECCINFO_PARITY_ODD) { if (info & CX_ECCINFO_PARITY_ODD) {
G_io_apdu_buffer[0]++; G_io_apdu_buffer[0]++;
} }
if (info & CX_ECCINFO_xGTn) { if (info & CX_ECCINFO_xGTn) {
G_io_apdu_buffer[0] += 2; G_io_apdu_buffer[0] += 2;
} }
format_signature_out(signature); format_signature_out(signature);
tx = 65; tx = 65;
@@ -45,13 +49,13 @@ unsigned int io_seproxyhal_touch_tx_ok(const bagl_element_t *e) {
G_io_apdu_buffer[tx++] = 0x00; G_io_apdu_buffer[tx++] = 0x00;
// Send back the response, do not restart the event loop // Send back the response, do not restart the event loop
io_exchange(CHANNEL_APDU | IO_RETURN_AFTER_TX, tx); io_exchange(CHANNEL_APDU | IO_RETURN_AFTER_TX, tx);
if(called_from_swap){ if (called_from_swap) {
os_sched_exit(0); os_sched_exit(0);
} }
reset_app_context(); reset_app_context();
// Display back the original UX // Display back the original UX
ui_idle(); ui_idle();
return 0; // do not redraw the widget return 0; // do not redraw the widget
} }
unsigned int io_seproxyhal_touch_tx_cancel(const bagl_element_t *e) { unsigned int io_seproxyhal_touch_tx_cancel(const bagl_element_t *e) {
@@ -62,31 +66,31 @@ unsigned int io_seproxyhal_touch_tx_cancel(const bagl_element_t *e) {
io_exchange(CHANNEL_APDU | IO_RETURN_AFTER_TX, 2); io_exchange(CHANNEL_APDU | IO_RETURN_AFTER_TX, 2);
// Display back the original UX // Display back the original UX
ui_idle(); ui_idle();
return 0; // do not redraw the widget return 0; // do not redraw the widget
} }
unsigned int io_seproxyhal_touch_data_ok(const bagl_element_t *e) { unsigned int io_seproxyhal_touch_data_ok(const bagl_element_t *e) {
parserStatus_e txResult = USTREAM_FINISHED; parserStatus_e txResult = USTREAM_FINISHED;
txResult = continueTx(&txContext); txResult = continueTx(&txContext);
switch (txResult) { switch (txResult) {
case USTREAM_SUSPENDED: case USTREAM_SUSPENDED:
break; break;
case USTREAM_FINISHED: case USTREAM_FINISHED:
break; break;
case USTREAM_PROCESSING: case USTREAM_PROCESSING:
io_seproxyhal_send_status(0x9000); io_seproxyhal_send_status(0x9000);
ui_idle(); ui_idle();
break; break;
case USTREAM_FAULT: case USTREAM_FAULT:
reset_app_context(); reset_app_context();
io_seproxyhal_send_status(0x6A80); io_seproxyhal_send_status(0x6A80);
ui_idle(); ui_idle();
break; break;
default: default:
PRINTF("Unexpected parser status\n"); PRINTF("Unexpected parser status\n");
reset_app_context(); reset_app_context();
io_seproxyhal_send_status(0x6A80); io_seproxyhal_send_status(0x6A80);
ui_idle(); ui_idle();
} }
if (txResult == USTREAM_FINISHED) { if (txResult == USTREAM_FINISHED) {
@@ -101,6 +105,5 @@ unsigned int io_seproxyhal_touch_data_cancel(const bagl_element_t *e) {
io_seproxyhal_send_status(0x6985); io_seproxyhal_send_status(0x6985);
// Display back the original UX // Display back the original UX
ui_idle(); ui_idle();
return 0; // do not redraw the widget return 0; // do not redraw the widget
} }

View File

@@ -1,6 +1,7 @@
#include "shared_context.h" #include "shared_context.h"
#include "ui_callbacks.h" #include "ui_callbacks.h"
// clang-format off
UX_STEP_NOCB( UX_STEP_NOCB(
ux_confirm_selector_flow_1_step, ux_confirm_selector_flow_1_step,
pnn, pnn,
@@ -33,15 +34,16 @@ UX_STEP_CB(
&C_icon_crossmark, &C_icon_crossmark,
"Reject", "Reject",
}); });
// clang-format on
UX_FLOW(ux_confirm_selector_flow, UX_FLOW(ux_confirm_selector_flow,
&ux_confirm_selector_flow_1_step, &ux_confirm_selector_flow_1_step,
&ux_confirm_selector_flow_2_step, &ux_confirm_selector_flow_2_step,
&ux_confirm_selector_flow_3_step, &ux_confirm_selector_flow_3_step,
&ux_confirm_selector_flow_4_step &ux_confirm_selector_flow_4_step);
);
////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////
// clang-format off
UX_STEP_NOCB( UX_STEP_NOCB(
ux_confirm_parameter_flow_1_step, ux_confirm_parameter_flow_1_step,
pnn, pnn,
@@ -73,15 +75,16 @@ UX_STEP_CB(
&C_icon_crossmark, &C_icon_crossmark,
"Reject", "Reject",
}); });
// clang-format on
UX_FLOW(ux_confirm_parameter_flow, UX_FLOW(ux_confirm_parameter_flow,
&ux_confirm_parameter_flow_1_step, &ux_confirm_parameter_flow_1_step,
&ux_confirm_parameter_flow_2_step, &ux_confirm_parameter_flow_2_step,
&ux_confirm_parameter_flow_3_step, &ux_confirm_parameter_flow_3_step,
&ux_confirm_parameter_flow_4_step &ux_confirm_parameter_flow_4_step);
);
////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////
// clang-format off
UX_STEP_NOCB(ux_approval_tx_1_step, UX_STEP_NOCB(ux_approval_tx_1_step,
pnn, pnn,
{ {
@@ -135,23 +138,21 @@ UX_STEP_NOCB(ux_approval_tx_data_warning_step,
"Data", "Data",
"Present", "Present",
}); });
// clang-format on
UX_FLOW(ux_approval_tx_flow, UX_FLOW(ux_approval_tx_flow,
&ux_approval_tx_1_step, &ux_approval_tx_1_step,
&ux_approval_tx_2_step, &ux_approval_tx_2_step,
&ux_approval_tx_3_step, &ux_approval_tx_3_step,
&ux_approval_tx_4_step, &ux_approval_tx_4_step,
&ux_approval_tx_5_step, &ux_approval_tx_5_step,
&ux_approval_tx_6_step &ux_approval_tx_6_step);
);
UX_FLOW(ux_approval_tx_data_warning_flow, UX_FLOW(ux_approval_tx_data_warning_flow,
&ux_approval_tx_1_step, &ux_approval_tx_1_step,
&ux_approval_tx_data_warning_step, &ux_approval_tx_data_warning_step,
&ux_approval_tx_2_step, &ux_approval_tx_2_step,
&ux_approval_tx_3_step, &ux_approval_tx_3_step,
&ux_approval_tx_4_step, &ux_approval_tx_4_step,
&ux_approval_tx_5_step, &ux_approval_tx_5_step,
&ux_approval_tx_6_step &ux_approval_tx_6_step);
);

View File

@@ -6,55 +6,61 @@
#include "feature_stark_getPublicKey.h" #include "feature_stark_getPublicKey.h"
#include "ui_flow.h" #include "ui_flow.h"
void handleStarkwareGetPublicKey(uint8_t p1, uint8_t p2, uint8_t *dataBuffer, uint16_t dataLength, unsigned int *flags, unsigned int *tx) { void handleStarkwareGetPublicKey(uint8_t p1,
UNUSED(dataLength); uint8_t p2,
uint8_t privateKeyData[32]; uint8_t *dataBuffer,
uint32_t bip32Path[MAX_BIP32_PATH]; uint16_t dataLength,
uint32_t i; unsigned int *flags,
uint8_t bip32PathLength = *(dataBuffer++); unsigned int *tx) {
cx_ecfp_private_key_t privateKey; UNUSED(dataLength);
reset_app_context(); uint8_t privateKeyData[32];
if ((bip32PathLength < 0x01) || uint32_t bip32Path[MAX_BIP32_PATH];
(bip32PathLength > MAX_BIP32_PATH)) { uint32_t i;
PRINTF("Invalid path\n"); uint8_t bip32PathLength = *(dataBuffer++);
THROW(0x6a80); cx_ecfp_private_key_t privateKey;
} reset_app_context();
if ((p1 != P1_CONFIRM) && (p1 != P1_NON_CONFIRM)) { if ((bip32PathLength < 0x01) || (bip32PathLength > MAX_BIP32_PATH)) {
THROW(0x6B00); PRINTF("Invalid path\n");
} THROW(0x6a80);
if (p2 != 0) { }
THROW(0x6B00); if ((p1 != P1_CONFIRM) && (p1 != P1_NON_CONFIRM)) {
} THROW(0x6B00);
for (i = 0; i < bip32PathLength; i++) { }
bip32Path[i] = U4BE(dataBuffer, 0); if (p2 != 0) {
dataBuffer += 4; THROW(0x6B00);
} }
io_seproxyhal_io_heartbeat(); for (i = 0; i < bip32PathLength; i++) {
starkDerivePrivateKey(bip32Path, bip32PathLength, privateKeyData); bip32Path[i] = U4BE(dataBuffer, 0);
cx_ecfp_init_private_key(CX_CURVE_Stark256, privateKeyData, 32, &privateKey); dataBuffer += 4;
io_seproxyhal_io_heartbeat(); }
cx_ecfp_generate_pair(CX_CURVE_Stark256, &tmpCtx.publicKeyContext.publicKey, &privateKey, 1); io_seproxyhal_io_heartbeat();
explicit_bzero(&privateKey, sizeof(privateKey)); starkDerivePrivateKey(bip32Path, bip32PathLength, privateKeyData);
explicit_bzero(privateKeyData, sizeof(privateKeyData)); cx_ecfp_init_private_key(CX_CURVE_Stark256, privateKeyData, 32, &privateKey);
io_seproxyhal_io_heartbeat(); io_seproxyhal_io_heartbeat();
cx_ecfp_generate_pair(CX_CURVE_Stark256, &tmpCtx.publicKeyContext.publicKey, &privateKey, 1);
explicit_bzero(&privateKey, sizeof(privateKey));
explicit_bzero(privateKeyData, sizeof(privateKeyData));
io_seproxyhal_io_heartbeat();
#ifndef NO_CONSENT #ifndef NO_CONSENT
if (p1 == P1_NON_CONFIRM) if (p1 == P1_NON_CONFIRM)
#endif // NO_CONSENT #endif // NO_CONSENT
{ {
*tx = set_result_get_stark_publicKey(); *tx = set_result_get_stark_publicKey();
THROW(0x9000); THROW(0x9000);
} }
#ifndef NO_CONSENT #ifndef NO_CONSENT
else else {
{ // prepare for a UI based reply
// prepare for a UI based reply snprintf(strings.tmp.tmp,
snprintf(strings.tmp.tmp, sizeof(strings.tmp.tmp), "0x%.*H", 32, tmpCtx.publicKeyContext.publicKey.W + 1); sizeof(strings.tmp.tmp),
ux_flow_init(0, ux_display_stark_public_flow, NULL); "0x%.*H",
32,
tmpCtx.publicKeyContext.publicKey.W + 1);
ux_flow_init(0, ux_display_stark_public_flow, NULL);
*flags |= IO_ASYNCH_REPLY; *flags |= IO_ASYNCH_REPLY;
} }
#endif // NO_CONSENT #endif // NO_CONSENT
} }
#endif #endif

View File

@@ -1,4 +1,3 @@
#include "shared_context.h" #include "shared_context.h"
uint32_t set_result_get_stark_publicKey(void); uint32_t set_result_get_stark_publicKey(void);

View File

@@ -11,5 +11,3 @@ uint32_t set_result_get_stark_publicKey() {
} }
#endif #endif

View File

@@ -13,8 +13,7 @@ unsigned int io_seproxyhal_touch_stark_pubkey_ok(const bagl_element_t *e) {
io_exchange(CHANNEL_APDU | IO_RETURN_AFTER_TX, tx); io_exchange(CHANNEL_APDU | IO_RETURN_AFTER_TX, tx);
// Display back the original UX // Display back the original UX
ui_idle(); ui_idle();
return 0; // do not redraw the widget return 0; // do not redraw the widget
} }
#endif #endif

View File

@@ -5,6 +5,7 @@
unsigned int io_seproxyhal_touch_stark_pubkey_ok(const bagl_element_t *e); unsigned int io_seproxyhal_touch_stark_pubkey_ok(const bagl_element_t *e);
// clang-format off
UX_STEP_NOCB( UX_STEP_NOCB(
ux_display_stark_public_flow_1_step, ux_display_stark_public_flow_1_step,
pnn, pnn,
@@ -36,13 +37,12 @@ UX_STEP_CB(
&C_icon_crossmark, &C_icon_crossmark,
"Reject", "Reject",
}); });
// clang-format on
UX_FLOW(ux_display_stark_public_flow, UX_FLOW(ux_display_stark_public_flow,
&ux_display_stark_public_flow_1_step, &ux_display_stark_public_flow_1_step,
&ux_display_stark_public_flow_2_step, &ux_display_stark_public_flow_2_step,
&ux_display_stark_public_flow_3_step, &ux_display_stark_public_flow_3_step,
&ux_display_stark_public_flow_4_step &ux_display_stark_public_flow_4_step);
);
#endif #endif

View File

@@ -4,56 +4,61 @@
#include "apdu_constants.h" #include "apdu_constants.h"
#include "ui_flow.h" #include "ui_flow.h"
void handleStarkwareProvideQuantum(uint8_t p1, uint8_t p2, uint8_t *dataBuffer, uint16_t dataLength, unsigned int *flags, unsigned int *tx) { void handleStarkwareProvideQuantum(uint8_t p1,
size_t i = 0; uint8_t p2,
uint8_t expectedDataSize = 20 + 32; uint8_t *dataBuffer,
uint8_t addressZero = 0; uint16_t dataLength,
tokenDefinition_t *currentToken = NULL; unsigned int *flags,
if (appState != APP_STATE_IDLE) { unsigned int *tx) {
reset_app_context(); size_t i = 0;
} uint8_t expectedDataSize = 20 + 32;
switch(p1) { uint8_t addressZero = 0;
case STARK_QUANTUM_LEGACY: tokenDefinition_t *currentToken = NULL;
break; if (appState != APP_STATE_IDLE) {
case STARK_QUANTUM_ETH: reset_app_context();
case STARK_QUANTUM_ERC20:
case STARK_QUANTUM_ERC721:
case STARK_QUANTUM_MINTABLE_ERC20:
case STARK_QUANTUM_MINTABLE_ERC721:
expectedDataSize += 32;
break;
default:
THROW(0x6B00);
}
if (dataLength != expectedDataSize) {
THROW(0x6700);
}
if (p1 == STARK_QUANTUM_LEGACY) {
addressZero = allzeroes(dataBuffer, 20);
}
if ((p1 != STARK_QUANTUM_ETH) && !addressZero) {
for(i=0; i<MAX_TOKEN; i++){
currentToken = &tmpCtx.transactionContext.tokens[i];
if (tmpCtx.transactionContext.tokenSet[i] && (memcmp(currentToken->address, dataBuffer, 20) == 0)) {
break;
}
} }
if (i == MAX_TOKEN) { switch (p1) {
PRINTF("Associated token not found\n"); case STARK_QUANTUM_LEGACY:
THROW(0x6A80); break;
case STARK_QUANTUM_ETH:
case STARK_QUANTUM_ERC20:
case STARK_QUANTUM_ERC721:
case STARK_QUANTUM_MINTABLE_ERC20:
case STARK_QUANTUM_MINTABLE_ERC721:
expectedDataSize += 32;
break;
default:
THROW(0x6B00);
} }
} if (dataLength != expectedDataSize) {
else { THROW(0x6700);
i = MAX_TOKEN; }
} if (p1 == STARK_QUANTUM_LEGACY) {
memmove(dataContext.tokenContext.quantum, dataBuffer + 20, 32); addressZero = allzeroes(dataBuffer, 20);
if (p1 != STARK_QUANTUM_LEGACY) { }
memmove(dataContext.tokenContext.mintingBlob, dataBuffer + 20 + 32, 32); if ((p1 != STARK_QUANTUM_ETH) && !addressZero) {
} for (i = 0; i < MAX_TOKEN; i++) {
dataContext.tokenContext.quantumIndex = i; currentToken = &tmpCtx.transactionContext.tokens[i];
dataContext.tokenContext.quantumType = p1; if (tmpCtx.transactionContext.tokenSet[i] &&
quantumSet = true; (memcmp(currentToken->address, dataBuffer, 20) == 0)) {
THROW(0x9000); break;
}
}
if (i == MAX_TOKEN) {
PRINTF("Associated token not found\n");
THROW(0x6A80);
}
} else {
i = MAX_TOKEN;
}
memmove(dataContext.tokenContext.quantum, dataBuffer + 20, 32);
if (p1 != STARK_QUANTUM_LEGACY) {
memmove(dataContext.tokenContext.mintingBlob, dataBuffer + 20 + 32, 32);
}
dataContext.tokenContext.quantumIndex = i;
dataContext.tokenContext.quantumType = p1;
quantumSet = true;
THROW(0x9000);
} }
#endif #endif

View File

@@ -7,208 +7,253 @@
#include "poorstream.h" #include "poorstream.h"
#include "ui_callbacks.h" #include "ui_callbacks.h"
#define U8BE(buf, off) (uint64_t)((((uint64_t)U4BE(buf, off)) << 32) | (((uint64_t)U4BE(buf, off + 4)) & 0xFFFFFFFF)) #define U8BE(buf, off) \
(uint64_t)((((uint64_t) U4BE(buf, off)) << 32) | (((uint64_t) U4BE(buf, off + 4)) & 0xFFFFFFFF))
#define TMP_OFFSET 140 #define TMP_OFFSET 140
void handleStarkwareSignMessage(uint8_t p1, uint8_t p2, uint8_t *dataBuffer, uint16_t dataLength, unsigned int *flags, unsigned int *tx) { void handleStarkwareSignMessage(uint8_t p1,
uint8_t privateKeyData[32]; uint8_t p2,
uint32_t i; uint8_t *dataBuffer,
uint8_t bip32PathLength = *(dataBuffer); uint16_t dataLength,
uint8_t offset = 1; unsigned int *flags,
cx_ecfp_private_key_t privateKey; unsigned int *tx) {
poorstream_t bitstream; uint8_t privateKeyData[32];
bool selfTransfer = false; uint32_t i;
uint8_t order = 1; uint8_t bip32PathLength = *(dataBuffer);
uint8_t protocol = 2; uint8_t offset = 1;
uint8_t preOffset, postOffset; cx_ecfp_private_key_t privateKey;
uint8_t zeroTest; poorstream_t bitstream;
// Initial checks bool selfTransfer = false;
if (appState != APP_STATE_IDLE) { uint8_t order = 1;
reset_app_context(); uint8_t protocol = 2;
} uint8_t preOffset, postOffset;
if ((bip32PathLength < 0x01) || uint8_t zeroTest;
(bip32PathLength > MAX_BIP32_PATH)) { // Initial checks
PRINTF("Invalid path\n"); if (appState != APP_STATE_IDLE) {
THROW(0x6a80); reset_app_context();
} }
switch(p1) { if ((bip32PathLength < 0x01) || (bip32PathLength > MAX_BIP32_PATH)) {
case P1_STARK_ORDER: PRINTF("Invalid path\n");
protocol = 1; THROW(0x6a80);
break; }
case P1_STARK_TRANSFER: switch (p1) {
protocol = 1; case P1_STARK_ORDER:
order = 0; protocol = 1;
break; break;
case P1_STARK_ORDER_V2: case P1_STARK_TRANSFER:
break; protocol = 1;
case P1_STARK_TRANSFER_V2: order = 0;
case P1_STARK_CONDITIONAL_TRANSFER: break;
order = 0; case P1_STARK_ORDER_V2:
break; break;
default: case P1_STARK_TRANSFER_V2:
THROW(0x6B00); case P1_STARK_CONDITIONAL_TRANSFER:
} order = 0;
postOffset = (protocol == 2 ? 1 + 32 : 0); break;
preOffset = (protocol == 2 ? 1 : 0); default:
if (order) { THROW(0x6B00);
if (dataLength != (20 + 32 + 20 + 32 + 4 + 4 + 8 + 8 + 4 + 4 + 1 + 4 * bip32PathLength + }
2 * postOffset)) { postOffset = (protocol == 2 ? 1 + 32 : 0);
THROW(0x6700); preOffset = (protocol == 2 ? 1 : 0);
if (order) {
if (dataLength != (20 + 32 + 20 + 32 + 4 + 4 + 8 + 8 + 4 + 4 + 1 + 4 * bip32PathLength +
2 * postOffset)) {
THROW(0x6700);
}
} else {
if (dataLength != (20 + 32 + 32 + 4 + 4 + 8 + 4 + 4 + 1 + 4 * bip32PathLength + postOffset +
(p1 == P1_STARK_CONDITIONAL_TRANSFER ? 32 + 20 : 0))) {
THROW(0x6700);
}
}
if (p2 != 0) {
THROW(0x6B00);
}
tmpCtx.transactionContext.pathLength = bip32PathLength;
for (i = 0; i < bip32PathLength; i++) {
tmpCtx.transactionContext.bip32Path[i] = U4BE(dataBuffer, offset);
PRINTF("Storing path %d %d\n", i, tmpCtx.transactionContext.bip32Path[i]);
offset += 4;
}
// Discard the path to use part of dataBuffer as a temporary buffer
memmove(dataBuffer, dataBuffer + offset, dataLength - offset);
dataContext.starkContext.conditional = (p1 == P1_STARK_CONDITIONAL_TRANSFER);
if (dataContext.starkContext.conditional) {
memmove(dataContext.starkContext.fact,
dataBuffer + 20 + 32 + postOffset + 32 + 4 + 4 + 8 + 4 + 4,
32);
memmove(dataContext.starkContext.conditionAddress,
dataBuffer + 20 + 32 + postOffset + 32 + 4 + 4 + 8 + 4 + 4 + 32,
20);
PRINTF("Fact %.*H\n", 32, dataContext.starkContext.fact);
PRINTF("Address %.*H\n", 20, dataContext.starkContext.conditionAddress);
} }
}
else {
if (dataLength != (20 + 32 + 32 + 4 + 4 + 8 + 4 + 4 + 1 + 4 * bip32PathLength +
postOffset + (p1 == P1_STARK_CONDITIONAL_TRANSFER ? 32 + 20 : 0))) {
THROW(0x6700);
}
}
if (p2 != 0) {
THROW(0x6B00);
}
tmpCtx.transactionContext.pathLength = bip32PathLength;
for (i = 0; i < bip32PathLength; i++) {
tmpCtx.transactionContext.bip32Path[i] = U4BE(dataBuffer, offset);
PRINTF("Storing path %d %d\n", i, tmpCtx.transactionContext.bip32Path[i]);
offset += 4;
}
// Discard the path to use part of dataBuffer as a temporary buffer
memmove(dataBuffer, dataBuffer + offset, dataLength - offset);
dataContext.starkContext.conditional = (p1 == P1_STARK_CONDITIONAL_TRANSFER);
if (dataContext.starkContext.conditional) {
memmove(dataContext.starkContext.fact, dataBuffer + 20 + 32 + postOffset + 32 + 4 + 4 + 8 + 4 + 4, 32);
memmove(dataContext.starkContext.conditionAddress, dataBuffer + 20 + 32 + postOffset + 32 + 4 + 4 + 8 + 4 + 4 + 32, 20);
PRINTF("Fact %.*H\n", 32, dataContext.starkContext.fact);
PRINTF("Address %.*H\n", 20, dataContext.starkContext.conditionAddress);
}
zeroTest = allzeroes(dataBuffer + preOffset, 20); zeroTest = allzeroes(dataBuffer + preOffset, 20);
if (zeroTest && (protocol == 2) && (dataBuffer[0] != STARK_QUANTUM_ETH)) { if (zeroTest && (protocol == 2) && (dataBuffer[0] != STARK_QUANTUM_ETH)) {
PRINTF("stark - unexpected quantum descriptor type for null first address %d\n", dataBuffer[0]); PRINTF("stark - unexpected quantum descriptor type for null first address %d\n",
THROW(0x6A80); dataBuffer[0]);
} THROW(0x6A80);
if (!zeroTest && getKnownToken(dataBuffer + preOffset) == NULL) {
PRINTF("stark - cannot process unknown token %.*H", 20, dataBuffer + preOffset);
THROW(0x6A80);
}
if (order) {
zeroTest = allzeroes(dataBuffer + 20 + 32 + postOffset + preOffset, 20);
if (zeroTest && (protocol == 2) && (dataBuffer[1 + 20 + 32 + 32] != STARK_QUANTUM_ETH)) {
PRINTF("stark - unexpected quantum descriptor type for null second address %d\n", dataBuffer[1 + 20 + 32 + 32]);
THROW(0x6A80);
} }
if (!zeroTest && getKnownToken(dataBuffer + 20 + 32 + postOffset + preOffset) == NULL) { if (!zeroTest && getKnownToken(dataBuffer + preOffset) == NULL) {
PRINTF("stark - cannot process unknown token %.*H", 20, dataBuffer + 20 + 32 + postOffset + preOffset); PRINTF("stark - cannot process unknown token %.*H", 20, dataBuffer + preOffset);
THROW(0x6A80); THROW(0x6A80);
} }
} if (order) {
// Prepare the Stark parameters zeroTest = allzeroes(dataBuffer + 20 + 32 + postOffset + preOffset, 20);
io_seproxyhal_io_heartbeat(); if (zeroTest && (protocol == 2) && (dataBuffer[1 + 20 + 32 + 32] != STARK_QUANTUM_ETH)) {
compute_token_id(&global_sha3, dataBuffer + preOffset, PRINTF("stark - unexpected quantum descriptor type for null second address %d\n",
(protocol == 2 ? dataBuffer[0] : STARK_QUANTUM_LEGACY), dataBuffer[1 + 20 + 32 + 32]);
dataBuffer + preOffset + 20, THROW(0x6A80);
(protocol == 2 ? dataBuffer + 1 + 20 + 32 : NULL), false, dataContext.starkContext.w1); }
if (order) { if (!zeroTest && getKnownToken(dataBuffer + 20 + 32 + postOffset + preOffset) == NULL) {
PRINTF("stark - cannot process unknown token %.*H",
20,
dataBuffer + 20 + 32 + postOffset + preOffset);
THROW(0x6A80);
}
}
// Prepare the Stark parameters
io_seproxyhal_io_heartbeat(); io_seproxyhal_io_heartbeat();
compute_token_id(&global_sha3, dataBuffer + 20 + 32 + postOffset + preOffset, compute_token_id(&global_sha3,
(protocol == 2 ? dataBuffer[1 + 20 + 32 + 32] : STARK_QUANTUM_LEGACY), dataBuffer + preOffset,
dataBuffer + 20 + 32 + postOffset + preOffset + 20, (protocol == 2 ? dataBuffer[0] : STARK_QUANTUM_LEGACY),
(protocol == 2 ? dataBuffer + 1 + 20 + 32 + 32 + 1 + 20 + 32 : NULL), false, dataContext.starkContext.w2); dataBuffer + preOffset + 20,
offset = 20 + 32 + postOffset + 20 + 32 + postOffset; (protocol == 2 ? dataBuffer + 1 + 20 + 32 : NULL),
} false,
else { dataContext.starkContext.w1);
memmove(dataContext.starkContext.w2, dataBuffer + 20 + 32 + postOffset, 32); if (order) {
offset = 20 + 32 + postOffset + 32; io_seproxyhal_io_heartbeat();
} compute_token_id(&global_sha3,
dataBuffer + 20 + 32 + postOffset + preOffset,
(protocol == 2 ? dataBuffer[1 + 20 + 32 + 32] : STARK_QUANTUM_LEGACY),
dataBuffer + 20 + 32 + postOffset + preOffset + 20,
(protocol == 2 ? dataBuffer + 1 + 20 + 32 + 32 + 1 + 20 + 32 : NULL),
false,
dataContext.starkContext.w2);
offset = 20 + 32 + postOffset + 20 + 32 + postOffset;
} else {
memmove(dataContext.starkContext.w2, dataBuffer + 20 + 32 + postOffset, 32);
offset = 20 + 32 + postOffset + 32;
}
poorstream_init(&bitstream, dataContext.starkContext.w3); poorstream_init(&bitstream, dataContext.starkContext.w3);
poorstream_write_bits(&bitstream, 0, 11); // padding poorstream_write_bits(&bitstream, 0, 11); // padding
poorstream_write_bits(&bitstream, poorstream_write_bits(
(p1 == P1_STARK_CONDITIONAL_TRANSFER ? STARK_CONDITIONAL_TRANSFER_TYPE : &bitstream,
order ? STARK_ORDER_TYPE : STARK_TRANSFER_TYPE), 4); (p1 == P1_STARK_CONDITIONAL_TRANSFER ? STARK_CONDITIONAL_TRANSFER_TYPE
poorstream_write_bits(&bitstream, U4BE(dataBuffer, offset), 31); : order ? STARK_ORDER_TYPE : STARK_TRANSFER_TYPE),
poorstream_write_bits(&bitstream, U4BE(dataBuffer, offset + 4), 31); 4);
poorstream_write_bits(&bitstream, U8BE(dataBuffer, offset + 4 + 4), 63); poorstream_write_bits(&bitstream, U4BE(dataBuffer, offset), 31);
if (order) { poorstream_write_bits(&bitstream, U4BE(dataBuffer, offset + 4), 31);
poorstream_write_bits(&bitstream, U8BE(dataBuffer, offset + 4 + 4 + 8), 63); poorstream_write_bits(&bitstream, U8BE(dataBuffer, offset + 4 + 4), 63);
offset += 4 + 4 + 8 + 8; if (order) {
} poorstream_write_bits(&bitstream, U8BE(dataBuffer, offset + 4 + 4 + 8), 63);
else { offset += 4 + 4 + 8 + 8;
poorstream_write_bits(&bitstream, 0, 63); } else {
offset += 4 + 4 + 8; poorstream_write_bits(&bitstream, 0, 63);
} offset += 4 + 4 + 8;
poorstream_write_bits(&bitstream, U4BE(dataBuffer, offset), 31);
poorstream_write_bits(&bitstream, U4BE(dataBuffer, offset + 4), 22);
PRINTF("stark w1 %.*H\n", 32, dataContext.starkContext.w1);
PRINTF("stark w2 %.*H\n", 32, dataContext.starkContext.w2);
PRINTF("stark w3 %.*H\n", 32, dataContext.starkContext.w3);
if (dataContext.starkContext.conditional) {
cx_keccak_init(&global_sha3, 256);
cx_hash((cx_hash_t*)&global_sha3, 0, dataContext.starkContext.conditionAddress, 20, NULL, 0);
cx_hash((cx_hash_t*)&global_sha3, CX_LAST, dataContext.starkContext.fact, 32, dataContext.starkContext.w4, 32);
dataContext.starkContext.w4[0] &= 0x03;
PRINTF("stark w4 %.*H\n", 32, dataContext.starkContext.w4);
}
// Prepare the UI
if (order) {
io_seproxyhal_io_heartbeat();
// amount to sell
stark_get_amount_string(dataBuffer + preOffset,
dataBuffer + preOffset + 20,
dataBuffer + 20 + 32 + postOffset + 20 + 32 + postOffset + 4 + 4,
(char*)(dataBuffer + TMP_OFFSET), strings.common.fullAmount);
io_seproxyhal_io_heartbeat();
// amount to buy
stark_get_amount_string(dataBuffer + 20 + 32 + postOffset + preOffset,
dataBuffer + 20 + 32 + postOffset + preOffset + 20,
dataBuffer + 20 + 32 + postOffset + 20 + 32 + postOffset + 4 + 4 + 8,
(char*)(dataBuffer + TMP_OFFSET), strings.common.maxFee);
// src vault ID
snprintf(strings.common.fullAddress, sizeof(strings.common.fullAddress), "%d",
U4BE(dataBuffer, 20 + 32 + postOffset + 20 + 32 + postOffset));
}
else {
cx_ecfp_public_key_t publicKey;
// Check if the transfer is a self transfer
io_seproxyhal_io_heartbeat();
starkDerivePrivateKey(tmpCtx.transactionContext.bip32Path, bip32PathLength, privateKeyData);
cx_ecfp_init_private_key(CX_CURVE_Stark256, privateKeyData, 32, &privateKey);
io_seproxyhal_io_heartbeat();
cx_ecfp_generate_pair(CX_CURVE_Stark256, &publicKey, &privateKey, 1);
explicit_bzero(&privateKey, sizeof(privateKey));
explicit_bzero(privateKeyData, sizeof(privateKeyData));
io_seproxyhal_io_heartbeat();
selfTransfer = (memcmp(publicKey.W + 1, dataBuffer + 20 + 32 + postOffset, 32) == 0);
PRINTF("self transfer %d\n", selfTransfer);
io_seproxyhal_io_heartbeat();
// amount to transfer
stark_get_amount_string(dataBuffer + preOffset,
dataBuffer + preOffset + 20,
dataBuffer + 20 + 32 + postOffset + 32 + 4 + 4, (char*)(dataBuffer + TMP_OFFSET), tmpContent.tmp);
// dest vault ID
snprintf(strings.tmp.tmp2, sizeof(strings.tmp.tmp2), "%d",
U4BE(dataBuffer, 20 + 32 + postOffset + 32 + 4));
if (!selfTransfer) {
memmove(dataContext.starkContext.transferDestination, dataBuffer + 20 + 32 + postOffset, 32);
snprintf(strings.tmp.tmp, sizeof(strings.tmp.tmp), "0x%.*H", 32, dataBuffer + 20 + 32 + postOffset);
} }
} poorstream_write_bits(&bitstream, U4BE(dataBuffer, offset), 31);
if (order) { poorstream_write_bits(&bitstream, U4BE(dataBuffer, offset + 4), 22);
ux_flow_init(0, ux_stark_limit_order_flow, NULL);
}
else {
if (selfTransfer) {
ux_flow_init(0, (dataContext.starkContext.conditional ? ux_stark_self_transfer_conditional_flow :
ux_stark_self_transfer_flow), NULL);
}
else {
ux_flow_init(0, (dataContext.starkContext.conditional ? ux_stark_transfer_conditional_flow :
ux_stark_transfer_flow), NULL);
}
}
*flags |= IO_ASYNCH_REPLY; PRINTF("stark w1 %.*H\n", 32, dataContext.starkContext.w1);
PRINTF("stark w2 %.*H\n", 32, dataContext.starkContext.w2);
PRINTF("stark w3 %.*H\n", 32, dataContext.starkContext.w3);
if (dataContext.starkContext.conditional) {
cx_keccak_init(&global_sha3, 256);
cx_hash((cx_hash_t *) &global_sha3,
0,
dataContext.starkContext.conditionAddress,
20,
NULL,
0);
cx_hash((cx_hash_t *) &global_sha3,
CX_LAST,
dataContext.starkContext.fact,
32,
dataContext.starkContext.w4,
32);
dataContext.starkContext.w4[0] &= 0x03;
PRINTF("stark w4 %.*H\n", 32, dataContext.starkContext.w4);
}
// Prepare the UI
if (order) {
io_seproxyhal_io_heartbeat();
// amount to sell
stark_get_amount_string(dataBuffer + preOffset,
dataBuffer + preOffset + 20,
dataBuffer + 20 + 32 + postOffset + 20 + 32 + postOffset + 4 + 4,
(char *) (dataBuffer + TMP_OFFSET),
strings.common.fullAmount);
io_seproxyhal_io_heartbeat();
// amount to buy
stark_get_amount_string(
dataBuffer + 20 + 32 + postOffset + preOffset,
dataBuffer + 20 + 32 + postOffset + preOffset + 20,
dataBuffer + 20 + 32 + postOffset + 20 + 32 + postOffset + 4 + 4 + 8,
(char *) (dataBuffer + TMP_OFFSET),
strings.common.maxFee);
// src vault ID
snprintf(strings.common.fullAddress,
sizeof(strings.common.fullAddress),
"%d",
U4BE(dataBuffer, 20 + 32 + postOffset + 20 + 32 + postOffset));
} else {
cx_ecfp_public_key_t publicKey;
// Check if the transfer is a self transfer
io_seproxyhal_io_heartbeat();
starkDerivePrivateKey(tmpCtx.transactionContext.bip32Path, bip32PathLength, privateKeyData);
cx_ecfp_init_private_key(CX_CURVE_Stark256, privateKeyData, 32, &privateKey);
io_seproxyhal_io_heartbeat();
cx_ecfp_generate_pair(CX_CURVE_Stark256, &publicKey, &privateKey, 1);
explicit_bzero(&privateKey, sizeof(privateKey));
explicit_bzero(privateKeyData, sizeof(privateKeyData));
io_seproxyhal_io_heartbeat();
selfTransfer = (memcmp(publicKey.W + 1, dataBuffer + 20 + 32 + postOffset, 32) == 0);
PRINTF("self transfer %d\n", selfTransfer);
io_seproxyhal_io_heartbeat();
// amount to transfer
stark_get_amount_string(dataBuffer + preOffset,
dataBuffer + preOffset + 20,
dataBuffer + 20 + 32 + postOffset + 32 + 4 + 4,
(char *) (dataBuffer + TMP_OFFSET),
tmpContent.tmp);
// dest vault ID
snprintf(strings.tmp.tmp2,
sizeof(strings.tmp.tmp2),
"%d",
U4BE(dataBuffer, 20 + 32 + postOffset + 32 + 4));
if (!selfTransfer) {
memmove(dataContext.starkContext.transferDestination,
dataBuffer + 20 + 32 + postOffset,
32);
snprintf(strings.tmp.tmp,
sizeof(strings.tmp.tmp),
"0x%.*H",
32,
dataBuffer + 20 + 32 + postOffset);
}
}
if (order) {
ux_flow_init(0, ux_stark_limit_order_flow, NULL);
} else {
if (selfTransfer) {
ux_flow_init(
0,
(dataContext.starkContext.conditional ? ux_stark_self_transfer_conditional_flow
: ux_stark_self_transfer_flow),
NULL);
} else {
ux_flow_init(0,
(dataContext.starkContext.conditional ? ux_stark_transfer_conditional_flow
: ux_stark_transfer_flow),
NULL);
}
}
*flags |= IO_ASYNCH_REPLY;
} }
#endif #endif

View File

@@ -9,12 +9,17 @@ unsigned int io_seproxyhal_touch_stark_ok(const bagl_element_t *e) {
uint8_t signature[72]; uint8_t signature[72];
uint32_t tx = 0; uint32_t tx = 0;
io_seproxyhal_io_heartbeat(); io_seproxyhal_io_heartbeat();
starkDerivePrivateKey(tmpCtx.transactionContext.bip32Path, tmpCtx.transactionContext.pathLength, privateKeyData); starkDerivePrivateKey(tmpCtx.transactionContext.bip32Path,
tmpCtx.transactionContext.pathLength,
privateKeyData);
io_seproxyhal_io_heartbeat(); io_seproxyhal_io_heartbeat();
stark_sign(signature, privateKeyData, dataContext.starkContext.w1, dataContext.starkContext.w2, stark_sign(signature,
dataContext.starkContext.w3, privateKeyData,
(dataContext.starkContext.conditional ? dataContext.starkContext.w4 : NULL)); dataContext.starkContext.w1,
G_io_apdu_buffer[0] = 0; dataContext.starkContext.w2,
dataContext.starkContext.w3,
(dataContext.starkContext.conditional ? dataContext.starkContext.w4 : NULL));
G_io_apdu_buffer[0] = 0;
format_signature_out(signature); format_signature_out(signature);
tx = 65; tx = 65;
G_io_apdu_buffer[tx++] = 0x90; G_io_apdu_buffer[tx++] = 0x90;
@@ -24,7 +29,7 @@ unsigned int io_seproxyhal_touch_stark_ok(const bagl_element_t *e) {
io_exchange(CHANNEL_APDU | IO_RETURN_AFTER_TX, tx); io_exchange(CHANNEL_APDU | IO_RETURN_AFTER_TX, tx);
// Display back the original UX // Display back the original UX
ui_idle(); ui_idle();
return 0; // do not redraw the widget return 0; // do not redraw the widget
} }
#endif #endif

View File

@@ -6,20 +6,28 @@
unsigned int io_seproxyhal_touch_stark_ok(const bagl_element_t *e); unsigned int io_seproxyhal_touch_stark_ok(const bagl_element_t *e);
void stark_sign_display_master_account() { void stark_sign_display_master_account() {
snprintf(strings.tmp.tmp, sizeof(strings.tmp.tmp), "0x%.*H", 32, dataContext.starkContext.transferDestination); snprintf(strings.tmp.tmp,
sizeof(strings.tmp.tmp),
"0x%.*H",
32,
dataContext.starkContext.transferDestination);
} }
void stark_sign_display_condition_address() { void stark_sign_display_condition_address() {
strings.tmp.tmp[0] = '0'; strings.tmp.tmp[0] = '0';
strings.tmp.tmp[1] = 'x'; strings.tmp.tmp[1] = 'x';
getEthAddressStringFromBinary(dataContext.starkContext.conditionAddress, (uint8_t*)(strings.tmp.tmp + 2), &global_sha3, chainConfig); getEthAddressStringFromBinary(dataContext.starkContext.conditionAddress,
strings.tmp.tmp[42] = '\0'; (uint8_t *) (strings.tmp.tmp + 2),
&global_sha3,
chainConfig);
strings.tmp.tmp[42] = '\0';
} }
void stark_sign_display_condition_fact() { void stark_sign_display_condition_fact() {
snprintf(strings.tmp.tmp, sizeof(strings.tmp.tmp), "0x%.*H", 32, dataContext.starkContext.fact); snprintf(strings.tmp.tmp, sizeof(strings.tmp.tmp), "0x%.*H", 32, dataContext.starkContext.fact);
} }
// clang-format off
UX_STEP_NOCB(ux_stark_limit_order_1_step, UX_STEP_NOCB(ux_stark_limit_order_1_step,
pnn, pnn,
{ {
@@ -80,19 +88,20 @@ UX_STEP_CB(
&C_icon_crossmark, &C_icon_crossmark,
"Reject", "Reject",
}); });
// clang-format on
UX_FLOW(ux_stark_limit_order_flow, UX_FLOW(ux_stark_limit_order_flow,
&ux_stark_limit_order_1_step, &ux_stark_limit_order_1_step,
&ux_stark_limit_order_2_step, &ux_stark_limit_order_2_step,
&ux_stark_limit_order_3_step, &ux_stark_limit_order_3_step,
&ux_stark_limit_order_4_step, &ux_stark_limit_order_4_step,
&ux_stark_limit_order_5_step, &ux_stark_limit_order_5_step,
&ux_stark_limit_order_6_step, &ux_stark_limit_order_6_step,
&ux_stark_limit_order_7_step, &ux_stark_limit_order_7_step,
&ux_stark_limit_order_8_step &ux_stark_limit_order_8_step);
);
////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////
// clang-format off
UX_STEP_NOCB(ux_stark_transfer_1_step, UX_STEP_NOCB(ux_stark_transfer_1_step,
pnn, pnn,
{ {
@@ -194,47 +203,44 @@ UX_STEP_NOCB_INIT(
.title = "Cond. Fact", .title = "Cond. Fact",
.text = strings.tmp.tmp .text = strings.tmp.tmp
}); });
// clang-format on
UX_FLOW(ux_stark_transfer_flow, UX_FLOW(ux_stark_transfer_flow,
&ux_stark_transfer_1_step, &ux_stark_transfer_1_step,
&ux_stark_transfer_2_step, &ux_stark_transfer_2_step,
&ux_stark_transfer_3_step, &ux_stark_transfer_3_step,
&ux_stark_transfer_4_step, &ux_stark_transfer_4_step,
&ux_stark_transfer_5_step, &ux_stark_transfer_5_step,
&ux_stark_transfer_6_step, &ux_stark_transfer_6_step,
&ux_stark_transfer_7_step &ux_stark_transfer_7_step);
);
UX_FLOW(ux_stark_self_transfer_flow, UX_FLOW(ux_stark_self_transfer_flow,
&ux_stark_transfer_1_step, &ux_stark_transfer_1_step,
&ux_stark_self_transfer_2_step, &ux_stark_self_transfer_2_step,
&ux_stark_transfer_3_step, &ux_stark_transfer_3_step,
&ux_stark_transfer_5_step, &ux_stark_transfer_5_step,
&ux_stark_transfer_6_step, &ux_stark_transfer_6_step,
&ux_stark_transfer_7_step &ux_stark_transfer_7_step);
);
UX_FLOW(ux_stark_transfer_conditional_flow, UX_FLOW(ux_stark_transfer_conditional_flow,
&ux_stark_transfer_1_step, &ux_stark_transfer_1_step,
&ux_stark_conditional_transfer_2_step, &ux_stark_conditional_transfer_2_step,
&ux_stark_transfer_3_step, &ux_stark_transfer_3_step,
&ux_stark_conditional_transfer_4_step, &ux_stark_conditional_transfer_4_step,
&ux_stark_transfer_5_step, &ux_stark_transfer_5_step,
&ux_stark_conditional_transfer_8_step, &ux_stark_conditional_transfer_8_step,
&ux_stark_conditional_transfer_9_step, &ux_stark_conditional_transfer_9_step,
&ux_stark_transfer_6_step, &ux_stark_transfer_6_step,
&ux_stark_transfer_7_step &ux_stark_transfer_7_step);
);
UX_FLOW(ux_stark_self_transfer_conditional_flow, UX_FLOW(ux_stark_self_transfer_conditional_flow,
&ux_stark_transfer_1_step, &ux_stark_transfer_1_step,
&ux_stark_self_conditional_transfer_2_step, &ux_stark_self_conditional_transfer_2_step,
&ux_stark_transfer_3_step, &ux_stark_transfer_3_step,
&ux_stark_transfer_5_step, &ux_stark_transfer_5_step,
&ux_stark_conditional_transfer_8_step, &ux_stark_conditional_transfer_8_step,
&ux_stark_conditional_transfer_9_step, &ux_stark_conditional_transfer_9_step,
&ux_stark_transfer_6_step, &ux_stark_transfer_6_step,
&ux_stark_transfer_7_step &ux_stark_transfer_7_step);
);
#endif #endif

View File

@@ -6,49 +6,53 @@
#include "ui_flow.h" #include "ui_flow.h"
#include "ui_callbacks.h" #include "ui_callbacks.h"
void handleStarkwareUnsafeSign(uint8_t p1, uint8_t p2, uint8_t *dataBuffer, uint16_t dataLength, unsigned int *flags, unsigned int *tx) { void handleStarkwareUnsafeSign(uint8_t p1,
uint32_t i; uint8_t p2,
uint8_t privateKeyData[32]; uint8_t *dataBuffer,
cx_ecfp_public_key_t publicKey; uint16_t dataLength,
cx_ecfp_private_key_t privateKey; unsigned int *flags,
uint8_t bip32PathLength = *(dataBuffer); unsigned int *tx) {
uint8_t offset = 1; uint32_t i;
// Initial checks uint8_t privateKeyData[32];
if (appState != APP_STATE_IDLE) { cx_ecfp_public_key_t publicKey;
reset_app_context(); cx_ecfp_private_key_t privateKey;
} uint8_t bip32PathLength = *(dataBuffer);
if ((bip32PathLength < 0x01) || uint8_t offset = 1;
(bip32PathLength > MAX_BIP32_PATH)) { // Initial checks
PRINTF("Invalid path\n"); if (appState != APP_STATE_IDLE) {
THROW(0x6a80); reset_app_context();
} }
if ((p1 != 0) || (p2 != 0)) { if ((bip32PathLength < 0x01) || (bip32PathLength > MAX_BIP32_PATH)) {
THROW(0x6B00); PRINTF("Invalid path\n");
} THROW(0x6a80);
}
if ((p1 != 0) || (p2 != 0)) {
THROW(0x6B00);
}
if (dataLength != 32 + 4 * bip32PathLength + 1) { if (dataLength != 32 + 4 * bip32PathLength + 1) {
THROW(0x6700); THROW(0x6700);
} }
tmpCtx.transactionContext.pathLength = bip32PathLength; tmpCtx.transactionContext.pathLength = bip32PathLength;
for (i = 0; i < bip32PathLength; i++) { for (i = 0; i < bip32PathLength; i++) {
tmpCtx.transactionContext.bip32Path[i] = U4BE(dataBuffer, offset); tmpCtx.transactionContext.bip32Path[i] = U4BE(dataBuffer, offset);
PRINTF("Storing path %d %d\n", i, tmpCtx.transactionContext.bip32Path[i]); PRINTF("Storing path %d %d\n", i, tmpCtx.transactionContext.bip32Path[i]);
offset += 4; offset += 4;
} }
memmove(dataContext.starkContext.w2, dataBuffer + offset, 32); memmove(dataContext.starkContext.w2, dataBuffer + offset, 32);
io_seproxyhal_io_heartbeat(); io_seproxyhal_io_heartbeat();
starkDerivePrivateKey(tmpCtx.transactionContext.bip32Path, bip32PathLength, privateKeyData); starkDerivePrivateKey(tmpCtx.transactionContext.bip32Path, bip32PathLength, privateKeyData);
cx_ecfp_init_private_key(CX_CURVE_Stark256, privateKeyData, 32, &privateKey); cx_ecfp_init_private_key(CX_CURVE_Stark256, privateKeyData, 32, &privateKey);
io_seproxyhal_io_heartbeat(); io_seproxyhal_io_heartbeat();
cx_ecfp_generate_pair(CX_CURVE_Stark256, &publicKey, &privateKey, 1); cx_ecfp_generate_pair(CX_CURVE_Stark256, &publicKey, &privateKey, 1);
explicit_bzero(&privateKey, sizeof(privateKey)); explicit_bzero(&privateKey, sizeof(privateKey));
explicit_bzero(privateKeyData, sizeof(privateKeyData)); explicit_bzero(privateKeyData, sizeof(privateKeyData));
io_seproxyhal_io_heartbeat(); io_seproxyhal_io_heartbeat();
memmove(dataContext.starkContext.w1, publicKey.W + 1, 32); memmove(dataContext.starkContext.w1, publicKey.W + 1, 32);
ux_flow_init(0, ux_stark_unsafe_sign_flow, NULL); ux_flow_init(0, ux_stark_unsafe_sign_flow, NULL);
*flags |= IO_ASYNCH_REPLY; *flags |= IO_ASYNCH_REPLY;
} }
#endif #endif

View File

@@ -11,11 +11,19 @@ unsigned int io_seproxyhal_touch_stark_unsafe_sign_ok(const bagl_element_t *e) {
unsigned int info = 0; unsigned int info = 0;
uint32_t tx = 0; uint32_t tx = 0;
io_seproxyhal_io_heartbeat(); io_seproxyhal_io_heartbeat();
starkDerivePrivateKey(tmpCtx.transactionContext.bip32Path, tmpCtx.transactionContext.pathLength, privateKeyData); starkDerivePrivateKey(tmpCtx.transactionContext.bip32Path,
tmpCtx.transactionContext.pathLength,
privateKeyData);
io_seproxyhal_io_heartbeat(); io_seproxyhal_io_heartbeat();
cx_ecfp_init_private_key(CX_CURVE_Stark256, privateKeyData, 32, &privateKey); cx_ecfp_init_private_key(CX_CURVE_Stark256, privateKeyData, 32, &privateKey);
cx_ecdsa_sign(&privateKey, CX_RND_RFC6979 | CX_LAST, CX_SHA256, cx_ecdsa_sign(&privateKey,
dataContext.starkContext.w2, sizeof(dataContext.starkContext.w2), signature, sizeof(signature), &info); CX_RND_RFC6979 | CX_LAST,
CX_SHA256,
dataContext.starkContext.w2,
sizeof(dataContext.starkContext.w2),
signature,
sizeof(signature),
&info);
G_io_apdu_buffer[0] = 0; G_io_apdu_buffer[0] = 0;
format_signature_out(signature); format_signature_out(signature);
tx = 65; tx = 65;
@@ -26,7 +34,7 @@ unsigned int io_seproxyhal_touch_stark_unsafe_sign_ok(const bagl_element_t *e) {
io_exchange(CHANNEL_APDU | IO_RETURN_AFTER_TX, tx); io_exchange(CHANNEL_APDU | IO_RETURN_AFTER_TX, tx);
// Display back the original UX // Display back the original UX
ui_idle(); ui_idle();
return 0; // do not redraw the widget return 0; // do not redraw the widget
} }
#endif #endif

View File

@@ -6,13 +6,14 @@
unsigned int io_seproxyhal_touch_stark_unsafe_sign_ok(const bagl_element_t *e); unsigned int io_seproxyhal_touch_stark_unsafe_sign_ok(const bagl_element_t *e);
void stark_unsafe_sign_display_account() { void stark_unsafe_sign_display_account() {
snprintf(strings.tmp.tmp, sizeof(strings.tmp.tmp), "0x%.*H", 32, dataContext.starkContext.w1); snprintf(strings.tmp.tmp, sizeof(strings.tmp.tmp), "0x%.*H", 32, dataContext.starkContext.w1);
} }
void stark_unsafe_sign_display_hash() { void stark_unsafe_sign_display_hash() {
snprintf(strings.tmp.tmp, sizeof(strings.tmp.tmp), "0x%.*H", 32, dataContext.starkContext.w2); snprintf(strings.tmp.tmp, sizeof(strings.tmp.tmp), "0x%.*H", 32, dataContext.starkContext.w2);
} }
// clang-format off
UX_STEP_NOCB(ux_stark_unsafe_sign_1_step, UX_STEP_NOCB(ux_stark_unsafe_sign_1_step,
pnn, pnn,
{ {
@@ -57,13 +58,13 @@ UX_STEP_CB(
&C_icon_crossmark, &C_icon_crossmark,
"Reject", "Reject",
}); });
// clang-format on
UX_FLOW(ux_stark_unsafe_sign_flow, UX_FLOW(ux_stark_unsafe_sign_flow,
&ux_stark_unsafe_sign_1_step, &ux_stark_unsafe_sign_1_step,
&ux_stark_unsafe_sign_2_step, &ux_stark_unsafe_sign_2_step,
&ux_stark_unsafe_sign_3_step, &ux_stark_unsafe_sign_3_step,
&ux_stark_unsafe_sign_4_step, &ux_stark_unsafe_sign_4_step,
&ux_stark_unsafe_sign_5_step &ux_stark_unsafe_sign_5_step);
);
#endif #endif

View File

@@ -1,7 +1,7 @@
#include <string.h> #include <string.h>
#include "eth_plugin_interface.h" #include "eth_plugin_interface.h"
#include "shared_context.h" // TODO : rewrite as independant code #include "shared_context.h" // TODO : rewrite as independant code
#include "eth_plugin_internal.h" // TODO : rewrite as independant code #include "eth_plugin_internal.h" // TODO : rewrite as independant code
#include "utils.h" #include "utils.h"
typedef enum { typedef enum {
@@ -39,11 +39,9 @@ typedef struct underlying_asset_decimals_t {
uint8_t decimals; uint8_t decimals;
} underlying_asset_decimals_t; } underlying_asset_decimals_t;
/* Sadly, we don't have the information about the underlying asset's decimals, which can differ from
the cToken decimals. Therefore, we hardcode a binding table. If Compound adds a lot of token in the
/* Sadly, we don't have the information about the underlying asset's decimals, which can differ from the cToken decimals. future, we will have to move to a CAL based architecture instead, as this one doesn't scale well.*/
Therefore, we hardcode a binding table. If Compound adds a lot of token in the future, we will have to move to a CAL
based architecture instead, as this one doesn't scale well.*/
#define NUM_COMPOUND_BINDINGS 9 #define NUM_COMPOUND_BINDINGS 9
const underlying_asset_decimals_t const UNDERLYING_ASSET_DECIMALS[NUM_COMPOUND_BINDINGS] = { const underlying_asset_decimals_t const UNDERLYING_ASSET_DECIMALS[NUM_COMPOUND_BINDINGS] = {
{"cDAI", 18}, {"cDAI", 18},
@@ -57,10 +55,13 @@ const underlying_asset_decimals_t const UNDERLYING_ASSET_DECIMALS[NUM_COMPOUND_B
{"cSAI", 18}, {"cSAI", 18},
}; };
bool get_underlying_asset_decimals(char* compound_ticker, uint8_t* out_decimals){ bool get_underlying_asset_decimals(char *compound_ticker, uint8_t *out_decimals) {
for(size_t i = 0; i < NUM_COMPOUND_BINDINGS; i++){ for (size_t i = 0; i < NUM_COMPOUND_BINDINGS; i++) {
underlying_asset_decimals_t* binding = (underlying_asset_decimals_t *)PIC(&UNDERLYING_ASSET_DECIMALS[i]); underlying_asset_decimals_t *binding =
if (strncmp(binding->c_ticker, compound_ticker, strnlen(binding->c_ticker, MAX_TICKER_LEN)) == 0){ (underlying_asset_decimals_t *) PIC(&UNDERLYING_ASSET_DECIMALS[i]);
if (strncmp(binding->c_ticker,
compound_ticker,
strnlen(binding->c_ticker, MAX_TICKER_LEN)) == 0) {
*out_decimals = binding->decimals; *out_decimals = binding->decimals;
return true; return true;
} }
@@ -69,21 +70,21 @@ bool get_underlying_asset_decimals(char* compound_ticker, uint8_t* out_decimals)
} }
void compound_plugin_call(int message, void *parameters) { void compound_plugin_call(int message, void *parameters) {
switch (message) {
switch(message) {
case ETH_PLUGIN_INIT_CONTRACT: { case ETH_PLUGIN_INIT_CONTRACT: {
ethPluginInitContract_t *msg = (ethPluginInitContract_t*)parameters; ethPluginInitContract_t *msg = (ethPluginInitContract_t *) parameters;
compound_parameters_t *context = (compound_parameters_t*)msg->pluginContext; compound_parameters_t *context = (compound_parameters_t *) msg->pluginContext;
size_t i; size_t i;
for (i=0; i<NUM_COMPOUND_SELECTORS; i++) { for (i = 0; i < NUM_COMPOUND_SELECTORS; i++) {
if (memcmp((uint8_t *)PIC(COMPOUND_SELECTORS[i]), msg->selector, SELECTOR_SIZE) == 0) { if (memcmp((uint8_t *) PIC(COMPOUND_SELECTORS[i]), msg->selector, SELECTOR_SIZE) ==
0) {
context->selectorIndex = i; context->selectorIndex = i;
break; break;
} }
} }
// enforce that ETH amount should be 0, except in ceth.mint case // enforce that ETH amount should be 0, except in ceth.mint case
if (!allzeroes(msg->pluginSharedRO->txContent->value.value, 32)){ if (!allzeroes(msg->pluginSharedRO->txContent->value.value, 32)) {
if(context->selectorIndex != CETH_MINT){ if (context->selectorIndex != CETH_MINT) {
msg->result = ETH_PLUGIN_RESULT_ERROR; msg->result = ETH_PLUGIN_RESULT_ERROR;
break; break;
} }
@@ -94,27 +95,35 @@ void compound_plugin_call(int message, void *parameters) {
break; break;
} }
if (msg->dataSize != COMPOUND_EXPECTED_DATA_SIZE[context->selectorIndex]) { if (msg->dataSize != COMPOUND_EXPECTED_DATA_SIZE[context->selectorIndex]) {
PRINTF("Unexpected data size for command %d expected %d got %d\n", context->selectorIndex, PRINTF("Unexpected data size for command %d expected %d got %d\n",
COMPOUND_EXPECTED_DATA_SIZE[context->selectorIndex], msg->dataSize); context->selectorIndex,
COMPOUND_EXPECTED_DATA_SIZE[context->selectorIndex],
msg->dataSize);
msg->result = ETH_PLUGIN_RESULT_ERROR; msg->result = ETH_PLUGIN_RESULT_ERROR;
break; break;
} }
if(context->selectorIndex == CETH_MINT){ if (context->selectorIndex == CETH_MINT) {
// ETH amount 0x1234 is stored 0x12340000...000 instead of 0x00....001234, so we strip the following zeroes when copying // ETH amount 0x1234 is stored 0x12340000...000 instead of 0x00....001234, so we
// strip the following zeroes when copying
memset(context->amount, 0, sizeof(context->amount)); memset(context->amount, 0, sizeof(context->amount));
memmove(context->amount + sizeof(context->amount) - msg->pluginSharedRO->txContent->value.length, msg->pluginSharedRO->txContent->value.value, msg->pluginSharedRO->txContent->value.length); memmove(context->amount + sizeof(context->amount) -
msg->pluginSharedRO->txContent->value.length,
msg->pluginSharedRO->txContent->value.value,
msg->pluginSharedRO->txContent->value.length);
} }
PRINTF("compound plugin inititialized\n"); PRINTF("compound plugin inititialized\n");
msg->result = ETH_PLUGIN_RESULT_OK; msg->result = ETH_PLUGIN_RESULT_OK;
} } break;
break;
case ETH_PLUGIN_PROVIDE_PARAMETER : { case ETH_PLUGIN_PROVIDE_PARAMETER: {
ethPluginProvideParameter_t *msg = (ethPluginProvideParameter_t*)parameters; ethPluginProvideParameter_t *msg = (ethPluginProvideParameter_t *) parameters;
compound_parameters_t *context = (compound_parameters_t*)msg->pluginContext; compound_parameters_t *context = (compound_parameters_t *) msg->pluginContext;
PRINTF("compound plugin provide parameter %d %.*H\n", msg->parameterOffset, 32, msg->parameter); PRINTF("compound plugin provide parameter %d %.*H\n",
if (context->selectorIndex != CETH_MINT){ msg->parameterOffset,
switch(msg->parameterOffset) { 32,
msg->parameter);
if (context->selectorIndex != CETH_MINT) {
switch (msg->parameterOffset) {
case 4: case 4:
memmove(context->amount, msg->parameter, 32); memmove(context->amount, msg->parameter, 32);
msg->result = ETH_PLUGIN_RESULT_OK; msg->result = ETH_PLUGIN_RESULT_OK;
@@ -124,36 +133,35 @@ void compound_plugin_call(int message, void *parameters) {
msg->result = ETH_PLUGIN_RESULT_ERROR; msg->result = ETH_PLUGIN_RESULT_ERROR;
break; break;
} }
} } else {
else {
PRINTF("CETH contract expects no parameters\n"); PRINTF("CETH contract expects no parameters\n");
msg->result = ETH_PLUGIN_RESULT_ERROR; msg->result = ETH_PLUGIN_RESULT_ERROR;
} }
} } break;
break;
case ETH_PLUGIN_FINALIZE: { case ETH_PLUGIN_FINALIZE: {
ethPluginFinalize_t *msg = (ethPluginFinalize_t*)parameters; ethPluginFinalize_t *msg = (ethPluginFinalize_t *) parameters;
PRINTF("compound plugin finalize\n"); PRINTF("compound plugin finalize\n");
msg->tokenLookup1 = msg->pluginSharedRO->txContent->destination; msg->tokenLookup1 = msg->pluginSharedRO->txContent->destination;
msg->numScreens = 2; msg->numScreens = 2;
msg->uiType = ETH_UI_TYPE_GENERIC; msg->uiType = ETH_UI_TYPE_GENERIC;
msg->result = ETH_PLUGIN_RESULT_OK; msg->result = ETH_PLUGIN_RESULT_OK;
} } break;
break;
case ETH_PLUGIN_PROVIDE_TOKEN: { case ETH_PLUGIN_PROVIDE_TOKEN: {
ethPluginProvideToken_t *msg = (ethPluginProvideToken_t*)parameters; ethPluginProvideToken_t *msg = (ethPluginProvideToken_t *) parameters;
compound_parameters_t *context = (compound_parameters_t*)msg->pluginContext; compound_parameters_t *context = (compound_parameters_t *) msg->pluginContext;
PRINTF("compound plugin provide token: %d\n", (msg->token1 != NULL)); PRINTF("compound plugin provide token: %d\n", (msg->token1 != NULL));
if (msg->token1 != NULL) { if (msg->token1 != NULL) {
strcpy((char *)context->ticker_1, (char *)msg->token1->ticker); strcpy((char *) context->ticker_1, (char *) msg->token1->ticker);
switch (context->selectorIndex) switch (context->selectorIndex) {
{
case COMPOUND_REDEEM_UNDERLYING: case COMPOUND_REDEEM_UNDERLYING:
case COMPOUND_MINT: case COMPOUND_MINT:
case CETH_MINT: case CETH_MINT:
msg->result = get_underlying_asset_decimals(context->ticker_1, &context->decimals) ? ETH_PLUGIN_RESULT_OK : ETH_PLUGIN_RESULT_FALLBACK; msg->result =
get_underlying_asset_decimals(context->ticker_1, &context->decimals)
? ETH_PLUGIN_RESULT_OK
: ETH_PLUGIN_RESULT_FALLBACK;
break; break;
// Only case where we use the compound contract decimals // Only case where we use the compound contract decimals
@@ -166,19 +174,16 @@ void compound_plugin_call(int message, void *parameters) {
msg->result = ETH_PLUGIN_RESULT_FALLBACK; msg->result = ETH_PLUGIN_RESULT_FALLBACK;
break; break;
} }
} } else {
else {
msg->result = ETH_PLUGIN_RESULT_FALLBACK; msg->result = ETH_PLUGIN_RESULT_FALLBACK;
} }
} } break;
break;
case ETH_PLUGIN_QUERY_CONTRACT_ID: { case ETH_PLUGIN_QUERY_CONTRACT_ID: {
ethQueryContractID_t *msg = (ethQueryContractID_t*)parameters; ethQueryContractID_t *msg = (ethQueryContractID_t *) parameters;
compound_parameters_t *context = (compound_parameters_t*)msg->pluginContext; compound_parameters_t *context = (compound_parameters_t *) msg->pluginContext;
strcpy(msg->name, "Type"); strcpy(msg->name, "Type");
switch (context->selectorIndex) switch (context->selectorIndex) {
{
case COMPOUND_REDEEM_UNDERLYING: case COMPOUND_REDEEM_UNDERLYING:
case COMPOUND_REDEEM: case COMPOUND_REDEEM:
strcpy(msg->version, "Redeem"); strcpy(msg->version, "Redeem");
@@ -194,37 +199,41 @@ void compound_plugin_call(int message, void *parameters) {
} }
strcat(msg->version, " Assets"); strcat(msg->version, " Assets");
msg->result = ETH_PLUGIN_RESULT_OK; msg->result = ETH_PLUGIN_RESULT_OK;
} } break;
break;
case ETH_PLUGIN_QUERY_CONTRACT_UI: { case ETH_PLUGIN_QUERY_CONTRACT_UI: {
ethQueryContractUI_t *msg = (ethQueryContractUI_t*)parameters; ethQueryContractUI_t *msg = (ethQueryContractUI_t *) parameters;
compound_parameters_t *context = (compound_parameters_t*)msg->pluginContext; compound_parameters_t *context = (compound_parameters_t *) msg->pluginContext;
switch(msg->screenIndex) { switch (msg->screenIndex) {
case 0: { case 0: {
strcpy(msg->title, "Amount"); strcpy(msg->title, "Amount");
char * ticker_ptr = (char *)context->ticker_1; char *ticker_ptr = (char *) context->ticker_1;
/* skip "c" in front of cToken unless we use "redeem", as /* skip "c" in front of cToken unless we use "redeem", as
redeem is the only operation dealing with a cToken amount */ redeem is the only operation dealing with a cToken amount */
if(context->selectorIndex != COMPOUND_REDEEM){ if (context->selectorIndex != COMPOUND_REDEEM) {
ticker_ptr++; ticker_ptr++;
} }
amountToString(context->amount, sizeof(context->amount), context->decimals, ticker_ptr, msg->msg, 100); amountToString(context->amount,
sizeof(context->amount),
context->decimals,
ticker_ptr,
msg->msg,
100);
msg->result = ETH_PLUGIN_RESULT_OK; msg->result = ETH_PLUGIN_RESULT_OK;
} } break;
break;
case 1: case 1:
strcpy(msg->title, "Contract"); strcpy(msg->title, "Contract");
strcpy(msg->msg, "Compound "); strcpy(msg->msg, "Compound ");
strcat(msg->msg, (char *)context->ticker_1 + 1); // remove the 'c' char at beginning of compound ticker strcat(msg->msg,
(char *) context->ticker_1 +
1); // remove the 'c' char at beginning of compound ticker
msg->result = ETH_PLUGIN_RESULT_OK; msg->result = ETH_PLUGIN_RESULT_OK;
break; break;
default: default:
break; break;
} }
} } break;
break;
default: default:
PRINTF("Unhandled message %d\n", message); PRINTF("Unhandled message %d\n", message);

View File

@@ -5,221 +5,223 @@
#include "ethUtils.h" #include "ethUtils.h"
#include "utils.h" #include "utils.h"
typedef enum { typedef enum { ERC20_TRANSFER = 0, ERC20_APPROVE } erc20Selector_t;
ERC20_TRANSFER = 0,
ERC20_APPROVE
} erc20Selector_t;
typedef enum { typedef enum { TARGET_ADDRESS = 0, TARGET_CONTRACT, TARGET_COMPOUND } targetType_t;
TARGET_ADDRESS = 0,
TARGET_CONTRACT,
TARGET_COMPOUND
} targetType_t;
typedef struct erc20_parameters_t { typedef struct erc20_parameters_t {
uint8_t selectorIndex; uint8_t selectorIndex;
uint8_t destinationAddress[21]; uint8_t destinationAddress[21];
uint8_t amount[32]; uint8_t amount[32];
uint8_t ticker_1[MAX_TICKER_LEN]; uint8_t ticker_1[MAX_TICKER_LEN];
uint8_t ticker_2[MAX_TICKER_LEN]; uint8_t ticker_2[MAX_TICKER_LEN];
uint8_t decimals; uint8_t decimals;
uint8_t target; uint8_t target;
} erc20_parameters_t; } erc20_parameters_t;
typedef struct ticker_binding_t { typedef struct ticker_binding_t {
char ticker1[MAX_TICKER_LEN]; char ticker1[MAX_TICKER_LEN];
char ticker2[MAX_TICKER_LEN]; char ticker2[MAX_TICKER_LEN];
} ticker_binding_t; } ticker_binding_t;
#define NUM_COMPOUND_BINDINGS 9 #define NUM_COMPOUND_BINDINGS 9
const ticker_binding_t const COMPOUND_BINDINGS[NUM_COMPOUND_BINDINGS] = { const ticker_binding_t const COMPOUND_BINDINGS[NUM_COMPOUND_BINDINGS] = {
{"DAI", "CDAI"}, {"DAI", "CDAI"},
{"WETH", "CETH"}, {"WETH", "CETH"},
{"USDC", "CUSDC"}, {"USDC", "CUSDC"},
{"ZRX", "CZRX"}, {"ZRX", "CZRX"},
{"USDT", "CUSDT"}, {"USDT", "CUSDT"},
{"WBTC", "CBTC"}, {"WBTC", "CBTC"},
{"BAT", "CBAT"}, {"BAT", "CBAT"},
{"REPv2", "CREP"}, {"REPv2", "CREP"},
{"SAI", "CSAI"}, {"SAI", "CSAI"},
}; };
bool check_token_binding(char* ticker1, char* ticker2, const ticker_binding_t* bindings, size_t num_bindings){ bool check_token_binding(char *ticker1,
for(size_t i = 0; i < num_bindings; i++){ char *ticker2,
ticker_binding_t* binding = (ticker_binding_t *)PIC(&bindings[i]); const ticker_binding_t *bindings,
if (strncmp(binding->ticker1, ticker1, strnlen(binding->ticker1, MAX_TICKER_LEN)) == 0 && size_t num_bindings) {
strncmp(binding->ticker2, ticker2, strnlen(binding->ticker2, MAX_TICKER_LEN)) == 0){ for (size_t i = 0; i < num_bindings; i++) {
return true; ticker_binding_t *binding = (ticker_binding_t *) PIC(&bindings[i]);
} if (strncmp(binding->ticker1, ticker1, strnlen(binding->ticker1, MAX_TICKER_LEN)) == 0 &&
} strncmp(binding->ticker2, ticker2, strnlen(binding->ticker2, MAX_TICKER_LEN)) == 0) {
return false; return true;
}
}
return false;
} }
bool erc20_plugin_available_check() { bool erc20_plugin_available_check() {
#ifdef HAVE_STARKWARE #ifdef HAVE_STARKWARE
if (quantumSet) { if (quantumSet) {
switch(dataContext.tokenContext.quantumType) { switch (dataContext.tokenContext.quantumType) {
case STARK_QUANTUM_LEGACY: case STARK_QUANTUM_LEGACY:
case STARK_QUANTUM_ETH: case STARK_QUANTUM_ETH:
case STARK_QUANTUM_ERC20: case STARK_QUANTUM_ERC20:
case STARK_QUANTUM_MINTABLE_ERC20: case STARK_QUANTUM_MINTABLE_ERC20:
return true; return true;
default: default:
return false; return false;
} }
} }
#endif #endif
return true; return true;
} }
void erc20_plugin_call(int message, void *parameters) { void erc20_plugin_call(int message, void *parameters) {
switch (message) {
case ETH_PLUGIN_INIT_CONTRACT: {
ethPluginInitContract_t *msg = (ethPluginInitContract_t *) parameters;
erc20_parameters_t *context = (erc20_parameters_t *) msg->pluginContext;
// enforce that ETH amount should be 0
if (!allzeroes(msg->pluginSharedRO->txContent->value.value, 32)) {
PRINTF("Err: Transaction amount is not 0\n");
msg->result = ETH_PLUGIN_RESULT_ERROR;
} else {
size_t i;
for (i = 0; i < NUM_ERC20_SELECTORS; i++) {
if (memcmp((uint8_t *) PIC(ERC20_SELECTORS[i]), msg->selector, SELECTOR_SIZE) ==
0) {
context->selectorIndex = i;
break;
}
}
if (i == NUM_ERC20_SELECTORS) {
PRINTF("Unknown selector %.*H\n", SELECTOR_SIZE, msg->selector);
msg->result = ETH_PLUGIN_RESULT_ERROR;
break;
}
PRINTF("erc20 plugin init\n");
msg->result = ETH_PLUGIN_RESULT_OK;
}
} break;
switch(message) { case ETH_PLUGIN_PROVIDE_PARAMETER: {
case ETH_PLUGIN_INIT_CONTRACT: { ethPluginProvideParameter_t *msg = (ethPluginProvideParameter_t *) parameters;
ethPluginInitContract_t *msg = (ethPluginInitContract_t*)parameters; erc20_parameters_t *context = (erc20_parameters_t *) msg->pluginContext;
erc20_parameters_t *context = (erc20_parameters_t*)msg->pluginContext; PRINTF("erc20 plugin provide parameter %d %.*H\n",
// enforce that ETH amount should be 0 msg->parameterOffset,
if (!allzeroes(msg->pluginSharedRO->txContent->value.value, 32)){ 32,
PRINTF("Err: Transaction amount is not 0\n"); msg->parameter);
msg->result = ETH_PLUGIN_RESULT_ERROR; switch (msg->parameterOffset) {
} case 4:
else { memmove(context->destinationAddress, msg->parameter + 12, 20);
size_t i; msg->result = ETH_PLUGIN_RESULT_OK;
for (i=0; i<NUM_ERC20_SELECTORS; i++) { break;
if (memcmp((uint8_t *)PIC(ERC20_SELECTORS[i]), msg->selector, SELECTOR_SIZE) == 0) { case 4 + 32:
context->selectorIndex = i; memmove(context->amount, msg->parameter, 32);
break; msg->result = ETH_PLUGIN_RESULT_OK;
} break;
} default:
if (i == NUM_ERC20_SELECTORS) { PRINTF("Unhandled parameter offset\n");
PRINTF("Unknown selector %.*H\n", SELECTOR_SIZE, msg->selector); msg->result = ETH_PLUGIN_RESULT_ERROR;
msg->result = ETH_PLUGIN_RESULT_ERROR; break;
break; }
} } break;
PRINTF("erc20 plugin init\n");
msg->result = ETH_PLUGIN_RESULT_OK;
}
}
break;
case ETH_PLUGIN_PROVIDE_PARAMETER : { case ETH_PLUGIN_FINALIZE: {
ethPluginProvideParameter_t *msg = (ethPluginProvideParameter_t*)parameters; ethPluginFinalize_t *msg = (ethPluginFinalize_t *) parameters;
erc20_parameters_t *context = (erc20_parameters_t*)msg->pluginContext; erc20_parameters_t *context = (erc20_parameters_t *) msg->pluginContext;
PRINTF("erc20 plugin provide parameter %d %.*H\n", msg->parameterOffset, 32, msg->parameter); PRINTF("erc20 plugin finalize\n");
switch(msg->parameterOffset) { if (context->selectorIndex == ERC20_TRANSFER) {
case 4: msg->tokenLookup1 = msg->pluginSharedRO->txContent->destination;
memmove(context->destinationAddress, msg->parameter + 12, 20); msg->amount = context->amount;
msg->result = ETH_PLUGIN_RESULT_OK; msg->address = context->destinationAddress;
break; msg->uiType = ETH_UI_TYPE_AMOUNT_ADDRESS;
case 4 + 32: msg->result = ETH_PLUGIN_RESULT_OK;
memmove(context->amount, msg->parameter, 32); } else if (context->selectorIndex == ERC20_APPROVE) {
msg->result = ETH_PLUGIN_RESULT_OK; msg->tokenLookup1 = msg->pluginSharedRO->txContent->destination;
break; msg->tokenLookup2 = context->destinationAddress;
default: msg->numScreens = 2;
PRINTF("Unhandled parameter offset\n"); msg->uiType = ETH_UI_TYPE_GENERIC;
msg->result = ETH_PLUGIN_RESULT_ERROR; msg->result = ETH_PLUGIN_RESULT_OK;
break; }
} } break;
}
break;
case ETH_PLUGIN_FINALIZE: { case ETH_PLUGIN_PROVIDE_TOKEN: {
ethPluginFinalize_t *msg = (ethPluginFinalize_t*)parameters; ethPluginProvideToken_t *msg = (ethPluginProvideToken_t *) parameters;
erc20_parameters_t *context = (erc20_parameters_t*)msg->pluginContext; erc20_parameters_t *context = (erc20_parameters_t *) msg->pluginContext;
PRINTF("erc20 plugin finalize\n"); PRINTF("erc20 plugin provide token 1: %d - 2: %d\n",
if (context->selectorIndex == ERC20_TRANSFER){ (msg->token1 != NULL),
msg->tokenLookup1 = msg->pluginSharedRO->txContent->destination; (msg->token2 != NULL));
msg->amount = context->amount; if (msg->token1 != NULL) {
msg->address = context->destinationAddress; context->target = TARGET_ADDRESS;
msg->uiType = ETH_UI_TYPE_AMOUNT_ADDRESS; strcpy((char *) context->ticker_1, (char *) msg->token1->ticker);
msg->result = ETH_PLUGIN_RESULT_OK; context->decimals = msg->token1->decimals;
} if (context->selectorIndex == ERC20_APPROVE) {
else if (context->selectorIndex == ERC20_APPROVE){ if (msg->token2 != NULL) {
msg->tokenLookup1 = msg->pluginSharedRO->txContent->destination; context->target = TARGET_CONTRACT;
msg->tokenLookup2 = context->destinationAddress; strcpy((char *) context->ticker_2, (char *) msg->token2->ticker);
msg->numScreens = 2; // test if we're doing a Compound allowance
msg->uiType = ETH_UI_TYPE_GENERIC; if (check_token_binding((char *) msg->token1->ticker,
msg->result = ETH_PLUGIN_RESULT_OK; (char *) msg->token2->ticker,
} COMPOUND_BINDINGS,
} NUM_COMPOUND_BINDINGS)) {
break; context->target = TARGET_COMPOUND;
}
}
}
msg->result = ETH_PLUGIN_RESULT_OK;
} else {
msg->result = ETH_PLUGIN_RESULT_FALLBACK;
}
} break;
case ETH_PLUGIN_PROVIDE_TOKEN: { case ETH_PLUGIN_QUERY_CONTRACT_ID: {
ethPluginProvideToken_t *msg = (ethPluginProvideToken_t*)parameters; ethQueryContractID_t *msg = (ethQueryContractID_t *) parameters;
erc20_parameters_t *context = (erc20_parameters_t*)msg->pluginContext; strcpy(msg->name, "Type");
PRINTF("erc20 plugin provide token 1: %d - 2: %d\n", (msg->token1 != NULL), (msg->token2 != NULL)); strcpy(msg->version, "Approve");
if (msg->token1 != NULL) { msg->result = ETH_PLUGIN_RESULT_OK;
context->target = TARGET_ADDRESS; } break;
strcpy((char *)context->ticker_1, (char *)msg->token1->ticker);
context->decimals = msg->token1->decimals;
if (context->selectorIndex == ERC20_APPROVE){
if(msg->token2 != NULL){
context->target = TARGET_CONTRACT;
strcpy((char *)context->ticker_2, (char *)msg->token2->ticker);
// test if we're doing a Compound allowance
if (check_token_binding((char *)msg->token1->ticker, (char *)msg->token2->ticker, COMPOUND_BINDINGS, NUM_COMPOUND_BINDINGS)){
context->target = TARGET_COMPOUND;
}
}
}
msg->result = ETH_PLUGIN_RESULT_OK;
}
else {
msg->result = ETH_PLUGIN_RESULT_FALLBACK;
}
}
break;
case ETH_PLUGIN_QUERY_CONTRACT_ID: { case ETH_PLUGIN_QUERY_CONTRACT_UI: {
ethQueryContractID_t *msg = (ethQueryContractID_t*)parameters; ethQueryContractUI_t *msg = (ethQueryContractUI_t *) parameters;
strcpy(msg->name, "Type"); erc20_parameters_t *context = (erc20_parameters_t *) msg->pluginContext;
strcpy(msg->version, "Approve"); switch (msg->screenIndex) {
msg->result = ETH_PLUGIN_RESULT_OK; case 0:
} strcpy(msg->title, "Amount");
break; if (ismaxint(context->amount, sizeof(context->amount))) {
strcpy(msg->msg, "Unlimited ");
strcat(msg->msg, (char *) context->ticker_1);
} else {
amountToString(context->amount,
sizeof(context->amount),
context->decimals,
(char *) context->ticker_1,
msg->msg,
100);
}
msg->result = ETH_PLUGIN_RESULT_OK;
break;
case 1:
if (context->target >= TARGET_CONTRACT) {
strcpy(msg->title, "Contract");
if (context->target == TARGET_COMPOUND) {
strcpy(msg->msg, "Compound ");
strcat(msg->msg,
(char *) context->ticker_2 +
1); // remove the 'c' char at beginning of compound ticker
} else {
strcpy(msg->msg, (char *) context->ticker_2);
}
} else {
strcpy(msg->title, "Address");
msg->msg[0] = '0';
msg->msg[1] = 'x';
getEthAddressStringFromBinary(context->destinationAddress,
(uint8_t *) msg->msg + 2,
msg->pluginSharedRW->sha3,
chainConfig);
}
case ETH_PLUGIN_QUERY_CONTRACT_UI: { msg->result = ETH_PLUGIN_RESULT_OK;
ethQueryContractUI_t *msg = (ethQueryContractUI_t*)parameters; break;
erc20_parameters_t *context = (erc20_parameters_t*)msg->pluginContext; default:
switch(msg->screenIndex) { break;
case 0: }
strcpy(msg->title, "Amount"); } break;
if(ismaxint(context->amount, sizeof(context->amount))){
strcpy(msg->msg, "Unlimited ");
strcat(msg->msg, (char *)context->ticker_1);
}
else{
amountToString(context->amount, sizeof(context->amount), context->decimals, (char *)context->ticker_1, msg->msg, 100);
}
msg->result = ETH_PLUGIN_RESULT_OK;
break;
case 1:
if(context->target >= TARGET_CONTRACT){
strcpy(msg->title, "Contract");
if (context->target == TARGET_COMPOUND){
strcpy(msg->msg, "Compound ");
strcat(msg->msg, (char *)context->ticker_2 + 1); // remove the 'c' char at beginning of compound ticker
}
else {
strcpy(msg->msg, (char *)context->ticker_2);
}
}
else{
strcpy(msg->title, "Address");
msg->msg[0] = '0';
msg->msg[1] = 'x';
getEthAddressStringFromBinary(context->destinationAddress, (uint8_t *)msg->msg + 2, msg->pluginSharedRW->sha3, chainConfig);
}
msg->result = ETH_PLUGIN_RESULT_OK; default:
break; PRINTF("Unhandled message %d\n", message);
default: }
break;
}
}
break;
default:
PRINTF("Unhandled message %d\n", message);
}
} }

View File

@@ -9,140 +9,139 @@ void starkware_print_stark_key(uint8_t *starkKey, char *destination);
void starkware_print_eth_address(uint8_t *address, char *destination); void starkware_print_eth_address(uint8_t *address, char *destination);
typedef struct erc721_parameters_t { typedef struct erc721_parameters_t {
uint8_t selectorIndex; uint8_t selectorIndex;
uint8_t address[20]; uint8_t address[20];
uint8_t tokenId[32]; uint8_t tokenId[32];
//tokenDefinition_t *tokenSelf; // tokenDefinition_t *tokenSelf;
//tokenDefinition_t *tokenAddress; // tokenDefinition_t *tokenAddress;
} erc721_parameters_t; } erc721_parameters_t;
bool erc721_plugin_available_check() { bool erc721_plugin_available_check() {
#ifdef HAVE_STARKWARE #ifdef HAVE_STARKWARE
if (quantumSet) { if (quantumSet) {
switch(dataContext.tokenContext.quantumType) { switch (dataContext.tokenContext.quantumType) {
case STARK_QUANTUM_ERC721: case STARK_QUANTUM_ERC721:
case STARK_QUANTUM_MINTABLE_ERC721: case STARK_QUANTUM_MINTABLE_ERC721:
return true; return true;
default: default:
return false; return false;
} }
} }
return false; return false;
#endif #endif
} }
void erc721_plugin_call(int message, void *parameters) { void erc721_plugin_call(int message, void *parameters) {
switch (message) {
case ETH_PLUGIN_INIT_CONTRACT: {
ethPluginInitContract_t *msg = (ethPluginInitContract_t *) parameters;
erc721_parameters_t *context = (erc721_parameters_t *) msg->pluginContext;
// enforce that ETH amount should be 0
if (!allzeroes(msg->pluginSharedRO->txContent->value.value, 32)) {
PRINTF("Err: Transaction amount is not 0 for erc721 approval\n");
msg->result = ETH_PLUGIN_RESULT_ERROR;
} else {
size_t i;
for (i = 0; i < NUM_ERC721_SELECTORS; i++) {
if (memcmp((uint8_t *) PIC(ERC721_SELECTORS[i]),
msg->selector,
SELECTOR_SIZE) == 0) {
context->selectorIndex = i;
break;
}
}
if (i == NUM_ERC721_SELECTORS) {
PRINTF("Unknown erc721 selector %.*H\n", SELECTOR_SIZE, msg->selector);
break;
}
if (msg->dataSize != 4 + 32 + 32) {
PRINTF("Invalid erc721 approval data size %d\n", msg->dataSize);
break;
}
PRINTF("erc721 plugin init\n");
msg->result = ETH_PLUGIN_RESULT_OK;
}
} break;
switch(message) { case ETH_PLUGIN_PROVIDE_PARAMETER: {
case ETH_PLUGIN_INIT_CONTRACT: { ethPluginProvideParameter_t *msg = (ethPluginProvideParameter_t *) parameters;
ethPluginInitContract_t *msg = (ethPluginInitContract_t*)parameters; erc721_parameters_t *context = (erc721_parameters_t *) msg->pluginContext;
erc721_parameters_t *context = (erc721_parameters_t*)msg->pluginContext; PRINTF("erc721 plugin provide parameter %d %.*H\n",
// enforce that ETH amount should be 0 msg->parameterOffset,
if (!allzeroes(msg->pluginSharedRO->txContent->value.value, 32)){ 32,
PRINTF("Err: Transaction amount is not 0 for erc721 approval\n"); msg->parameter);
msg->result = ETH_PLUGIN_RESULT_ERROR; switch (msg->parameterOffset) {
} case 4:
else { memmove(context->address, msg->parameter + 32 - 20, 20);
size_t i; msg->result = ETH_PLUGIN_RESULT_OK;
for (i=0; i<NUM_ERC721_SELECTORS; i++) { break;
if (memcmp((uint8_t *)PIC(ERC721_SELECTORS[i]), msg->selector, SELECTOR_SIZE) == 0) { case 4 + 32:
context->selectorIndex = i; memmove(context->tokenId, msg->parameter, 32);
break; msg->result = ETH_PLUGIN_RESULT_OK;
} break;
} default:
if (i == NUM_ERC721_SELECTORS) { PRINTF("Unhandled parameter offset\n");
PRINTF("Unknown erc721 selector %.*H\n", SELECTOR_SIZE, msg->selector); break;
break; }
} } break;
if (msg->dataSize != 4 + 32 + 32) {
PRINTF("Invalid erc721 approval data size %d\n", msg->dataSize);
break;
}
PRINTF("erc721 plugin init\n");
msg->result = ETH_PLUGIN_RESULT_OK;
}
}
break;
case ETH_PLUGIN_PROVIDE_PARAMETER : { case ETH_PLUGIN_FINALIZE: {
ethPluginProvideParameter_t *msg = (ethPluginProvideParameter_t*)parameters; ethPluginFinalize_t *msg = (ethPluginFinalize_t *) parameters;
erc721_parameters_t *context = (erc721_parameters_t*)msg->pluginContext; erc721_parameters_t *context = (erc721_parameters_t *) msg->pluginContext;
PRINTF("erc721 plugin provide parameter %d %.*H\n", msg->parameterOffset, 32, msg->parameter); PRINTF("erc721 plugin finalize\n");
switch(msg->parameterOffset) { msg->tokenLookup1 = msg->pluginSharedRO->txContent->destination;
case 4: msg->tokenLookup2 = context->address;
memmove(context->address, msg->parameter + 32 - 20, 20); msg->numScreens = 3;
msg->result = ETH_PLUGIN_RESULT_OK; msg->uiType = ETH_UI_TYPE_GENERIC;
break; msg->result = ETH_PLUGIN_RESULT_OK;
case 4 + 32: } break;
memmove(context->tokenId, msg->parameter, 32);
msg->result = ETH_PLUGIN_RESULT_OK;
break;
default:
PRINTF("Unhandled parameter offset\n");
break;
}
}
break;
case ETH_PLUGIN_FINALIZE: { case ETH_PLUGIN_PROVIDE_TOKEN: {
ethPluginFinalize_t *msg = (ethPluginFinalize_t*)parameters; ethPluginProvideToken_t *msg = (ethPluginProvideToken_t *) parameters;
erc721_parameters_t *context = (erc721_parameters_t*)msg->pluginContext; erc721_parameters_t *context = (erc721_parameters_t *) msg->pluginContext;
PRINTF("erc721 plugin finalize\n"); PRINTF("erc721 plugin provide token dest: %d - address: %d\n",
msg->tokenLookup1 = msg->pluginSharedRO->txContent->destination; (msg->token1 != NULL),
msg->tokenLookup2 = context->address; (msg->token2 != NULL));
msg->numScreens = 3; // context->tokenSelf = msg->token1;
msg->uiType = ETH_UI_TYPE_GENERIC; // context->tokenAddress = msg->token2;
msg->result = ETH_PLUGIN_RESULT_OK; msg->result = ETH_PLUGIN_RESULT_OK;
} } break;
break;
case ETH_PLUGIN_PROVIDE_TOKEN: { case ETH_PLUGIN_QUERY_CONTRACT_ID: {
ethPluginProvideToken_t *msg = (ethPluginProvideToken_t*)parameters; ethQueryContractID_t *msg = (ethQueryContractID_t *) parameters;
erc721_parameters_t *context = (erc721_parameters_t*)msg->pluginContext; strcpy(msg->name, "Allowance");
PRINTF("erc721 plugin provide token dest: %d - address: %d\n", (msg->token1 != NULL), (msg->token2 != NULL)); strcpy(msg->version, "");
//context->tokenSelf = msg->token1; msg->result = ETH_PLUGIN_RESULT_OK;
//context->tokenAddress = msg->token2; } break;
msg->result = ETH_PLUGIN_RESULT_OK;
}
break;
case ETH_PLUGIN_QUERY_CONTRACT_ID: { case ETH_PLUGIN_QUERY_CONTRACT_UI: {
ethQueryContractID_t *msg = (ethQueryContractID_t*)parameters; ethQueryContractUI_t *msg = (ethQueryContractUI_t *) parameters;
strcpy(msg->name, "Allowance"); erc721_parameters_t *context = (erc721_parameters_t *) msg->pluginContext;
strcpy(msg->version, ""); switch (msg->screenIndex) {
msg->result = ETH_PLUGIN_RESULT_OK; case 0:
} strcpy(msg->title, "Contract Name");
break; starkware_print_eth_address(tmpContent.txContent.destination, msg->msg);
msg->result = ETH_PLUGIN_RESULT_OK;
break;
case ETH_PLUGIN_QUERY_CONTRACT_UI: { case 1:
ethQueryContractUI_t *msg = (ethQueryContractUI_t*)parameters; strcpy(msg->title, "NFT Contract");
erc721_parameters_t *context = (erc721_parameters_t*)msg->pluginContext; starkware_print_eth_address(context->address, msg->msg);
switch(msg->screenIndex) { msg->result = ETH_PLUGIN_RESULT_OK;
case 0: break;
strcpy(msg->title, "Contract Name");
starkware_print_eth_address(tmpContent.txContent.destination, msg->msg);
msg->result = ETH_PLUGIN_RESULT_OK;
break;
case 1: case 2:
strcpy(msg->title, "NFT Contract"); strcpy(msg->title, "TokenID");
starkware_print_eth_address(context->address, msg->msg); starkware_print_stark_key(context->tokenId, msg->msg);
msg->result = ETH_PLUGIN_RESULT_OK; msg->result = ETH_PLUGIN_RESULT_OK;
break; break;
case 2: default:
strcpy(msg->title, "TokenID"); break;
starkware_print_stark_key(context->tokenId, msg->msg); }
msg->result = ETH_PLUGIN_RESULT_OK; } break;
break;
default: default:
break; PRINTF("Unhandled message %d\n", message);
} }
}
break;
default:
PRINTF("Unhandled message %d\n", message);
}
} }

View File

@@ -13,155 +13,156 @@ void getEth2PublicKey(uint32_t *bip32Path, uint8_t bip32PathLength, uint8_t *out
#define WITHDRAWAL_KEY_PATH_2 3600 #define WITHDRAWAL_KEY_PATH_2 3600
#define WITHDRAWAL_KEY_PATH_4 0 #define WITHDRAWAL_KEY_PATH_4 0
#define ETH2_DEPOSIT_PUBKEY_OFFSET 0x80 #define ETH2_DEPOSIT_PUBKEY_OFFSET 0x80
#define ETH2_WITHDRAWAL_CREDENTIALS_OFFSET 0xE0 #define ETH2_WITHDRAWAL_CREDENTIALS_OFFSET 0xE0
#define ETH2_SIGNATURE_OFFSET 0x120 #define ETH2_SIGNATURE_OFFSET 0x120
#define ETH2_DEPOSIT_PUBKEY_LENGTH 0x30 #define ETH2_DEPOSIT_PUBKEY_LENGTH 0x30
#define ETH2_WITHDRAWAL_CREDENTIALS_LENGTH 0x20 #define ETH2_WITHDRAWAL_CREDENTIALS_LENGTH 0x20
#define ETH2_SIGNATURE_LENGTH 0x60 #define ETH2_SIGNATURE_LENGTH 0x60
typedef struct eth2_deposit_parameters_t { typedef struct eth2_deposit_parameters_t {
uint8_t valid; uint8_t valid;
} eth2_deposit_parameters_t; } eth2_deposit_parameters_t;
void eth2_plugin_call(int message, void *parameters) { void eth2_plugin_call(int message, void *parameters) {
switch (message) {
case ETH_PLUGIN_INIT_CONTRACT: {
ethPluginInitContract_t *msg = (ethPluginInitContract_t *) parameters;
eth2_deposit_parameters_t *context = (eth2_deposit_parameters_t *) msg->pluginContext;
context->valid = 1;
msg->result = ETH_PLUGIN_RESULT_OK;
} break;
switch(message) { case ETH_PLUGIN_PROVIDE_PARAMETER: {
case ETH_PLUGIN_INIT_CONTRACT: { ethPluginProvideParameter_t *msg = (ethPluginProvideParameter_t *) parameters;
ethPluginInitContract_t *msg = (ethPluginInitContract_t*)parameters; eth2_deposit_parameters_t *context = (eth2_deposit_parameters_t *) msg->pluginContext;
eth2_deposit_parameters_t *context = (eth2_deposit_parameters_t*)msg->pluginContext; uint32_t index;
context->valid = 1; PRINTF("eth2 plugin provide parameter %d %.*H\n",
msg->result = ETH_PLUGIN_RESULT_OK; msg->parameterOffset,
} 32,
break; msg->parameter);
switch (msg->parameterOffset) {
case 4 + (32 * 0): // pubkey offset
case 4 + (32 * 1): // withdrawal credentials offset
case 4 + (32 * 2): // signature offset
case 4 + (32 * 4): // deposit pubkey length
case 4 + (32 * 7): // withdrawal credentials length
case 4 + (32 * 9): // signature length
{
uint32_t check = 0;
switch (msg->parameterOffset) {
case 4 + (32 * 0):
check = ETH2_DEPOSIT_PUBKEY_OFFSET;
break;
case 4 + (32 * 1):
check = ETH2_WITHDRAWAL_CREDENTIALS_OFFSET;
break;
case 4 + (32 * 2):
check = ETH2_SIGNATURE_OFFSET;
break;
case 4 + (32 * 4):
check = ETH2_DEPOSIT_PUBKEY_LENGTH;
break;
case 4 + (32 * 7):
check = ETH2_WITHDRAWAL_CREDENTIALS_LENGTH;
break;
case 4 + (32 * 9):
check = ETH2_SIGNATURE_LENGTH;
break;
default:
break;
}
index = U4BE(msg->parameter, 32 - 4);
if (index != check) {
PRINTF("eth2 plugin parameter check %d failed, expected %d got %d\n",
msg->parameterOffset,
check,
index);
context->valid = 0;
}
msg->result = ETH_PLUGIN_RESULT_OK;
} break;
case ETH_PLUGIN_PROVIDE_PARAMETER : { case 4 + (32 * 3): // deposit data root
ethPluginProvideParameter_t *msg = (ethPluginProvideParameter_t*)parameters; case 4 + (32 * 5): // deposit pubkey
eth2_deposit_parameters_t *context = (eth2_deposit_parameters_t*)msg->pluginContext; case 4 + (32 * 6):
uint32_t index; case 4 + (32 * 10): // signature
PRINTF("eth2 plugin provide parameter %d %.*H\n", msg->parameterOffset, 32, msg->parameter); case 4 + (32 * 11):
switch(msg->parameterOffset) { case 4 + (32 * 12):
case 4 + (32 * 0): // pubkey offset msg->result = ETH_PLUGIN_RESULT_OK;
case 4 + (32 * 1): // withdrawal credentials offset break;
case 4 + (32 * 2): // signature offset
case 4 + (32 * 4): // deposit pubkey length
case 4 + (32 * 7): // withdrawal credentials length
case 4 + (32 * 9): // signature length
{
uint32_t check = 0;
switch(msg->parameterOffset) {
case 4 + (32 * 0):
check = ETH2_DEPOSIT_PUBKEY_OFFSET;
break;
case 4 + (32 * 1):
check = ETH2_WITHDRAWAL_CREDENTIALS_OFFSET;
break;
case 4 + (32 * 2):
check = ETH2_SIGNATURE_OFFSET;
break;
case 4 + (32 * 4):
check = ETH2_DEPOSIT_PUBKEY_LENGTH;
break;
case 4 + (32 * 7):
check = ETH2_WITHDRAWAL_CREDENTIALS_LENGTH;
break;
case 4 + (32 * 9):
check = ETH2_SIGNATURE_LENGTH;
break;
default:
break;
}
index = U4BE(msg->parameter, 32 - 4);
if (index != check) {
PRINTF("eth2 plugin parameter check %d failed, expected %d got %d\n", msg->parameterOffset, check, index);
context->valid = 0;
}
msg->result = ETH_PLUGIN_RESULT_OK;
}
break;
case 4 + (32 * 3): // deposit data root case 4 + (32 * 8): // withdrawal credentials
case 4 + (32 * 5): // deposit pubkey {
case 4 + (32 * 6): uint8_t tmp[48];
case 4 + (32 * 10): // signature uint32_t withdrawalKeyPath[4];
case 4 + (32 * 11): withdrawalKeyPath[0] = WITHDRAWAL_KEY_PATH_1;
case 4 + (32 * 12): withdrawalKeyPath[1] = WITHDRAWAL_KEY_PATH_2;
msg->result = ETH_PLUGIN_RESULT_OK; withdrawalKeyPath[2] = eth2WithdrawalIndex;
break; withdrawalKeyPath[3] = WITHDRAWAL_KEY_PATH_4;
getEth2PublicKey(withdrawalKeyPath, 4, tmp);
PRINTF("eth2 plugin computed withdrawal public key %.*H\n", 48, tmp);
cx_hash_sha256(tmp, 48, tmp, 32);
tmp[0] = 0;
if (memcmp(tmp, msg->parameter, 32) != 0) {
PRINTF("eth2 plugin invalid withdrawal credentials\n");
PRINTF("Got %.*H\n", 32, msg->parameter);
PRINTF("Expected %.*H\n", 32, tmp);
context->valid = 0;
}
msg->result = ETH_PLUGIN_RESULT_OK;
} break;
case 4 + (32 * 8): // withdrawal credentials default:
{ PRINTF("Unhandled parameter offset\n");
uint8_t tmp[48]; break;
uint32_t withdrawalKeyPath[4]; }
withdrawalKeyPath[0] = WITHDRAWAL_KEY_PATH_1; } break;
withdrawalKeyPath[1] = WITHDRAWAL_KEY_PATH_2;
withdrawalKeyPath[2] = eth2WithdrawalIndex;
withdrawalKeyPath[3] = WITHDRAWAL_KEY_PATH_4;
getEth2PublicKey(withdrawalKeyPath, 4, tmp);
PRINTF("eth2 plugin computed withdrawal public key %.*H\n", 48, tmp);
cx_hash_sha256(tmp, 48, tmp, 32);
tmp[0] = 0;
if (memcmp(tmp, msg->parameter, 32) != 0) {
PRINTF("eth2 plugin invalid withdrawal credentials\n");
PRINTF("Got %.*H\n", 32, msg->parameter);
PRINTF("Expected %.*H\n", 32, tmp);
context->valid = 0;
}
msg->result = ETH_PLUGIN_RESULT_OK;
}
break;
default: case ETH_PLUGIN_FINALIZE: {
PRINTF("Unhandled parameter offset\n"); ethPluginFinalize_t *msg = (ethPluginFinalize_t *) parameters;
break; eth2_deposit_parameters_t *context = (eth2_deposit_parameters_t *) msg->pluginContext;
} PRINTF("eth2 plugin finalize\n");
} if (context->valid) {
break; msg->numScreens = 1;
msg->uiType = ETH_UI_TYPE_GENERIC;
msg->result = ETH_PLUGIN_RESULT_OK;
} else {
msg->result = ETH_PLUGIN_RESULT_FALLBACK;
}
} break;
case ETH_PLUGIN_FINALIZE: { case ETH_PLUGIN_QUERY_CONTRACT_ID: {
ethPluginFinalize_t *msg = (ethPluginFinalize_t*)parameters; ethQueryContractID_t *msg = (ethQueryContractID_t *) parameters;
eth2_deposit_parameters_t *context = (eth2_deposit_parameters_t*)msg->pluginContext; strcpy(msg->name, "ETH2");
PRINTF("eth2 plugin finalize\n"); strcpy(msg->version, "Deposit");
if (context->valid) { msg->result = ETH_PLUGIN_RESULT_OK;
msg->numScreens = 1; } break;
msg->uiType = ETH_UI_TYPE_GENERIC;
msg->result = ETH_PLUGIN_RESULT_OK;
}
else {
msg->result = ETH_PLUGIN_RESULT_FALLBACK;
}
}
break;
case ETH_PLUGIN_QUERY_CONTRACT_ID: { case ETH_PLUGIN_QUERY_CONTRACT_UI: {
ethQueryContractID_t *msg = (ethQueryContractID_t*)parameters; ethQueryContractUI_t *msg = (ethQueryContractUI_t *) parameters;
strcpy(msg->name, "ETH2"); // eth2_deposit_parameters_t *context = (eth2_deposit_parameters_t*)msg->pluginContext;
strcpy(msg->version, "Deposit"); switch (msg->screenIndex) {
msg->result = ETH_PLUGIN_RESULT_OK; case 0: {
} uint8_t decimals = WEI_TO_ETHER;
break; uint8_t *ticker = (uint8_t *) PIC(chainConfig->coinName);
strcpy(msg->title, "Amount");
amountToString(tmpContent.txContent.value.value,
tmpContent.txContent.value.length,
decimals,
(char *) ticker,
msg->msg,
100);
msg->result = ETH_PLUGIN_RESULT_OK;
} break;
default:
break;
}
} break;
case ETH_PLUGIN_QUERY_CONTRACT_UI: { default:
ethQueryContractUI_t *msg = (ethQueryContractUI_t*)parameters; PRINTF("Unhandled message %d\n", message);
//eth2_deposit_parameters_t *context = (eth2_deposit_parameters_t*)msg->pluginContext; }
switch(msg->screenIndex) {
case 0: {
uint8_t decimals = WEI_TO_ETHER;
uint8_t *ticker = (uint8_t *)PIC(chainConfig->coinName);
strcpy(msg->title, "Amount");
amountToString(tmpContent.txContent.value.value, tmpContent.txContent.value.length, decimals, (char*)ticker, msg->msg, 100);
msg->result = ETH_PLUGIN_RESULT_OK;
}
break;
default:
break;
}
}
break;
default:
PRINTF("Unhandled message %d\n", message);
}
} }
#endif #endif

File diff suppressed because it is too large Load Diff