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"
#define APP_FLAG_DATA_ALLOWED 0x01
#define APP_FLAG_DATA_ALLOWED 0x01
#define APP_FLAG_EXTERNAL_TOKEN_NEEDED 0x02
#define APP_FLAG_STARKWARE 0x04
#define APP_FLAG_STARKWARE_V2 0x08
#define APP_FLAG_STARKWARE 0x04
#define APP_FLAG_STARKWARE_V2 0x08
#define CLA 0xE0
#define INS_GET_PUBLIC_KEY 0x02
#define INS_SIGN 0x04
#define INS_GET_APP_CONFIGURATION 0x06
#define INS_SIGN_PERSONAL_MESSAGE 0x08
#define CLA 0xE0
#define INS_GET_PUBLIC_KEY 0x02
#define INS_SIGN 0x04
#define INS_GET_APP_CONFIGURATION 0x06
#define INS_SIGN_PERSONAL_MESSAGE 0x08
#define INS_PROVIDE_ERC20_TOKEN_INFORMATION 0x0A
#define INS_SIGN_EIP_712_MESSAGE 0x0C
#define INS_GET_ETH2_PUBLIC_KEY 0x0E
#define INS_SET_ETH2_WITHDRAWAL_INDEX 0x10
#define P1_CONFIRM 0x01
#define P1_NON_CONFIRM 0x00
#define P2_NO_CHAINCODE 0x00
#define P2_CHAINCODE 0x01
#define P1_FIRST 0x00
#define P1_MORE 0x80
#define INS_SIGN_EIP_712_MESSAGE 0x0C
#define INS_GET_ETH2_PUBLIC_KEY 0x0E
#define INS_SET_ETH2_WITHDRAWAL_INDEX 0x10
#define P1_CONFIRM 0x01
#define P1_NON_CONFIRM 0x00
#define P2_NO_CHAINCODE 0x00
#define P2_CHAINCODE 0x01
#define P1_FIRST 0x00
#define P1_MORE 0x80
#define COMMON_CLA 0xB0
#define COMMON_CLA 0xB0
#define COMMON_INS_GET_WALLET_ID 0x04
#ifdef HAVE_STARKWARE
#define STARKWARE_CLA 0xF0
#define STARKWARE_INS_GET_PUBLIC_KEY 0x02
#define STARKWARE_INS_SIGN_MESSAGE 0x04
#define STARKWARE_CLA 0xF0
#define STARKWARE_INS_GET_PUBLIC_KEY 0x02
#define STARKWARE_INS_SIGN_MESSAGE 0x04
#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_TRANSFER 0x02
#define P1_STARK_ORDER_V2 0x03
#define P1_STARK_TRANSFER_V2 0x04
#define P1_STARK_ORDER 0x01
#define P1_STARK_TRANSFER 0x02
#define P1_STARK_ORDER_V2 0x03
#define P1_STARK_TRANSFER_V2 0x04
#define P1_STARK_CONDITIONAL_TRANSFER 0x05
#define STARK_ORDER_TYPE 0
#define STARK_TRANSFER_TYPE 1
#define STARK_ORDER_TYPE 0
#define STARK_TRANSFER_TYPE 1
#define STARK_CONDITIONAL_TRANSFER_TYPE 2
#endif
#define OFFSET_CLA 0
#define OFFSET_INS 1
#define OFFSET_P1 2
#define OFFSET_P2 3
#define OFFSET_LC 4
#define OFFSET_CLA 0
#define OFFSET_INS 1
#define OFFSET_P1 2
#define OFFSET_P2 3
#define OFFSET_LC 4
#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 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);
void handleGetPublicKey(uint8_t p1,
uint8_t p2,
uint8_t *dataBuffer,
uint16_t dataLength,
unsigned int *flags,
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
void handleGetEth2PublicKey(uint8_t p1, 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);
void handleGetEth2PublicKey(uint8_t p1,
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
#ifdef HAVE_STARKWARE
void handleStarkwareGetPublicKey(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 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);
void handleStarkwareGetPublicKey(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 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

View File

@@ -2,16 +2,16 @@
* Copyright (c) 2003 Apple Computer, Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
*
* Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
*
*
* This file contains Original Code and/or Modifications of Original Code
* as defined in and that are subject to the Apple Public Source License
* Version 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ and read it before using this
* file.
*
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
@@ -19,7 +19,7 @@
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
*
* @APPLE_LICENSE_HEADER_END@
*/
/* ====================================================================
@@ -172,41 +172,34 @@ int Base64decode(char *bufplain, const char *bufcoded)
#endif
static const char basis_64[] =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
static const char basis_64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
int Base64encode_len(int len)
{
int Base64encode_len(int len) {
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;
char *p;
p = encoded;
for (i = 0; i < len - 2; i += 3) {
*p++ = basis_64[(string[i] >> 2) & 0x3F];
*p++ = basis_64[((string[i] & 0x3) << 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 + 2] & 0x3F];
*p++ = basis_64[(string[i] >> 2) & 0x3F];
*p++ = basis_64[((string[i] & 0x3) << 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 + 2] & 0x3F];
}
if (i < len) {
*p++ = basis_64[(string[i] >> 2) & 0x3F];
if (i == (len - 1)) {
*p++ = basis_64[((string[i] & 0x3) << 4)];
*p++ = basis_64[(string[i] >> 2) & 0x3F];
if (i == (len - 1)) {
*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++ = '=';
}
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';
return p - encoded;

View File

@@ -2,16 +2,16 @@
* Copyright (c) 2003 Apple Computer, Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
*
* Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
*
*
* This file contains Original Code and/or Modifications of Original Code
* as defined in and that are subject to the Apple Public Source License
* Version 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ and read it before using this
* file.
*
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
@@ -19,7 +19,7 @@
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
*
* @APPLE_LICENSE_HEADER_END@
*/
/* ====================================================================
@@ -79,8 +79,6 @@
*
*/
#ifndef _BASE64_H_
#define _BASE64_H_
@@ -89,7 +87,7 @@ extern "C" {
#endif
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
@@ -102,4 +100,4 @@ int Base64decode(char * plain_dst, const char *coded_src);
}
#endif
#endif //_BASE64_H_
#endif //_BASE64_H_

View File

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

View File

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

View File

@@ -3,11 +3,24 @@
#include "eth_plugin_interface.h"
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_provide_token(ethPluginProvideToken_t *provideToken, tokenDefinition_t *token1, 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);
void eth_plugin_prepare_provide_token(ethPluginProvideToken_t *provideToken,
tokenDefinition_t *token1,
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);
// 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);
#endif

View File

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

View File

@@ -3,138 +3,118 @@
bool erc20_plugin_available_check(void);
bool erc721_plugin_available_check(void);
void erc20_plugin_call(int message, void *parameters);
void erc721_plugin_call(int message, void *parameters);
void compound_plugin_call(int message, void *parameters);
void erc20_plugin_call(int message, void* parameters);
void erc721_plugin_call(int message, void* parameters);
void compound_plugin_call(int message, void* parameters);
#ifdef HAVE_STARKWARE
void starkware_plugin_call(int message, void *parameters);
void starkware_plugin_call(int message, void* parameters);
#endif
#ifdef HAVE_ETH2
void eth2_plugin_call(int message, void *parameters);
void eth2_plugin_call(int message, void* parameters);
#endif
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_TRANSFER_SELECTOR[SELECTOR_SIZE] = {0xa9, 0x05, 0x9c, 0xbb};
static const uint8_t const ERC20_APPROVE_SELECTOR[SELECTOR_SIZE] = {0x09, 0x5e, 0xa7, 0xb3};
const uint8_t* const ERC20_SELECTORS[NUM_ERC20_SELECTORS] = {
ERC20_TRANSFER_SELECTOR, ERC20_APPROVE_SELECTOR
};
const uint8_t* const ERC20_SELECTORS[NUM_ERC20_SELECTORS] = {ERC20_TRANSFER_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] = {
ERC721_APPROVE_SELECTOR
};
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_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 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_MINT_SELECTOR[SELECTOR_SIZE] = {0xa0, 0x71, 0x2d, 0x68};
static const uint8_t const CETH_MINT_SELECTOR[SELECTOR_SIZE] = {0x12, 0x49, 0xc5, 0x8b};
const uint8_t* const COMPOUND_SELECTORS[NUM_COMPOUND_SELECTORS] = {
COMPOUND_REDEEM_UNDERLYING_SELECTOR, COMPOUND_REDEEM_SELECTOR,
COMPOUND_MINT_SELECTOR, CETH_MINT_SELECTOR
};
COMPOUND_REDEEM_UNDERLYING_SELECTOR,
COMPOUND_REDEEM_SELECTOR,
COMPOUND_MINT_SELECTOR,
CETH_MINT_SELECTOR};
#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] = {
ETH2_DEPOSIT_SELECTOR
};
const uint8_t* const ETH2_SELECTORS[NUM_ETH2_SELECTORS] = {ETH2_DEPOSIT_SELECTOR};
#endif
#ifdef HAVE_STARKWARE
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_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_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_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_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_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_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_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_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_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_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_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] = {
STARKWARE_REGISTER_ID, STARKWARE_DEPOSIT_TOKEN_ID, STARKWARE_DEPOSIT_ETH_ID,
STARKWARE_DEPOSIT_CANCEL_ID, STARKWARE_DEPOSIT_RECLAIM_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
};
STARKWARE_REGISTER_ID,
STARKWARE_DEPOSIT_TOKEN_ID,
STARKWARE_DEPOSIT_ETH_ID,
STARKWARE_DEPOSIT_CANCEL_ID,
STARKWARE_DEPOSIT_RECLAIM_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
// All internal alias names start with 'minus'
const internalEthPlugin_t const INTERNAL_ETH_PLUGINS[] = {
{
erc20_plugin_available_check,
ERC20_SELECTORS,
NUM_ERC20_SELECTORS,
"-erc20",
erc20_plugin_call
},
const internalEthPlugin_t const INTERNAL_ETH_PLUGINS[] = {
{erc20_plugin_available_check,
ERC20_SELECTORS,
NUM_ERC20_SELECTORS,
"-erc20",
erc20_plugin_call},
{
erc721_plugin_available_check,
ERC721_SELECTORS,
NUM_ERC721_SELECTORS,
"-er721",
erc721_plugin_call
},
{erc721_plugin_available_check,
ERC721_SELECTORS,
NUM_ERC721_SELECTORS,
"-er721",
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
{
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
{
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 struct internalEthPlugin_t {
PluginAvailableCheck availableCheck;
const uint8_t **selectors;
uint8_t num_selectors;
char alias[7];
PluginCall impl;
PluginAvailableCheck availableCheck;
const uint8_t** selectors;
uint8_t num_selectors;
char alias[7];
PluginCall impl;
} internalEthPlugin_t;
#define NUM_ERC20_SELECTORS 2

View File

@@ -7,86 +7,94 @@
typedef enum {
PLUGIN_UI_INSIDE = 0,
PLUGIN_UI_OUTSIDE
PLUGIN_UI_INSIDE = 0,
PLUGIN_UI_OUTSIDE
} plugin_ui_state_t;
void computeFees(char *displayBuffer, uint32_t displayBufferSize);
void plugin_ui_get_id() {
ethQueryContractID_t pluginQueryContractID;
eth_plugin_prepare_query_contract_ID(&pluginQueryContractID, strings.tmp.tmp, sizeof(strings.tmp.tmp), strings.tmp.tmp2, sizeof(strings.tmp.tmp2));
// Query the original contract for ID if it's not an internal alias
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);
}
ethQueryContractID_t pluginQueryContractID;
eth_plugin_prepare_query_contract_ID(&pluginQueryContractID,
strings.tmp.tmp,
sizeof(strings.tmp.tmp),
strings.tmp.tmp2,
sizeof(strings.tmp.tmp2));
// Query the original contract for ID if it's not an internal alias
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() {
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));
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);
}
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));
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) {
if (entering) {
if (dataContext.tokenContext.pluginUiState == PLUGIN_UI_OUTSIDE) {
dataContext.tokenContext.pluginUiState = PLUGIN_UI_INSIDE;
dataContext.tokenContext.pluginUiCurrentItem = 0;
plugin_ui_get_item();
ux_flow_next();
if (entering) {
if (dataContext.tokenContext.pluginUiState == PLUGIN_UI_OUTSIDE) {
dataContext.tokenContext.pluginUiState = PLUGIN_UI_INSIDE;
dataContext.tokenContext.pluginUiCurrentItem = 0;
plugin_ui_get_item();
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() {
computeFees(strings.common.maxFee, sizeof(strings.common.maxFee));
computeFees(strings.common.maxFee, sizeof(strings.common.maxFee));
}
// clang-format off
UX_FLOW_DEF_NOCB(
ux_plugin_approval_intro_step,
pnn,
@@ -155,21 +163,20 @@ UX_FLOW_DEF_VALID(
&C_icon_crossmark,
"Reject",
});
// clang-format on
UX_FLOW(
ux_plugin_approval_flow,
&ux_plugin_approval_intro_step,
&ux_plugin_approval_id_step,
&ux_plugin_approval_before_step,
&ux_plugin_approval_display_step,
&ux_plugin_approval_after_step,
&ux_plugin_approval_fees_step,
&ux_plugin_approval_ok_step,
&ux_plugin_approval_cancel_step
);
UX_FLOW(ux_plugin_approval_flow,
&ux_plugin_approval_intro_step,
&ux_plugin_approval_id_step,
&ux_plugin_approval_before_step,
&ux_plugin_approval_display_step,
&ux_plugin_approval_after_step,
&ux_plugin_approval_fees_step,
&ux_plugin_approval_ok_step,
&ux_plugin_approval_cancel_step);
void plugin_ui_start() {
dataContext.tokenContext.pluginUiState = PLUGIN_UI_OUTSIDE;
dataContext.tokenContext.pluginUiCurrentItem = 0;
ux_flow_init(0, ux_plugin_approval_flow, NULL);
dataContext.tokenContext.pluginUiState = PLUGIN_UI_OUTSIDE;
dataContext.tokenContext.pluginUiCurrentItem = 0;
ux_flow_init(0, ux_plugin_approval_flow, NULL);
}

View File

@@ -7,8 +7,8 @@
#define ZERO(x) memset(x, 0, sizeof(x))
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("Address to check %s\n",params->address_to_check);
PRINTF("Params on the address %d\n", (unsigned int) params);
PRINTF("Address to check %s\n", params->address_to_check);
PRINTF("Inside handle_check_address\n");
params->result = 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 *bip32_path_ptr = params->address_parameters;
uint8_t* bip32_path_ptr = params->address_parameters;
uint8_t bip32PathLength = *(bip32_path_ptr++);
cx_sha3_t local_sha3;
// Common memory is used for locals that are not used concurrently
union group1
{
union group1 {
uint32_t bip32Path[MAX_BIP32_PATH];
cx_ecfp_private_key_t privateKey;
char address[51];
} locals_union1;
union group2
{
union group2 {
uint8_t privateKeyData[32];
cx_ecfp_public_key_t publicKey;
} locals_union2;
if ((bip32PathLength < 0x01) ||
(bip32PathLength > MAX_BIP32_PATH) ||
(bip32PathLength*4 != params->address_parameters_length - 1)) {
if ((bip32PathLength < 0x01) || (bip32PathLength > MAX_BIP32_PATH) ||
(bip32PathLength * 4 != params->address_parameters_length - 1)) {
PRINTF("Invalid path\n");
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);
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);
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);
cx_ecfp_generate_pair(CX_CURVE_256K1, &locals_union2.publicKey, &locals_union1.privateKey, 1);
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);
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;
}
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");
return;
}

View File

@@ -4,6 +4,7 @@
#include "swap_lib_calls.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 <stdint.h>
void handle_get_printable_amount( get_printable_amount_parameters_t* params, chain_config_t *config) {
void handle_get_printable_amount(get_printable_amount_parameters_t* params,
chain_config_t* config) {
uint8_t decimals;
char ticker[MAX_TICKER_LEN];
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);
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");
os_lib_end();
}
// 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));
memcpy(ticker, config->coinName, ticker_len);
ticker[ticker_len] = ' ';
ticker[ticker_len+1] = '\0';
ticker[ticker_len + 1] = '\0';
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 "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 "utils.h"
void copy_transaction_parameters(create_transaction_parameters_t* sign_transaction_params, chain_config_t *config) {
void copy_transaction_parameters(create_transaction_parameters_t* sign_transaction_params,
chain_config_t* config) {
// 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
txStringProperties_t 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') ||
(sign_transaction_params->amount_length > 32) ||
(sign_transaction_params->fee_amount_length > 8)) {
@@ -19,21 +21,35 @@ void copy_transaction_parameters(create_transaction_parameters_t* sign_transacti
uint8_t decimals;
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");
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
strcpy(ticker, config->coinName);
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));
}
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);
chainConfig = config;
reset_app_context();
@@ -41,25 +57,25 @@ void handle_swap_sign_transaction(create_transaction_parameters_t* sign_transact
io_seproxyhal_init();
if (N_storage.initialized != 0x01) {
internalStorage_t storage;
storage.dataAllowed = 0x00;
storage.contractDetails = 0x00;
storage.initialized = 0x01;
nvm_write((void*)&N_storage, (void*)&storage, sizeof(internalStorage_t));
internalStorage_t storage;
storage.dataAllowed = 0x00;
storage.contractDetails = 0x00;
storage.initialized = 0x01;
nvm_write((void*) &N_storage, (void*) &storage, sizeof(internalStorage_t));
}
UX_INIT();
USB_power(0);
USB_power(1);
//ui_idle();
// ui_idle();
PRINTF("USB power ON/OFF\n");
#ifdef TARGET_NANOX
// grab the current plane mode setting
G_io_app.plane_mode = os_setting_get(OS_SETTING_PLANEMODE, NULL, 0);
#endif // TARGET_NANOX
#endif // TARGET_NANOX
#ifdef HAVE_BLE
BLE_power(0, NULL);
BLE_power(1, "Nano X");
#endif // HAVE_BLE
#endif // HAVE_BLE
app_main();
}

View File

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

View File

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

View File

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

View File

@@ -22,24 +22,24 @@
#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 {
unsigned char dataAllowed;
unsigned char contractDetails;
uint8_t initialized;
unsigned char dataAllowed;
unsigned char contractDetails;
uint8_t initialized;
} internalStorage_t;
#ifdef HAVE_STARKWARE
typedef enum starkQuantumType_e {
STARK_QUANTUM_LEGACY = 0x00,
STARK_QUANTUM_ETH,
STARK_QUANTUM_ERC20,
STARK_QUANTUM_ERC721,
STARK_QUANTUM_MINTABLE_ERC20,
STARK_QUANTUM_MINTABLE_ERC721
STARK_QUANTUM_LEGACY = 0x00,
STARK_QUANTUM_ETH,
STARK_QUANTUM_ERC20,
STARK_QUANTUM_ERC721,
STARK_QUANTUM_MINTABLE_ERC20,
STARK_QUANTUM_MINTABLE_ERC721
} starkQuantumType_e;
@@ -47,11 +47,11 @@ typedef enum starkQuantumType_e {
typedef struct tokenContext_t {
char pluginName[PLUGIN_ID_LENGTH];
uint8_t pluginAvailable;
uint8_t pluginAvailable;
uint8_t data[32];
uint8_t fieldIndex;
uint8_t fieldOffset;
uint8_t fieldOffset;
uint8_t pluginUiMaxItems;
uint8_t pluginUiCurrentItem;
@@ -98,7 +98,6 @@ typedef struct messageSigningContext712_t {
uint8_t messageHash[32];
} messageSigningContext712_t;
typedef union {
publicKeyContext_t publicKeyContext;
transactionContext_t transactionContext;
@@ -107,22 +106,22 @@ typedef union {
} tmpCtx_t;
typedef union {
txContent_t txContent;
cx_sha256_t sha2;
char tmp[100];
txContent_t txContent;
cx_sha256_t sha2;
char tmp[100];
} tmpContent_t;
#ifdef HAVE_STARKWARE
typedef struct starkContext_t {
uint8_t w1[32];
uint8_t w2[32];
uint8_t w3[32];
uint8_t w4[32];
uint8_t conditional;
uint8_t transferDestination[32];
uint8_t fact[32];
uint8_t conditionAddress[20];
uint8_t w1[32];
uint8_t w2[32];
uint8_t w3[32];
uint8_t w4[32];
uint8_t conditional;
uint8_t transferDestination[32];
uint8_t fact[32];
uint8_t conditionAddress[20];
} starkContext_t;
#endif
@@ -134,27 +133,23 @@ typedef union {
#endif
} dataContext_t;
typedef enum {
APP_STATE_IDLE,
APP_STATE_SIGNING_TX,
APP_STATE_SIGNING_MESSAGE
} app_state_t;
typedef enum { APP_STATE_IDLE, APP_STATE_SIGNING_TX, APP_STATE_SIGNING_MESSAGE } app_state_t;
typedef enum {
CONTRACT_NONE,
CONTRACT_ERC20,
CONTRACT_ALLOWANCE,
CONTRACT_NONE,
CONTRACT_ERC20,
CONTRACT_ALLOWANCE,
#ifdef HAVE_STARKWARE
CONTRACT_STARKWARE_REGISTER,
CONTRACT_STARKWARE_DEPOSIT_TOKEN,
CONTRACT_STARKWARE_DEPOSIT_ETH,
CONTRACT_STARKWARE_WITHDRAW,
CONTRACT_STARKWARE_DEPOSIT_CANCEL,
CONTRACT_STARKWARE_DEPOSIT_RECLAIM,
CONTRACT_STARKWARE_FULL_WITHDRAWAL,
CONTRACT_STARKWARE_FREEZE,
CONTRACT_STARKWARE_ESCAPE,
CONTRACT_STARKWARE_VERIFY_ESCAPE
CONTRACT_STARKWARE_REGISTER,
CONTRACT_STARKWARE_DEPOSIT_TOKEN,
CONTRACT_STARKWARE_DEPOSIT_ETH,
CONTRACT_STARKWARE_WITHDRAW,
CONTRACT_STARKWARE_DEPOSIT_CANCEL,
CONTRACT_STARKWARE_DEPOSIT_RECLAIM,
CONTRACT_STARKWARE_FULL_WITHDRAWAL,
CONTRACT_STARKWARE_FREEZE,
CONTRACT_STARKWARE_ESCAPE,
CONTRACT_STARKWARE_VERIFY_ESCAPE
#endif
} contract_call_t;
@@ -196,5 +191,4 @@ extern uint32_t eth2WithdrawalIndex;
void reset_app_context(void);
#endif // __SHARED_CONTEXT_H__
#endif // __SHARED_CONTEXT_H__

View File

@@ -5,18 +5,17 @@
#include "ui_callbacks.h"
#include "utils.h"
static unsigned char const C_cx_Stark256_n[] = {
//n: 0x0800000000000010ffffffffffffffffb781126dcae7b2321e66a241adc64d2f
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};
// C_cx_secp256k1_n - (C_cx_secp256k1_n % C_cx_Stark256_n)
static unsigned char const STARK_DERIVE_BIAS[] = {
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
};
static unsigned char const C_cx_Stark256_n[] = {
// n: 0x0800000000000010ffffffffffffffffb781126dcae7b2321e66a241adc64d2f
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};
void starkDerivePrivateKey(uint32_t *bip32Path, uint32_t bip32PathLength, uint8_t *privateKeyData) {
// C_cx_secp256k1_n - (C_cx_secp256k1_n % C_cx_Stark256_n)
static unsigned char const STARK_DERIVE_BIAS[] = {
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};
void starkDerivePrivateKey(uint32_t *bip32Path, uint32_t bip32PathLength, uint8_t *privateKeyData) {
#if 0
// Sanity check
if (bip32Path[0] != STARK_BIP32_PATH_0) {
@@ -29,59 +28,62 @@ void starkDerivePrivateKey(uint32_t *bip32Path, uint32_t bip32PathLength, uint8_
cx_math_modm(privateKeyData, 32, C_cx_Stark256_n, 32);
PRINTF("Private key after processing %.*H\n", 32, privateKeyData);
#else
uint8_t tmp[33];
uint8_t index = 0;
// Sanity check
if ((bip32PathLength < 2) || (bip32Path[0] != STARK_BIP32_PATH_0) || (bip32Path[1] != STARK_BIP32_PATH_1)) {
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;
uint8_t tmp[33];
uint8_t index = 0;
// Sanity check
if ((bip32PathLength < 2) || (bip32Path[0] != STARK_BIP32_PATH_0) ||
(bip32Path[1] != STARK_BIP32_PATH_1)) {
PRINTF("Invalid Stark derivation path %d %d\n", bip32Path[0], bip32Path[1]);
THROW(0x6a80);
}
index++;
}
PRINTF("Key result %.*H\n", 32, privateKeyData);
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++;
}
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) {
uint256_t amountPre, quantum, amount;
uint8_t decimals;
char *ticker = (char*)PIC(chainConfig->coinName);
void stark_get_amount_string(uint8_t *contractAddress,
uint8_t *quantum256,
uint8_t *amount64,
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)) {
decimals = WEI_TO_ETHER;
PRINTF("stark_get_amount_string - ETH\n");
}
else {
tokenDefinition_t *token = getKnownToken(contractAddress);
if (token == NULL) { // caught earlier
THROW(0x6A80);
if (allzeroes(contractAddress, 20)) {
decimals = WEI_TO_ETHER;
PRINTF("stark_get_amount_string - ETH\n");
} else {
tokenDefinition_t *token = getKnownToken(contractAddress);
if (token == NULL) { // caught earlier
THROW(0x6A80);
}
decimals = token->decimals;
ticker = (char *) token->ticker;
PRINTF("stark_get_amount_string - decimals %d ticker %s\n", decimals, ticker);
}
decimals = token->decimals;
ticker = (char*)token->ticker;
PRINTF("stark_get_amount_string - decimals %d ticker %s\n", decimals, ticker);
}
convertUint256BE(amount64, 8, &amountPre);
readu256BE(quantum256, &quantum);
mul256(&amountPre, &quantum, &amount);
tostring256(&amount, 10, tmp100, 100);
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);
convertUint256BE(amount64, 8, &amountPre);
readu256BE(quantum256, &quantum);
mul256(&amountPre, &quantum, &amount);
tostring256(&amount, 10, tmp100, 100);
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 "cx.h"
/* EC points */
#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 ECPoint[EC_POINT_SIZE];
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)
static const ECPoint PEDERSEN_SHIFT[] = { {
static const ECPoint PEDERSEN_SHIFT[] = {{
0x04,
0x04, 0x9e, 0xe3, 0xeb, 0xa8, 0xc1, 0x60, 0x07, 0x00, 0xee, 0x1b,
0x87, 0xeb, 0x59, 0x9f, 0x16, 0x71, 0x6b, 0x0b, 0x10, 0x22, 0x94,
0x77, 0x33, 0x55, 0x1f, 0xde, 0x40, 0x50, 0xca, 0x68, 0x04,
0x04, 0x9e, 0xe3, 0xeb, 0xa8, 0xc1, 0x60, 0x07, 0x00, 0xee, 0x1b, 0x87, 0xeb, 0x59, 0x9f, 0x16,
0x71, 0x6b, 0x0b, 0x10, 0x22, 0x94, 0x77, 0x33, 0x55, 0x1f, 0xde, 0x40, 0x50, 0xca, 0x68, 0x04,
0x03, 0xca, 0x0c, 0xfe, 0x4b, 0x3b, 0xc6, 0xdd, 0xf3, 0x46, 0xd4,
0x9d, 0x06, 0xea, 0x0e, 0xd3, 0x4e, 0x62, 0x10, 0x62, 0xc0, 0xe0,
0x56, 0xc1, 0xd0, 0x40, 0x5d, 0x26, 0x6e, 0x10, 0x26, 0x8a,
0x03, 0xca, 0x0c, 0xfe, 0x4b, 0x3b, 0xc6, 0xdd, 0xf3, 0x46, 0xd4, 0x9d, 0x06, 0xea, 0x0e, 0xd3,
0x4e, 0x62, 0x10, 0x62, 0xc0, 0xe0, 0x56, 0xc1, 0xd0, 0x40, 0x5d, 0x26, 0x6e, 0x10, 0x26, 0x8a,
}};
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 */
FieldElement a, FieldElement b) {
FieldElement a,
FieldElement b) {
ECPoint hash;
memcpy(hash, PEDERSEN_SHIFT, sizeof(hash));
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, FIELD_ELEMENT_SIZE-1, 2);
accum_ec_mul(&hash, b + 1, FIELD_ELEMENT_SIZE - 1, 2);
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);
cx_ecfp_init_private_key(CX_CURVE_Stark256, privateKeyData, 32, &privateKey);
io_seproxyhal_io_heartbeat();
int signatureLength = cx_ecdsa_sign(&privateKey, CX_RND_RFC6979 | CX_LAST, CX_SHA256,
hash, sizeof(hash), signature, SIGNATURE_MAX_LEN, &info);
int signatureLength = cx_ecdsa_sign(&privateKey,
CX_RND_RFC6979 | CX_LAST,
CX_SHA256,
hash,
sizeof(hash),
signature,
SIGNATURE_MAX_LEN,
&info);
PRINTF("Stark signature %.*H\n", signatureLength, signature);
return signatureLength;
}
// ERC20Token(address)
static const uint8_t ERC20_SELECTOR[] = { 0xf4, 0x72, 0x61, 0xb0 };
static const uint8_t ERC20_SELECTOR[] = {0xf4, 0x72, 0x61, 0xb0};
// ETH()
static const uint8_t ETH_SELECTOR[] = { 0x83, 0x22, 0xff, 0xf2 };
static const uint8_t ETH_SELECTOR[] = {0x83, 0x22, 0xff, 0xf2};
// 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)
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)
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 MINTABLE_ASSET_ID_PREFIX[] = { 'M', 'I', 'N', 'T', 'A', 'B', 'L', 'E', ':', 0 };
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 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];
cx_keccak_init(sha3, 256);
if ((contractAddress != NULL) && (!allzeroes(contractAddress, 20))) {
const uint8_t *selector = NULL;
switch(quantumType) {
switch (quantumType) {
case STARK_QUANTUM_ERC20:
case STARK_QUANTUM_LEGACY:
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));
memmove(tmp, selector, 4);
memmove(tmp + 16, contractAddress, 20);
cx_hash((cx_hash_t*)sha3, 0, tmp, sizeof(tmp), NULL, 0);
}
else {
cx_hash((cx_hash_t *) sha3, 0, tmp, sizeof(tmp), NULL, 0);
} else {
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);
tmp[31] = 1;
PRINTF("compute_token_id quantum %.*H\n", 32, tmp);
cx_hash((cx_hash_t*)sha3, CX_LAST, tmp, 32, output, 32);
}
else {
cx_hash((cx_hash_t *) sha3, CX_LAST, tmp, 32, output, 32);
} else {
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) &&
(quantumType != STARK_QUANTUM_ETH) &&
(quantumType != STARK_QUANTUM_ERC20))) {
if (!assetTypeOnly &&
((quantumType != STARK_QUANTUM_LEGACY) && (quantumType != STARK_QUANTUM_ETH) &&
(quantumType != STARK_QUANTUM_ERC20))) {
const char *prefix = NULL;
output[0] &= 0x03;
cx_keccak_init(sha3, 256);
switch(quantumType) {
switch (quantumType) {
case STARK_QUANTUM_ERC721:
prefix = NFT_ASSET_ID_PREFIX;
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);
return;
}
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, CX_LAST, mintingBlob, 32, output, 32);
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, 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[1] = 0x00;
}
else {
} else {
output[0] &= 0x03;
}
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 "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 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 */
uint8_t *privateKeyData,
@@ -23,4 +33,3 @@ int stark_sign(uint8_t *signature, /* out */
FieldElement condition);
#endif

View File

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

File diff suppressed because it is too large Load Diff

View File

@@ -1,26 +1,26 @@
/*******************************************************************************
* Ledger Ethereum App
* (c) 2016-2019 Ledger
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
********************************************************************************/
* Ledger Ethereum App
* (c) 2016-2019 Ledger
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
********************************************************************************/
#ifndef _TOKENS_H_
#define _TOKENS_H_
#include <stdint.h>
#define MAX_TICKER_LEN 12 // 10 characters + ' ' + '\0'
#define MAX_TICKER_LEN 12 // 10 characters + ' ' + '\0'
typedef struct tokenDefinition_t {
#ifdef HAVE_CONTRACT_NAME_IN_DESCRIPTOR
@@ -33,7 +33,7 @@ typedef struct tokenDefinition_t {
#ifdef HAVE_TOKENS_EXTRA_LIST
#define NUM_TOKENS_EXTRA 4
#define NUM_TOKENS_EXTRA 4
extern tokenDefinition_t const TOKENS_EXTRA[NUM_TOKENS_EXTRA];
@@ -41,36 +41,36 @@ extern tokenDefinition_t const TOKENS_EXTRA[NUM_TOKENS_EXTRA];
#ifdef HAVE_TOKENS_LIST
#define NUM_TOKENS_AKROMA 0
#define NUM_TOKENS_ELLAISM 1
#define NUM_TOKENS_ETHEREUM 1102
#define NUM_TOKENS_AKROMA 0
#define NUM_TOKENS_ELLAISM 1
#define NUM_TOKENS_ETHEREUM 1102
#define NUM_TOKENS_ETHEREUM_CLASSIC 4
#define NUM_TOKENS_ETHERSOCIAL 0
#define NUM_TOKENS_ETHER1 0
#define NUM_TOKENS_PIRL 0
#define NUM_TOKENS_POA 0
#define NUM_TOKENS_RSK 0
#define NUM_TOKENS_UBIQ 6
#define NUM_TOKENS_EXPANSE 0
#define NUM_TOKENS_WANCHAIN 0
#define NUM_TOKENS_KUSD 0
#define NUM_TOKENS_MUSICOIN 0
#define NUM_TOKENS_CALLISTO 0
#define NUM_TOKENS_ETHERGEM 0
#define NUM_TOKENS_ATHEIOS 0
#define NUM_TOKENS_GOCHAIN 0
#define NUM_TOKENS_MIX 0
#define NUM_TOKENS_REOSC 0
#define NUM_TOKENS_HPB 0
#define NUM_TOKENS_TOMOCHAIN 0
#define NUM_TOKENS_TOBALABA 0
#define NUM_TOKENS_DEXON 0
#define NUM_TOKENS_VOLTA 0
#define NUM_TOKENS_EWC 0
#define NUM_TOKENS_ARTIS_SIGMA1 0
#define NUM_TOKENS_ARTIS_TAU1 0
#define NUM_TOKENS_WEBCHAIN 0
#define NUM_TOKENS_THUNDERCORE 0
#define NUM_TOKENS_ETHERSOCIAL 0
#define NUM_TOKENS_ETHER1 0
#define NUM_TOKENS_PIRL 0
#define NUM_TOKENS_POA 0
#define NUM_TOKENS_RSK 0
#define NUM_TOKENS_UBIQ 6
#define NUM_TOKENS_EXPANSE 0
#define NUM_TOKENS_WANCHAIN 0
#define NUM_TOKENS_KUSD 0
#define NUM_TOKENS_MUSICOIN 0
#define NUM_TOKENS_CALLISTO 0
#define NUM_TOKENS_ETHERGEM 0
#define NUM_TOKENS_ATHEIOS 0
#define NUM_TOKENS_GOCHAIN 0
#define NUM_TOKENS_MIX 0
#define NUM_TOKENS_REOSC 0
#define NUM_TOKENS_HPB 0
#define NUM_TOKENS_TOMOCHAIN 0
#define NUM_TOKENS_TOBALABA 0
#define NUM_TOKENS_DEXON 0
#define NUM_TOKENS_VOLTA 0
#define NUM_TOKENS_EWC 0
#define NUM_TOKENS_ARTIS_SIGMA1 0
#define NUM_TOKENS_ARTIS_TAU1 0
#define NUM_TOKENS_WEBCHAIN 0
#define NUM_TOKENS_THUNDERCORE 0
extern tokenDefinition_t const TOKENS_AKROMA[NUM_TOKENS_AKROMA];
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 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);
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);
//////////////////////////////////////////////////////////////////////
// clang-format off
UX_STEP_NOCB(
ux_idle_flow_1_step,
nn, //pnn,
@@ -37,16 +38,18 @@ UX_STEP_CB(
&C_icon_dashboard_x,
"Quit",
});
// clang-format on
UX_FLOW(ux_idle_flow,
&ux_idle_flow_1_step,
&ux_idle_flow_2_step,
&ux_idle_flow_3_step,
&ux_idle_flow_4_step,
FLOW_LOOP
);
&ux_idle_flow_1_step,
&ux_idle_flow_2_step,
&ux_idle_flow_3_step,
&ux_idle_flow_4_step,
FLOW_LOOP);
#if defined(TARGET_NANOS)
// clang-format off
UX_STEP_CB(
ux_settings_flow_1_step,
bnnn_paging,
@@ -99,28 +102,28 @@ UX_STEP_CB(
&C_icon_back_x,
"Back",
});
// clang-format on
UX_FLOW(ux_settings_flow,
&ux_settings_flow_1_step,
&ux_settings_flow_2_step,
&ux_settings_flow_3_step
);
&ux_settings_flow_1_step,
&ux_settings_flow_2_step,
&ux_settings_flow_3_step);
void display_settings() {
strcpy(strings.common.fullAddress, (N_storage.dataAllowed ? "Allowed" : "NOT Allowed"));
strcpy(strings.common.fullAddress + 20, (N_storage.contractDetails ? "Displayed" : "NOT Displayed"));
ux_flow_init(0, ux_settings_flow, NULL);
strcpy(strings.common.fullAddress, (N_storage.dataAllowed ? "Allowed" : "NOT Allowed"));
strcpy(strings.common.fullAddress + 20,
(N_storage.contractDetails ? "Displayed" : "NOT Displayed"));
ux_flow_init(0, ux_settings_flow, NULL);
}
void switch_settings_contract_data() {
uint8_t value = (N_storage.dataAllowed ? 0 : 1);
nvm_write((void*)&N_storage.dataAllowed, (void*)&value, sizeof(uint8_t));
display_settings();
uint8_t value = (N_storage.dataAllowed ? 0 : 1);
nvm_write((void*) &N_storage.dataAllowed, (void*) &value, sizeof(uint8_t));
display_settings();
}
void switch_settings_display_data() {
uint8_t value = (N_storage.contractDetails ? 0 : 1);
nvm_write((void*)&N_storage.contractDetails, (void*)&value, sizeof(uint8_t));
display_settings();
uint8_t value = (N_storage.contractDetails ? 0 : 1);
nvm_write((void*) &N_storage.contractDetails, (void*) &value, sizeof(uint8_t));
display_settings();
}

View File

@@ -2,55 +2,54 @@
#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
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

View File

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

View File

@@ -1,19 +1,19 @@
/*******************************************************************************
* Ledger Ethereum App
* (c) 2016-2019 Ledger
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
********************************************************************************/
* Ledger Ethereum App
* (c) 2016-2019 Ledger
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
********************************************************************************/
#ifndef _UTILS_H_
#define _UTILS_H_
@@ -22,15 +22,20 @@
#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);

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,19 +1,19 @@
/*******************************************************************************
* Ledger Ethereum App
* (c) 2016-2019 Ledger
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
********************************************************************************/
* Ledger Ethereum App
* (c) 2016-2019 Ledger
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
********************************************************************************/
// Adapted from https://github.com/calccrypto/uint256_t
@@ -25,14 +25,18 @@
#include "os.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 LOWER_P(x) x->elements[1]
#define UPPER(x) x.elements[0]
#define LOWER(x) x.elements[1]
#define UPPER(x) x.elements[0]
#define LOWER(x) x.elements[1]
void readu128BE(uint8_t *buffer, uint128_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 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);
bool tostring128(uint128_t *number, uint32_t base, char *out,
uint32_t outLength);
bool tostring256(uint256_t *number, uint32_t base, char *out,
uint32_t outLength);
bool tostring128(uint128_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_ */

View File

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

View File

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

View File

@@ -6,75 +6,81 @@
#include "ui_flow.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) {
uint8_t privateKeyData[32];
cx_ecfp_256_extended_private_key_t privateKey;
cx_ecfp_384_public_key_t publicKey;
uint8_t yFlag = 0;
uint8_t tmp[96];
uint8_t privateKeyData[32];
cx_ecfp_256_extended_private_key_t privateKey;
cx_ecfp_384_public_key_t publicKey;
uint8_t yFlag = 0;
uint8_t tmp[96];
io_seproxyhal_io_heartbeat();
os_perso_derive_eip2333(CX_CURVE_BLS12_381_G1, bip32Path, bip32PathLength, privateKeyData);
io_seproxyhal_io_heartbeat();
memset(tmp, 0, 48);
memmove(tmp + 16, privateKeyData, 32);
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);
explicit_bzero(tmp, 96);
explicit_bzero((void*)&privateKey, sizeof(cx_ecfp_256_extended_private_key_t));
tmp[47] = 2;
cx_math_mult(tmp, publicKey.W + 1 + 48, tmp, 48);
if (cx_math_cmp(tmp + 48, BLS12_381_FIELD_MODULUS, 48) > 0) {
yFlag = 0x20;
}
publicKey.W[1] &= 0x1f;
publicKey.W[1] |= 0x80 | yFlag;
memmove(out, publicKey.W + 1, 48);
io_seproxyhal_io_heartbeat();
os_perso_derive_eip2333(CX_CURVE_BLS12_381_G1, bip32Path, bip32PathLength, privateKeyData);
io_seproxyhal_io_heartbeat();
memset(tmp, 0, 48);
memmove(tmp + 16, privateKeyData, 32);
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);
explicit_bzero(tmp, 96);
explicit_bzero((void *) &privateKey, sizeof(cx_ecfp_256_extended_private_key_t));
tmp[47] = 2;
cx_math_mult(tmp, publicKey.W + 1 + 48, tmp, 48);
if (cx_math_cmp(tmp + 48, BLS12_381_FIELD_MODULUS, 48) > 0) {
yFlag = 0x20;
}
publicKey.W[1] &= 0x1f;
publicKey.W[1] |= 0x80 | yFlag;
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) {
UNUSED(dataLength);
uint32_t bip32Path[MAX_BIP32_PATH];
uint32_t i;
uint8_t bip32PathLength = *(dataBuffer++);
void handleGetEth2PublicKey(uint8_t p1,
uint8_t p2,
uint8_t *dataBuffer,
uint16_t dataLength,
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){
reset_app_context();
}
if ((bip32PathLength < 0x01) ||
(bip32PathLength > MAX_BIP32_PATH)) {
PRINTF("Invalid path\n");
THROW(0x6a80);
}
if ((p1 != P1_CONFIRM) && (p1 != P1_NON_CONFIRM)) {
THROW(0x6B00);
}
if (p2 != 0) {
THROW(0x6B00);
}
for (i = 0; i < bip32PathLength; i++) {
bip32Path[i] = U4BE(dataBuffer, 0);
dataBuffer += 4;
}
getEth2PublicKey(bip32Path, bip32PathLength, tmpCtx.publicKeyContext.publicKey.W);
if (!called_from_swap) {
reset_app_context();
}
if ((bip32PathLength < 0x01) || (bip32PathLength > MAX_BIP32_PATH)) {
PRINTF("Invalid path\n");
THROW(0x6a80);
}
if ((p1 != P1_CONFIRM) && (p1 != P1_NON_CONFIRM)) {
THROW(0x6B00);
}
if (p2 != 0) {
THROW(0x6B00);
}
for (i = 0; i < bip32PathLength; i++) {
bip32Path[i] = U4BE(dataBuffer, 0);
dataBuffer += 4;
}
getEth2PublicKey(bip32Path, bip32PathLength, tmpCtx.publicKeyContext.publicKey.W);
#ifndef NO_CONSENT
if (p1 == P1_NON_CONFIRM)
#endif // NO_CONSENT
{
*tx = set_result_get_eth2_publicKey();
THROW(0x9000);
}
if (p1 == P1_NON_CONFIRM)
#endif // NO_CONSENT
{
*tx = set_result_get_eth2_publicKey();
THROW(0x9000);
}
#ifndef NO_CONSENT
else
{
ux_flow_init(0, ux_display_public_eth2_flow, NULL);
else {
ux_flow_init(0, ux_display_public_eth2_flow, NULL);
*flags |= IO_ASYNCH_REPLY;
}
#endif // NO_CONSENT
*flags |= IO_ASYNCH_REPLY;
}
#endif // NO_CONSENT
}
#endif

View File

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

View File

@@ -10,4 +10,3 @@ uint32_t set_result_get_eth2_publicKey() {
}
#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);
// Display back the original UX
ui_idle();
return 0; // do not redraw the widget
return 0; // do not redraw the widget
}
#if 0

View File

@@ -4,9 +4,10 @@
#include "ui_callbacks.h"
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_display_public_eth2_flow_1_step,
pnn,
@@ -39,12 +40,12 @@ UX_STEP_CB(
&C_icon_crossmark,
"Reject",
});
// clang-format on
UX_FLOW(ux_display_public_eth2_flow,
&ux_display_public_eth2_flow_1_step,
&ux_display_public_eth2_flow_2_step,
&ux_display_public_eth2_flow_3_step,
&ux_display_public_eth2_flow_4_step
);
&ux_display_public_eth2_flow_1_step,
&ux_display_public_eth2_flow_2_step,
&ux_display_public_eth2_flow_3_step,
&ux_display_public_eth2_flow_4_step);
#endif

View File

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

View File

@@ -1,4 +1,3 @@
#include "shared_context.h"
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);
tx += 40;
if (tmpCtx.publicKeyContext.getChaincode) {
memmove(G_io_apdu_buffer + tx, tmpCtx.publicKeyContext.chainCode, 32);
tx += 32;
memmove(G_io_apdu_buffer + tx, tmpCtx.publicKeyContext.chainCode, 32);
tx += 32;
}
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);
// Display back the original UX
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) {
@@ -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);
// Display back the original UX
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 "ui_callbacks.h"
// clang-format off
UX_STEP_NOCB(
ux_display_public_flow_1_step,
pnn,
@@ -32,10 +33,10 @@ UX_STEP_CB(
&C_icon_crossmark,
"Reject",
});
// clang-format on
UX_FLOW(ux_display_public_flow,
&ux_display_public_flow_1_step,
&ux_display_public_flow_2_step,
&ux_display_public_flow_3_step,
&ux_display_public_flow_4_step
);
&ux_display_public_flow_1_step,
&ux_display_public_flow_2_step,
&ux_display_public_flow_3_step,
&ux_display_public_flow_4_step);

View File

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

View File

@@ -3,19 +3,23 @@
#include "shared_context.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 (dataLength != 4) {
THROW(0x6700);
}
if ((p1 != 0) || (p2 != 0)) {
THROW(0x6B00);
}
if ((p1 != 0) || (p2 != 0)) {
THROW(0x6B00);
}
eth2WithdrawalIndex = U4BE(dataBuffer, 0);
eth2WithdrawalIndex = U4BE(dataBuffer, 0);
THROW(0x9000);
THROW(0x9000);
}
#endif

View File

@@ -3,94 +3,113 @@
#include "utils.h"
#include "ui_flow.h"
static const char const SIGN_MAGIC[] = "\x19"
"Ethereum Signed Message:\n";
static const char const SIGN_MAGIC[] =
"\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) {
UNUSED(tx);
uint8_t hashMessage[32];
if (p1 == P1_FIRST) {
char tmp[11];
uint32_t index;
uint32_t base = 10;
uint8_t pos = 0;
uint32_t i;
if (dataLength < 1) {
PRINTF("Invalid data\n");
THROW(0x6a80);
}
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);
void handleSignPersonalMessage(uint8_t p1,
uint8_t p2,
uint8_t *workBuffer,
uint16_t dataLength,
unsigned int *flags,
unsigned int *tx) {
UNUSED(tx);
uint8_t hashMessage[32];
if (p1 == P1_FIRST) {
char tmp[11];
uint32_t index;
uint32_t base = 10;
uint8_t pos = 0;
uint32_t i;
if (dataLength < 1) {
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;
dataLength -= 4;
}
if (dataLength < 4) {
PRINTF("Invalid data\n");
THROW(0x6a80);
}
tmpCtx.messageSigningContext.remainingLength = U4BE(workBuffer, 0);
workBuffer += 4;
dataLength -= 4;
// Initialize message header + length
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) &&
// Initialize message header + length
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);
for (; index; index /= base) {
tmp[pos++] = '0' + ((tmpCtx.messageSigningContext.remainingLength / index) % base);
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';
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);
}
if (p2 != 0) {
THROW(0x6B00);
}
if ((p1 == P1_MORE) && (appState != APP_STATE_SIGNING_MESSAGE)) {
PRINTF("Signature not initialized\n");
THROW(0x6985);
}
if (dataLength > tmpCtx.messageSigningContext.remainingLength) {
THROW(0x6A80);
}
cx_hash((cx_hash_t *)&global_sha3, 0, workBuffer, dataLength, NULL, 0);
cx_hash((cx_hash_t *)&tmpContent.sha2, 0, workBuffer, dataLength, NULL, 0);
tmpCtx.messageSigningContext.remainingLength -= dataLength;
if (tmpCtx.messageSigningContext.remainingLength == 0) {
cx_hash((cx_hash_t *)&global_sha3, CX_LAST, workBuffer, 0, tmpCtx.messageSigningContext.hash, 32);
cx_hash((cx_hash_t *)&tmpContent.sha2, CX_LAST, workBuffer, 0, hashMessage, 32);
snprintf(strings.tmp.tmp, sizeof(strings.tmp.tmp), "%.*H", sizeof(hashMessage), hashMessage);
if (p2 != 0) {
THROW(0x6B00);
}
if ((p1 == P1_MORE) && (appState != APP_STATE_SIGNING_MESSAGE)) {
PRINTF("Signature not initialized\n");
THROW(0x6985);
}
if (dataLength > tmpCtx.messageSigningContext.remainingLength) {
THROW(0x6A80);
}
cx_hash((cx_hash_t *) &global_sha3, 0, workBuffer, dataLength, NULL, 0);
cx_hash((cx_hash_t *) &tmpContent.sha2, 0, workBuffer, dataLength, NULL, 0);
tmpCtx.messageSigningContext.remainingLength -= dataLength;
if (tmpCtx.messageSigningContext.remainingLength == 0) {
cx_hash((cx_hash_t *) &global_sha3,
CX_LAST,
workBuffer,
0,
tmpCtx.messageSigningContext.hash,
32);
cx_hash((cx_hash_t *) &tmpContent.sha2, CX_LAST, workBuffer, 0, hashMessage, 32);
snprintf(strings.tmp.tmp,
sizeof(strings.tmp.tmp),
"%.*H",
sizeof(hashMessage),
hashMessage);
#ifdef NO_CONSENT
io_seproxyhal_touch_signMessage_ok(NULL);
#else //NO_CONSENT
ux_flow_init(0, ux_sign_flow, NULL);
#endif // NO_CONSENT
io_seproxyhal_touch_signMessage_ok(NULL);
#else // NO_CONSENT
ux_flow_init(0, ux_sign_flow, NULL);
#endif // NO_CONSENT
*flags |= IO_ASYNCH_REPLY;
*flags |= IO_ASYNCH_REPLY;
} else {
THROW(0x9000);
}
} else {
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;
uint32_t tx = 0;
io_seproxyhal_io_heartbeat();
os_perso_derive_node_bip32(
CX_CURVE_256K1, tmpCtx.messageSigningContext.bip32Path,
tmpCtx.messageSigningContext.pathLength, privateKeyData, NULL);
os_perso_derive_node_bip32(CX_CURVE_256K1,
tmpCtx.messageSigningContext.bip32Path,
tmpCtx.messageSigningContext.pathLength,
privateKeyData,
NULL);
io_seproxyhal_io_heartbeat();
cx_ecfp_init_private_key(CX_CURVE_256K1, privateKeyData, 32, &privateKey);
explicit_bzero(privateKeyData, sizeof(privateKeyData));
unsigned int info = 0;
io_seproxyhal_io_heartbeat();
signatureLength =
cx_ecdsa_sign(&privateKey, CX_RND_RFC6979 | CX_LAST, CX_SHA256,
tmpCtx.messageSigningContext.hash,
sizeof(tmpCtx.messageSigningContext.hash), signature, sizeof(signature), &info);
signatureLength = cx_ecdsa_sign(&privateKey,
CX_RND_RFC6979 | CX_LAST,
CX_SHA256,
tmpCtx.messageSigningContext.hash,
sizeof(tmpCtx.messageSigningContext.hash),
signature,
sizeof(signature),
&info);
explicit_bzero(&privateKey, sizeof(privateKey));
G_io_apdu_buffer[0] = 27;
if (info & CX_ECCINFO_PARITY_ODD) {
G_io_apdu_buffer[0]++;
G_io_apdu_buffer[0]++;
}
if (info & CX_ECCINFO_xGTn) {
G_io_apdu_buffer[0] += 2;
G_io_apdu_buffer[0] += 2;
}
format_signature_out(signature);
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);
// Display back the original UX
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) {
@@ -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);
// Display back the original UX
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 "ui_callbacks.h"
// clang-format off
UX_STEP_NOCB(
ux_sign_flow_1_step,
pnn,
@@ -34,11 +35,10 @@ UX_STEP_CB(
"Cancel",
"signature",
});
// clang-format on
UX_FLOW(ux_sign_flow,
&ux_sign_flow_1_step,
&ux_sign_flow_2_step,
&ux_sign_flow_3_step,
&ux_sign_flow_4_step
);
&ux_sign_flow_1_step,
&ux_sign_flow_2_step,
&ux_sign_flow_3_step,
&ux_sign_flow_4_step);

View File

@@ -3,52 +3,58 @@
#include "utils.h"
#include "ui_flow.h"
static const char const SIGN_MAGIC[] = "\x19"
"Ethereum Signed Message:\n";
static const char const SIGN_MAGIC[] =
"\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) {
uint8_t i;
void handleSignEIP712Message(uint8_t p1,
uint8_t p2,
uint8_t *workBuffer,
uint16_t dataLength,
unsigned int *flags,
unsigned int *tx) {
uint8_t i;
UNUSED(tx);
if ((p1 != 00) || (p2 != 00)) {
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);
UNUSED(tx);
if ((p1 != 00) || (p2 != 00)) {
THROW(0x6B00);
}
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);
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);
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
io_seproxyhal_touch_signMessage_ok(NULL);
#else //NO_CONSENT
#else // NO_CONSENT
ux_flow_init(0, ux_sign_712_v0_flow, NULL);
#endif // NO_CONSENT
#endif // NO_CONSENT
*flags |= IO_ASYNCH_REPLY;
}

View File

@@ -1,7 +1,7 @@
#include "shared_context.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) {
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;
io_seproxyhal_io_heartbeat();
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, 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));
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,
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);
io_seproxyhal_io_heartbeat();
os_perso_derive_node_bip32(
CX_CURVE_256K1, tmpCtx.messageSigningContext712.bip32Path,
tmpCtx.messageSigningContext712.pathLength, privateKeyData, NULL);
os_perso_derive_node_bip32(CX_CURVE_256K1,
tmpCtx.messageSigningContext712.bip32Path,
tmpCtx.messageSigningContext712.pathLength,
privateKeyData,
NULL);
io_seproxyhal_io_heartbeat();
cx_ecfp_init_private_key(CX_CURVE_256K1, privateKeyData, 32, &privateKey);
explicit_bzero(privateKeyData, sizeof(privateKeyData));
unsigned int info = 0;
io_seproxyhal_io_heartbeat();
signatureLength =
cx_ecdsa_sign(&privateKey, CX_RND_RFC6979 | CX_LAST, CX_SHA256,
hash,
sizeof(hash), signature, sizeof(signature), &info);
signatureLength = cx_ecdsa_sign(&privateKey,
CX_RND_RFC6979 | CX_LAST,
CX_SHA256,
hash,
sizeof(hash),
signature,
sizeof(signature),
&info);
explicit_bzero(&privateKey, sizeof(privateKey));
G_io_apdu_buffer[0] = 27;
if (info & CX_ECCINFO_PARITY_ODD) {
G_io_apdu_buffer[0]++;
G_io_apdu_buffer[0]++;
}
if (info & CX_ECCINFO_xGTn) {
G_io_apdu_buffer[0] += 2;
G_io_apdu_buffer[0] += 2;
}
format_signature_out(signature);
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);
// Display back the original UX
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) {
@@ -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);
// Display back the original UX
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"
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() {
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_sign_712_v0_flow_1_step,
pnn,
@@ -51,12 +52,11 @@ UX_STEP_CB(
"Cancel",
"signature",
});
// clang-format on
UX_FLOW(ux_sign_712_v0_flow,
&ux_sign_712_v0_flow_1_step,
&ux_sign_712_v0_flow_2_step,
&ux_sign_712_v0_flow_3_step,
&ux_sign_712_v0_flow_4_step,
&ux_sign_712_v0_flow_5_step
);
&ux_sign_712_v0_flow_1_step,
&ux_sign_712_v0_flow_2_step,
&ux_sign_712_v0_flow_3_step,
&ux_sign_712_v0_flow_4_step,
&ux_sign_712_v0_flow_5_step);

View File

@@ -3,74 +3,79 @@
#include "ui_flow.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) {
UNUSED(tx);
parserStatus_e txResult;
uint32_t i;
if (p1 == P1_FIRST) {
if (dataLength < 1) {
PRINTF("Invalid data\n");
THROW(0x6a80);
void handleSign(uint8_t p1,
uint8_t p2,
uint8_t *workBuffer,
uint16_t dataLength,
unsigned int *flags,
unsigned int *tx) {
UNUSED(tx);
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) {
reset_app_context();
if (p2 != 0) {
THROW(0x6B00);
}
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);
if ((p1 == P1_MORE) && (appState != APP_STATE_SIGNING_TX)) {
PRINTF("Signature not initialized\n");
THROW(0x6985);
}
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;
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);
}
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) {
finalizeParsing(false);
}
if (txResult == USTREAM_FINISHED) {
finalizeParsing(false);
}
*flags |= IO_ASYNCH_REPLY;
*flags |= IO_ASYNCH_REPLY;
}

View File

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

View File

@@ -11,7 +11,7 @@
uint32_t splitBinaryParameterPart(char *result, uint8_t *parameter) {
uint32_t i;
for (i=0; i<8; i++) {
for (i = 0; i < 8; i++) {
if (parameter[i] != 0x00) {
break;
}
@@ -21,16 +21,14 @@ uint32_t splitBinaryParameterPart(char *result, uint8_t *parameter) {
result[1] = '0';
result[2] = '\0';
return 2;
}
else {
} else {
array_hexstr(result, parameter + i, 8 - i);
return ((8 - i) * 2);
}
}
customStatus_e customProcessor(txContext_t *context) {
if ((context->currentField == TX_RLP_DATA) &&
(context->currentFieldLength != 0)) {
if ((context->currentField == TX_RLP_DATA) && (context->currentFieldLength != 0)) {
dataPresent = true;
// If handling a new contract rather than a function call, abort immediately
if (tmpContent.txContent.destinationLength == 0) {
@@ -38,320 +36,341 @@ customStatus_e customProcessor(txContext_t *context) {
}
if (context->currentFieldPos == 0) {
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) {
PRINTF("Missing function selector\n");
return CUSTOM_FAULT;
}
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);
if (dataContext.tokenContext.pluginAvailable) {
dataContext.tokenContext.fieldIndex = 0;
dataContext.tokenContext.fieldOffset = 0;
copyTxData(context, NULL, 4);
if (context->currentFieldLength == 4) {
return CUSTOM_NOT_HANDLED;
}
dataContext.tokenContext.fieldIndex = 0;
dataContext.tokenContext.fieldOffset = 0;
copyTxData(context, NULL, 4);
if (context->currentFieldLength == 4) {
return CUSTOM_NOT_HANDLED;
}
}
}
uint32_t blockSize;
uint32_t copySize;
uint32_t fieldPos = context->currentFieldPos;
if (fieldPos == 0) { // not reached if a plugin is available
if (!N_storage.dataAllowed) {
uint32_t blockSize;
uint32_t copySize;
uint32_t fieldPos = context->currentFieldPos;
if (fieldPos == 0) { // not reached if a plugin is available
if (!N_storage.dataAllowed) {
PRINTF("Data field forbidden\n");
return CUSTOM_FAULT;
}
if (!N_storage.contractDetails) {
}
if (!N_storage.contractDetails) {
return CUSTOM_NOT_HANDLED;
}
dataContext.tokenContext.fieldIndex = 0;
dataContext.tokenContext.fieldOffset = 0;
blockSize = 4;
}
else {
if (!N_storage.contractDetails && !dataContext.tokenContext.pluginAvailable) {
}
dataContext.tokenContext.fieldIndex = 0;
dataContext.tokenContext.fieldOffset = 0;
blockSize = 4;
} else {
if (!N_storage.contractDetails && !dataContext.tokenContext.pluginAvailable) {
return CUSTOM_NOT_HANDLED;
}
blockSize = 32 - (dataContext.tokenContext.fieldOffset % 32);
}
}
blockSize = 32 - (dataContext.tokenContext.fieldOffset % 32);
}
// Sanity check
if ((context->currentFieldLength - fieldPos) < blockSize) {
PRINTF("Unconsistent data\n");
return CUSTOM_FAULT;
}
// Sanity check
if ((context->currentFieldLength - fieldPos) < blockSize) {
PRINTF("Unconsistent data\n");
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,
dataContext.tokenContext.data + dataContext.tokenContext.fieldOffset,
copySize);
copyTxData(context,
dataContext.tokenContext.data + dataContext.tokenContext.fieldOffset,
copySize);
if (context->currentFieldPos == context->currentFieldLength) {
context->currentField++;
context->processingField = false;
}
if (context->currentFieldPos == context->currentFieldLength) {
context->currentField++;
context->processingField = false;
}
dataContext.tokenContext.fieldOffset += copySize;
dataContext.tokenContext.fieldOffset += copySize;
if (copySize == blockSize) {
// Can process or display
if (dataContext.tokenContext.pluginAvailable) {
if (copySize == blockSize) {
// Can process or display
if (dataContext.tokenContext.pluginAvailable) {
ethPluginProvideParameter_t pluginProvideParameter;
eth_plugin_prepare_provide_parameter(&pluginProvideParameter,
dataContext.tokenContext.data,
dataContext.tokenContext.fieldIndex * 32 + 4);
if (!eth_plugin_call(NULL, ETH_PLUGIN_PROVIDE_PARAMETER, (void*)&pluginProvideParameter)) {
PRINTF("Plugin parameter call failed\n");
return CUSTOM_FAULT;
eth_plugin_prepare_provide_parameter(&pluginProvideParameter,
dataContext.tokenContext.data,
dataContext.tokenContext.fieldIndex * 32 + 4);
if (!eth_plugin_call(NULL,
ETH_PLUGIN_PROVIDE_PARAMETER,
(void *) &pluginProvideParameter)) {
PRINTF("Plugin parameter call failed\n");
return CUSTOM_FAULT;
}
dataContext.tokenContext.fieldIndex++;
dataContext.tokenContext.fieldOffset = 0;
return CUSTOM_HANDLED;
}
}
if (fieldPos != 0) {
dataContext.tokenContext.fieldIndex++;
}
dataContext.tokenContext.fieldOffset = 0;
if (fieldPos == 0) {
array_hexstr(strings.tmp.tmp, dataContext.tokenContext.data, 4);
ux_flow_init(0, ux_confirm_selector_flow, NULL);
}
else {
uint32_t offset = 0;
uint32_t i;
snprintf(strings.tmp.tmp2, sizeof(strings.tmp.tmp2), "Field %d", dataContext.tokenContext.fieldIndex);
for (i=0; i<4; i++) {
offset += splitBinaryParameterPart(strings.tmp.tmp + offset, dataContext.tokenContext.data + 8 * i);
if (i != 3) {
strings.tmp.tmp[offset++] = ':';
}
}
ux_flow_init(0, ux_confirm_parameter_flow, NULL);
}
}
else {
return CUSTOM_HANDLED;
}
if (fieldPos != 0) {
dataContext.tokenContext.fieldIndex++;
}
dataContext.tokenContext.fieldOffset = 0;
if (fieldPos == 0) {
array_hexstr(strings.tmp.tmp, dataContext.tokenContext.data, 4);
ux_flow_init(0, ux_confirm_selector_flow, NULL);
} else {
uint32_t offset = 0;
uint32_t i;
snprintf(strings.tmp.tmp2,
sizeof(strings.tmp.tmp2),
"Field %d",
dataContext.tokenContext.fieldIndex);
for (i = 0; i < 4; i++) {
offset += splitBinaryParameterPart(strings.tmp.tmp + offset,
dataContext.tokenContext.data + 8 * i);
if (i != 3) {
strings.tmp.tmp[offset++] = ':';
}
}
ux_flow_init(0, ux_confirm_parameter_flow, NULL);
}
} else {
return CUSTOM_HANDLED;
}
return CUSTOM_SUSPENDED;
return CUSTOM_SUSPENDED;
}
return CUSTOM_NOT_HANDLED;
}
void to_uppercase(char* str, unsigned char size){
for (unsigned char i = 0; i < size && str[i] != 0; i++)
{
void to_uppercase(char *str, unsigned char size) {
for (unsigned char i = 0; i < size && str[i] != 0; i++) {
str[i] = str[i] >= 'a' ? str[i] - ('a' - 'A') : str[i];
}
}
void compareOrCopy(char* preapproved_string, char* parsed_string, bool silent_mode){
if(silent_mode){
/* ETH address are not fundamentally case sensitive but might
have some for checksum purpose, so let's get rid of these diffs */
to_uppercase(preapproved_string, strlen(preapproved_string));
to_uppercase(parsed_string, strlen(parsed_string));
if(memcmp(preapproved_string, parsed_string, strlen(preapproved_string))){
THROW(ERR_SILENT_MODE_CHECK_FAILED);
void compareOrCopy(char *preapproved_string, char *parsed_string, bool silent_mode) {
if (silent_mode) {
/* ETH address are not fundamentally case sensitive but might
have some for checksum purpose, so let's get rid of these diffs */
to_uppercase(preapproved_string, strlen(preapproved_string));
to_uppercase(parsed_string, strlen(parsed_string));
if (memcmp(preapproved_string, parsed_string, strlen(preapproved_string))) {
THROW(ERR_SILENT_MODE_CHECK_FAILED);
}
} else {
strcpy(preapproved_string, parsed_string);
}
}
else{
strcpy(preapproved_string, parsed_string);
}
}
void reportFinalizeError(bool direct) {
reset_app_context();
if (direct) {
THROW(0x6A80);
}
else {
io_seproxyhal_send_status(0x6A80);
ui_idle();
}
reset_app_context();
if (direct) {
THROW(0x6A80);
} else {
io_seproxyhal_send_status(0x6A80);
ui_idle();
}
}
void computeFees(char *displayBuffer, uint32_t displayBufferSize) {
uint256_t gasPrice, startGas, uint256;
uint8_t *feeTicker = (uint8_t *)PIC(chainConfig->coinName);
uint8_t tickerOffset = 0;
uint32_t i;
uint256_t gasPrice, startGas, uint256;
uint8_t *feeTicker = (uint8_t *) PIC(chainConfig->coinName);
uint8_t tickerOffset = 0;
uint32_t i;
PRINTF("Max fee\n");
PRINTF("Gasprice %.*H\n", tmpContent.txContent.gasprice.length, tmpContent.txContent.gasprice.value);
PRINTF("Startgas %.*H\n", tmpContent.txContent.startgas.length, tmpContent.txContent.startgas.value);
convertUint256BE(tmpContent.txContent.gasprice.value, tmpContent.txContent.gasprice.length, &gasPrice);
convertUint256BE(tmpContent.txContent.startgas.value, tmpContent.txContent.startgas.length, &startGas);
mul256(&gasPrice, &startGas, &uint256);
tostring256(&uint256, 10, (char *)(G_io_apdu_buffer + 100), 100);
i = 0;
while (G_io_apdu_buffer[100 + i]) {
i++;
}
adjustDecimals((char *)(G_io_apdu_buffer + 100), i, (char *)G_io_apdu_buffer, 100, 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';
PRINTF("Max fee\n");
PRINTF("Gasprice %.*H\n",
tmpContent.txContent.gasprice.length,
tmpContent.txContent.gasprice.value);
PRINTF("Startgas %.*H\n",
tmpContent.txContent.startgas.length,
tmpContent.txContent.startgas.value);
convertUint256BE(tmpContent.txContent.gasprice.value,
tmpContent.txContent.gasprice.length,
&gasPrice);
convertUint256BE(tmpContent.txContent.startgas.value,
tmpContent.txContent.startgas.length,
&startGas);
mul256(&gasPrice, &startGas, &uint256);
tostring256(&uint256, 10, (char *) (G_io_apdu_buffer + 100), 100);
i = 0;
while (G_io_apdu_buffer[100 + i]) {
i++;
}
adjustDecimals((char *) (G_io_apdu_buffer + 100),
i,
(char *) G_io_apdu_buffer,
100,
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) {
char displayBuffer[50];
uint8_t decimals = WEI_TO_ETHER;
uint8_t *ticker = (uint8_t *)PIC(chainConfig->coinName);
ethPluginFinalize_t pluginFinalize;
tokenDefinition_t *token1 = NULL, *token2 = NULL;
bool genericUI = true;
void finalizeParsing(bool direct) {
char displayBuffer[50];
uint8_t decimals = WEI_TO_ETHER;
uint8_t *ticker = (uint8_t *) PIC(chainConfig->coinName);
ethPluginFinalize_t pluginFinalize;
tokenDefinition_t *token1 = NULL, *token2 = NULL;
bool genericUI = true;
// Verify the chain
if (chainConfig->chainId != 0) {
uint32_t v = getV(&tmpContent.txContent);
if (chainConfig->chainId != v) {
reset_app_context();
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");
// Verify the chain
if (chainConfig->chainId != 0) {
uint32_t v = getV(&tmpContent.txContent);
if (chainConfig->chainId != v) {
reset_app_context();
PRINTF("Invalid chainId %d expected %d\n", v, chainConfig->chainId);
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;
}
}
}
// 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);
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;
}
}
}
}
else {
genericUI = true;
// 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);
}
}
if (dataPresent && !N_storage.dataAllowed) {
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;
bool no_consent = false;
no_consent = called_from_swap;
no_consent = called_from_swap;
#ifdef NO_CONSENT
no_consent = true;
#endif // NO_CONSENT
no_consent = true;
#endif // NO_CONSENT
if(no_consent){
io_seproxyhal_touch_tx_ok(NULL);
}
else{
if (genericUI) {
ux_flow_init(0,
((dataPresent && !N_storage.contractDetails) ? ux_approval_tx_data_warning_flow : ux_approval_tx_flow),
NULL);
if (no_consent) {
io_seproxyhal_touch_tx_ok(NULL);
} else {
if (genericUI) {
ux_flow_init(
0,
((dataPresent && !N_storage.contractDetails) ? ux_approval_tx_data_warning_flow
: ux_approval_tx_flow),
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 v = getV(&tmpContent.txContent);
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,
privateKeyData, NULL);
cx_ecfp_init_private_key(CX_CURVE_256K1, privateKeyData, 32,
&privateKey);
privateKeyData,
NULL);
cx_ecfp_init_private_key(CX_CURVE_256K1, privateKeyData, 32, &privateKey);
explicit_bzero(privateKeyData, sizeof(privateKeyData));
unsigned int info = 0;
io_seproxyhal_io_heartbeat();
signatureLength =
cx_ecdsa_sign(&privateKey, CX_RND_RFC6979 | CX_LAST, CX_SHA256,
tmpCtx.transactionContext.hash,
sizeof(tmpCtx.transactionContext.hash), signature, sizeof(signature), &info);
signatureLength = cx_ecdsa_sign(&privateKey,
CX_RND_RFC6979 | CX_LAST,
CX_SHA256,
tmpCtx.transactionContext.hash,
sizeof(tmpCtx.transactionContext.hash),
signature,
sizeof(signature),
&info);
explicit_bzero(&privateKey, sizeof(privateKey));
// Parity is present in the sequence tag in the legacy API
if (tmpContent.txContent.vLength == 0) {
// Legacy API
G_io_apdu_buffer[0] = 27;
}
else {
// New API
// Note that this is wrong for a large v, but the client can always recover
G_io_apdu_buffer[0] = (v * 2) + 35;
// Legacy API
G_io_apdu_buffer[0] = 27;
} else {
// New API
// Note that this is wrong for a large v, but the client can always recover
G_io_apdu_buffer[0] = (v * 2) + 35;
}
if (info & CX_ECCINFO_PARITY_ODD) {
G_io_apdu_buffer[0]++;
G_io_apdu_buffer[0]++;
}
if (info & CX_ECCINFO_xGTn) {
G_io_apdu_buffer[0] += 2;
G_io_apdu_buffer[0] += 2;
}
format_signature_out(signature);
tx = 65;
@@ -45,13 +49,13 @@ unsigned int io_seproxyhal_touch_tx_ok(const bagl_element_t *e) {
G_io_apdu_buffer[tx++] = 0x00;
// Send back the response, do not restart the event loop
io_exchange(CHANNEL_APDU | IO_RETURN_AFTER_TX, tx);
if(called_from_swap){
if (called_from_swap) {
os_sched_exit(0);
}
reset_app_context();
// Display back the original UX
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) {
@@ -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);
// Display back the original UX
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) {
parserStatus_e txResult = USTREAM_FINISHED;
txResult = continueTx(&txContext);
switch (txResult) {
case USTREAM_SUSPENDED:
break;
case USTREAM_FINISHED:
break;
case USTREAM_PROCESSING:
io_seproxyhal_send_status(0x9000);
ui_idle();
break;
case USTREAM_FAULT:
reset_app_context();
io_seproxyhal_send_status(0x6A80);
ui_idle();
break;
default:
PRINTF("Unexpected parser status\n");
reset_app_context();
io_seproxyhal_send_status(0x6A80);
ui_idle();
case USTREAM_SUSPENDED:
break;
case USTREAM_FINISHED:
break;
case USTREAM_PROCESSING:
io_seproxyhal_send_status(0x9000);
ui_idle();
break;
case USTREAM_FAULT:
reset_app_context();
io_seproxyhal_send_status(0x6A80);
ui_idle();
break;
default:
PRINTF("Unexpected parser status\n");
reset_app_context();
io_seproxyhal_send_status(0x6A80);
ui_idle();
}
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);
// Display back the original UX
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 "ui_callbacks.h"
// clang-format off
UX_STEP_NOCB(
ux_confirm_selector_flow_1_step,
pnn,
@@ -33,15 +34,16 @@ UX_STEP_CB(
&C_icon_crossmark,
"Reject",
});
// clang-format on
UX_FLOW(ux_confirm_selector_flow,
&ux_confirm_selector_flow_1_step,
&ux_confirm_selector_flow_2_step,
&ux_confirm_selector_flow_3_step,
&ux_confirm_selector_flow_4_step
);
UX_FLOW(ux_confirm_selector_flow,
&ux_confirm_selector_flow_1_step,
&ux_confirm_selector_flow_2_step,
&ux_confirm_selector_flow_3_step,
&ux_confirm_selector_flow_4_step);
//////////////////////////////////////////////////////////////////////
// clang-format off
UX_STEP_NOCB(
ux_confirm_parameter_flow_1_step,
pnn,
@@ -73,15 +75,16 @@ UX_STEP_CB(
&C_icon_crossmark,
"Reject",
});
// clang-format on
UX_FLOW(ux_confirm_parameter_flow,
&ux_confirm_parameter_flow_1_step,
&ux_confirm_parameter_flow_2_step,
&ux_confirm_parameter_flow_3_step,
&ux_confirm_parameter_flow_4_step
);
&ux_confirm_parameter_flow_1_step,
&ux_confirm_parameter_flow_2_step,
&ux_confirm_parameter_flow_3_step,
&ux_confirm_parameter_flow_4_step);
//////////////////////////////////////////////////////////////////////
// clang-format off
UX_STEP_NOCB(ux_approval_tx_1_step,
pnn,
{
@@ -135,23 +138,21 @@ UX_STEP_NOCB(ux_approval_tx_data_warning_step,
"Data",
"Present",
});
// clang-format on
UX_FLOW(ux_approval_tx_flow,
&ux_approval_tx_1_step,
&ux_approval_tx_2_step,
&ux_approval_tx_3_step,
&ux_approval_tx_4_step,
&ux_approval_tx_5_step,
&ux_approval_tx_6_step
);
&ux_approval_tx_1_step,
&ux_approval_tx_2_step,
&ux_approval_tx_3_step,
&ux_approval_tx_4_step,
&ux_approval_tx_5_step,
&ux_approval_tx_6_step);
UX_FLOW(ux_approval_tx_data_warning_flow,
&ux_approval_tx_1_step,
&ux_approval_tx_data_warning_step,
&ux_approval_tx_2_step,
&ux_approval_tx_3_step,
&ux_approval_tx_4_step,
&ux_approval_tx_5_step,
&ux_approval_tx_6_step
);
&ux_approval_tx_1_step,
&ux_approval_tx_data_warning_step,
&ux_approval_tx_2_step,
&ux_approval_tx_3_step,
&ux_approval_tx_4_step,
&ux_approval_tx_5_step,
&ux_approval_tx_6_step);

View File

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

View File

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

View File

@@ -11,5 +11,3 @@ uint32_t set_result_get_stark_publicKey() {
}
#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);
// Display back the original UX
ui_idle();
return 0; // do not redraw the widget
return 0; // do not redraw the widget
}
#endif

View File

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

View File

@@ -4,56 +4,61 @@
#include "apdu_constants.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) {
size_t i = 0;
uint8_t expectedDataSize = 20 + 32;
uint8_t addressZero = 0;
tokenDefinition_t *currentToken = NULL;
if (appState != APP_STATE_IDLE) {
reset_app_context();
}
switch(p1) {
case STARK_QUANTUM_LEGACY:
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) {
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;
}
void handleStarkwareProvideQuantum(uint8_t p1,
uint8_t p2,
uint8_t *dataBuffer,
uint16_t dataLength,
unsigned int *flags,
unsigned int *tx) {
size_t i = 0;
uint8_t expectedDataSize = 20 + 32;
uint8_t addressZero = 0;
tokenDefinition_t *currentToken = NULL;
if (appState != APP_STATE_IDLE) {
reset_app_context();
}
if (i == MAX_TOKEN) {
PRINTF("Associated token not found\n");
THROW(0x6A80);
switch (p1) {
case STARK_QUANTUM_LEGACY:
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);
}
}
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);
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) {
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

View File

@@ -7,208 +7,253 @@
#include "poorstream.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
void handleStarkwareSignMessage(uint8_t p1, uint8_t p2, uint8_t *dataBuffer, uint16_t dataLength, unsigned int *flags, unsigned int *tx) {
uint8_t privateKeyData[32];
uint32_t i;
uint8_t bip32PathLength = *(dataBuffer);
uint8_t offset = 1;
cx_ecfp_private_key_t privateKey;
poorstream_t bitstream;
bool selfTransfer = false;
uint8_t order = 1;
uint8_t protocol = 2;
uint8_t preOffset, postOffset;
uint8_t zeroTest;
// Initial checks
if (appState != APP_STATE_IDLE) {
reset_app_context();
}
if ((bip32PathLength < 0x01) ||
(bip32PathLength > MAX_BIP32_PATH)) {
PRINTF("Invalid path\n");
THROW(0x6a80);
}
switch(p1) {
case P1_STARK_ORDER:
protocol = 1;
break;
case P1_STARK_TRANSFER:
protocol = 1;
order = 0;
break;
case P1_STARK_ORDER_V2:
break;
case P1_STARK_TRANSFER_V2:
case P1_STARK_CONDITIONAL_TRANSFER:
order = 0;
break;
default:
THROW(0x6B00);
}
postOffset = (protocol == 2 ? 1 + 32 : 0);
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);
}
zeroTest = allzeroes(dataBuffer + preOffset, 20);
if (zeroTest && (protocol == 2) && (dataBuffer[0] != STARK_QUANTUM_ETH)) {
PRINTF("stark - unexpected quantum descriptor type for null first address %d\n", 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);
void handleStarkwareSignMessage(uint8_t p1,
uint8_t p2,
uint8_t *dataBuffer,
uint16_t dataLength,
unsigned int *flags,
unsigned int *tx) {
uint8_t privateKeyData[32];
uint32_t i;
uint8_t bip32PathLength = *(dataBuffer);
uint8_t offset = 1;
cx_ecfp_private_key_t privateKey;
poorstream_t bitstream;
bool selfTransfer = false;
uint8_t order = 1;
uint8_t protocol = 2;
uint8_t preOffset, postOffset;
uint8_t zeroTest;
// Initial checks
if (appState != APP_STATE_IDLE) {
reset_app_context();
}
if (!zeroTest && getKnownToken(dataBuffer + 20 + 32 + postOffset + preOffset) == NULL) {
PRINTF("stark - cannot process unknown token %.*H", 20, dataBuffer + 20 + 32 + postOffset + preOffset);
THROW(0x6A80);
if ((bip32PathLength < 0x01) || (bip32PathLength > MAX_BIP32_PATH)) {
PRINTF("Invalid path\n");
THROW(0x6a80);
}
}
// Prepare the Stark parameters
io_seproxyhal_io_heartbeat();
compute_token_id(&global_sha3, dataBuffer + preOffset,
(protocol == 2 ? dataBuffer[0] : STARK_QUANTUM_LEGACY),
dataBuffer + preOffset + 20,
(protocol == 2 ? dataBuffer + 1 + 20 + 32 : NULL), false, dataContext.starkContext.w1);
if (order) {
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_write_bits(&bitstream, 0, 11); // padding
poorstream_write_bits(&bitstream,
(p1 == P1_STARK_CONDITIONAL_TRANSFER ? STARK_CONDITIONAL_TRANSFER_TYPE :
order ? STARK_ORDER_TYPE : STARK_TRANSFER_TYPE), 4);
poorstream_write_bits(&bitstream, U4BE(dataBuffer, offset), 31);
poorstream_write_bits(&bitstream, U4BE(dataBuffer, offset + 4), 31);
poorstream_write_bits(&bitstream, U8BE(dataBuffer, offset + 4 + 4), 63);
if (order) {
poorstream_write_bits(&bitstream, U8BE(dataBuffer, offset + 4 + 4 + 8), 63);
offset += 4 + 4 + 8 + 8;
}
else {
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);
switch (p1) {
case P1_STARK_ORDER:
protocol = 1;
break;
case P1_STARK_TRANSFER:
protocol = 1;
order = 0;
break;
case P1_STARK_ORDER_V2:
break;
case P1_STARK_TRANSFER_V2:
case P1_STARK_CONDITIONAL_TRANSFER:
order = 0;
break;
default:
THROW(0x6B00);
}
}
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);
postOffset = (protocol == 2 ? 1 + 32 : 0);
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);
}
}
else {
ux_flow_init(0, (dataContext.starkContext.conditional ? ux_stark_transfer_conditional_flow :
ux_stark_transfer_flow), NULL);
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);
}
}
*flags |= IO_ASYNCH_REPLY;
zeroTest = allzeroes(dataBuffer + preOffset, 20);
if (zeroTest && (protocol == 2) && (dataBuffer[0] != STARK_QUANTUM_ETH)) {
PRINTF("stark - unexpected quantum descriptor type for null first address %d\n",
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) {
PRINTF("stark - cannot process unknown token %.*H",
20,
dataBuffer + 20 + 32 + postOffset + preOffset);
THROW(0x6A80);
}
}
// Prepare the Stark parameters
io_seproxyhal_io_heartbeat();
compute_token_id(&global_sha3,
dataBuffer + preOffset,
(protocol == 2 ? dataBuffer[0] : STARK_QUANTUM_LEGACY),
dataBuffer + preOffset + 20,
(protocol == 2 ? dataBuffer + 1 + 20 + 32 : NULL),
false,
dataContext.starkContext.w1);
if (order) {
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_write_bits(&bitstream, 0, 11); // padding
poorstream_write_bits(
&bitstream,
(p1 == P1_STARK_CONDITIONAL_TRANSFER ? STARK_CONDITIONAL_TRANSFER_TYPE
: order ? STARK_ORDER_TYPE : STARK_TRANSFER_TYPE),
4);
poorstream_write_bits(&bitstream, U4BE(dataBuffer, offset), 31);
poorstream_write_bits(&bitstream, U4BE(dataBuffer, offset + 4), 31);
poorstream_write_bits(&bitstream, U8BE(dataBuffer, offset + 4 + 4), 63);
if (order) {
poorstream_write_bits(&bitstream, U8BE(dataBuffer, offset + 4 + 4 + 8), 63);
offset += 4 + 4 + 8 + 8;
} else {
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);
}
}
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

View File

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

View File

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

View File

@@ -6,49 +6,53 @@
#include "ui_flow.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) {
uint32_t i;
uint8_t privateKeyData[32];
cx_ecfp_public_key_t publicKey;
cx_ecfp_private_key_t privateKey;
uint8_t bip32PathLength = *(dataBuffer);
uint8_t offset = 1;
// Initial checks
if (appState != APP_STATE_IDLE) {
reset_app_context();
}
if ((bip32PathLength < 0x01) ||
(bip32PathLength > MAX_BIP32_PATH)) {
PRINTF("Invalid path\n");
THROW(0x6a80);
}
if ((p1 != 0) || (p2 != 0)) {
THROW(0x6B00);
}
void handleStarkwareUnsafeSign(uint8_t p1,
uint8_t p2,
uint8_t *dataBuffer,
uint16_t dataLength,
unsigned int *flags,
unsigned int *tx) {
uint32_t i;
uint8_t privateKeyData[32];
cx_ecfp_public_key_t publicKey;
cx_ecfp_private_key_t privateKey;
uint8_t bip32PathLength = *(dataBuffer);
uint8_t offset = 1;
// Initial checks
if (appState != APP_STATE_IDLE) {
reset_app_context();
}
if ((bip32PathLength < 0x01) || (bip32PathLength > MAX_BIP32_PATH)) {
PRINTF("Invalid path\n");
THROW(0x6a80);
}
if ((p1 != 0) || (p2 != 0)) {
THROW(0x6B00);
}
if (dataLength != 32 + 4 * bip32PathLength + 1) {
THROW(0x6700);
}
if (dataLength != 32 + 4 * bip32PathLength + 1) {
THROW(0x6700);
}
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;
}
memmove(dataContext.starkContext.w2, dataBuffer + offset, 32);
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();
memmove(dataContext.starkContext.w1, publicKey.W + 1, 32);
ux_flow_init(0, ux_stark_unsafe_sign_flow, NULL);
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;
}
memmove(dataContext.starkContext.w2, dataBuffer + offset, 32);
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();
memmove(dataContext.starkContext.w1, publicKey.W + 1, 32);
ux_flow_init(0, ux_stark_unsafe_sign_flow, NULL);
*flags |= IO_ASYNCH_REPLY;
*flags |= IO_ASYNCH_REPLY;
}
#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;
uint32_t tx = 0;
io_seproxyhal_io_heartbeat();
starkDerivePrivateKey(tmpCtx.transactionContext.bip32Path, tmpCtx.transactionContext.pathLength, privateKeyData);
starkDerivePrivateKey(tmpCtx.transactionContext.bip32Path,
tmpCtx.transactionContext.pathLength,
privateKeyData);
io_seproxyhal_io_heartbeat();
cx_ecfp_init_private_key(CX_CURVE_Stark256, privateKeyData, 32, &privateKey);
cx_ecdsa_sign(&privateKey, CX_RND_RFC6979 | CX_LAST, CX_SHA256,
dataContext.starkContext.w2, sizeof(dataContext.starkContext.w2), signature, sizeof(signature), &info);
cx_ecdsa_sign(&privateKey,
CX_RND_RFC6979 | CX_LAST,
CX_SHA256,
dataContext.starkContext.w2,
sizeof(dataContext.starkContext.w2),
signature,
sizeof(signature),
&info);
G_io_apdu_buffer[0] = 0;
format_signature_out(signature);
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);
// Display back the original UX
ui_idle();
return 0; // do not redraw the widget
return 0; // do not redraw the widget
}
#endif

View File

@@ -6,13 +6,14 @@
unsigned int io_seproxyhal_touch_stark_unsafe_sign_ok(const bagl_element_t *e);
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() {
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,
pnn,
{
@@ -57,13 +58,13 @@ UX_STEP_CB(
&C_icon_crossmark,
"Reject",
});
// clang-format on
UX_FLOW(ux_stark_unsafe_sign_flow,
&ux_stark_unsafe_sign_1_step,
&ux_stark_unsafe_sign_2_step,
&ux_stark_unsafe_sign_3_step,
&ux_stark_unsafe_sign_4_step,
&ux_stark_unsafe_sign_5_step
);
&ux_stark_unsafe_sign_1_step,
&ux_stark_unsafe_sign_2_step,
&ux_stark_unsafe_sign_3_step,
&ux_stark_unsafe_sign_4_step,
&ux_stark_unsafe_sign_5_step);
#endif

View File

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

View File

@@ -5,221 +5,223 @@
#include "ethUtils.h"
#include "utils.h"
typedef enum {
ERC20_TRANSFER = 0,
ERC20_APPROVE
} erc20Selector_t;
typedef enum { ERC20_TRANSFER = 0, ERC20_APPROVE } erc20Selector_t;
typedef enum {
TARGET_ADDRESS = 0,
TARGET_CONTRACT,
TARGET_COMPOUND
} targetType_t;
typedef enum { TARGET_ADDRESS = 0, TARGET_CONTRACT, TARGET_COMPOUND } targetType_t;
typedef struct erc20_parameters_t {
uint8_t selectorIndex;
uint8_t destinationAddress[21];
uint8_t amount[32];
uint8_t ticker_1[MAX_TICKER_LEN];
uint8_t ticker_2[MAX_TICKER_LEN];
uint8_t decimals;
uint8_t target;
uint8_t selectorIndex;
uint8_t destinationAddress[21];
uint8_t amount[32];
uint8_t ticker_1[MAX_TICKER_LEN];
uint8_t ticker_2[MAX_TICKER_LEN];
uint8_t decimals;
uint8_t target;
} erc20_parameters_t;
typedef struct ticker_binding_t {
char ticker1[MAX_TICKER_LEN];
char ticker2[MAX_TICKER_LEN];
char ticker1[MAX_TICKER_LEN];
char ticker2[MAX_TICKER_LEN];
} ticker_binding_t;
#define NUM_COMPOUND_BINDINGS 9
const ticker_binding_t const COMPOUND_BINDINGS[NUM_COMPOUND_BINDINGS] = {
{"DAI", "CDAI"},
{"WETH", "CETH"},
{"USDC", "CUSDC"},
{"ZRX", "CZRX"},
{"USDT", "CUSDT"},
{"WBTC", "CBTC"},
{"BAT", "CBAT"},
{"REPv2", "CREP"},
{"SAI", "CSAI"},
{"DAI", "CDAI"},
{"WETH", "CETH"},
{"USDC", "CUSDC"},
{"ZRX", "CZRX"},
{"USDT", "CUSDT"},
{"WBTC", "CBTC"},
{"BAT", "CBAT"},
{"REPv2", "CREP"},
{"SAI", "CSAI"},
};
bool check_token_binding(char* ticker1, char* ticker2, const ticker_binding_t* bindings, size_t num_bindings){
for(size_t i = 0; i < num_bindings; i++){
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 true;
}
}
return false;
bool check_token_binding(char *ticker1,
char *ticker2,
const ticker_binding_t *bindings,
size_t num_bindings) {
for (size_t i = 0; i < num_bindings; i++) {
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 true;
}
}
return false;
}
bool erc20_plugin_available_check() {
#ifdef HAVE_STARKWARE
if (quantumSet) {
switch(dataContext.tokenContext.quantumType) {
case STARK_QUANTUM_LEGACY:
case STARK_QUANTUM_ETH:
case STARK_QUANTUM_ERC20:
case STARK_QUANTUM_MINTABLE_ERC20:
return true;
default:
return false;
}
}
if (quantumSet) {
switch (dataContext.tokenContext.quantumType) {
case STARK_QUANTUM_LEGACY:
case STARK_QUANTUM_ETH:
case STARK_QUANTUM_ERC20:
case STARK_QUANTUM_MINTABLE_ERC20:
return true;
default:
return false;
}
}
#endif
return true;
return true;
}
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_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;
case ETH_PLUGIN_PROVIDE_PARAMETER: {
ethPluginProvideParameter_t *msg = (ethPluginProvideParameter_t *) parameters;
erc20_parameters_t *context = (erc20_parameters_t *) msg->pluginContext;
PRINTF("erc20 plugin provide parameter %d %.*H\n",
msg->parameterOffset,
32,
msg->parameter);
switch (msg->parameterOffset) {
case 4:
memmove(context->destinationAddress, msg->parameter + 12, 20);
msg->result = ETH_PLUGIN_RESULT_OK;
break;
case 4 + 32:
memmove(context->amount, msg->parameter, 32);
msg->result = ETH_PLUGIN_RESULT_OK;
break;
default:
PRINTF("Unhandled parameter offset\n");
msg->result = ETH_PLUGIN_RESULT_ERROR;
break;
}
} break;
case ETH_PLUGIN_PROVIDE_PARAMETER : {
ethPluginProvideParameter_t *msg = (ethPluginProvideParameter_t*)parameters;
erc20_parameters_t *context = (erc20_parameters_t*)msg->pluginContext;
PRINTF("erc20 plugin provide parameter %d %.*H\n", msg->parameterOffset, 32, msg->parameter);
switch(msg->parameterOffset) {
case 4:
memmove(context->destinationAddress, msg->parameter + 12, 20);
msg->result = ETH_PLUGIN_RESULT_OK;
break;
case 4 + 32:
memmove(context->amount, msg->parameter, 32);
msg->result = ETH_PLUGIN_RESULT_OK;
break;
default:
PRINTF("Unhandled parameter offset\n");
msg->result = ETH_PLUGIN_RESULT_ERROR;
break;
}
}
break;
case ETH_PLUGIN_FINALIZE: {
ethPluginFinalize_t *msg = (ethPluginFinalize_t *) parameters;
erc20_parameters_t *context = (erc20_parameters_t *) msg->pluginContext;
PRINTF("erc20 plugin finalize\n");
if (context->selectorIndex == ERC20_TRANSFER) {
msg->tokenLookup1 = msg->pluginSharedRO->txContent->destination;
msg->amount = context->amount;
msg->address = context->destinationAddress;
msg->uiType = ETH_UI_TYPE_AMOUNT_ADDRESS;
msg->result = ETH_PLUGIN_RESULT_OK;
} else if (context->selectorIndex == ERC20_APPROVE) {
msg->tokenLookup1 = msg->pluginSharedRO->txContent->destination;
msg->tokenLookup2 = context->destinationAddress;
msg->numScreens = 2;
msg->uiType = ETH_UI_TYPE_GENERIC;
msg->result = ETH_PLUGIN_RESULT_OK;
}
} break;
case ETH_PLUGIN_FINALIZE: {
ethPluginFinalize_t *msg = (ethPluginFinalize_t*)parameters;
erc20_parameters_t *context = (erc20_parameters_t*)msg->pluginContext;
PRINTF("erc20 plugin finalize\n");
if (context->selectorIndex == ERC20_TRANSFER){
msg->tokenLookup1 = msg->pluginSharedRO->txContent->destination;
msg->amount = context->amount;
msg->address = context->destinationAddress;
msg->uiType = ETH_UI_TYPE_AMOUNT_ADDRESS;
msg->result = ETH_PLUGIN_RESULT_OK;
}
else if (context->selectorIndex == ERC20_APPROVE){
msg->tokenLookup1 = msg->pluginSharedRO->txContent->destination;
msg->tokenLookup2 = context->destinationAddress;
msg->numScreens = 2;
msg->uiType = ETH_UI_TYPE_GENERIC;
msg->result = ETH_PLUGIN_RESULT_OK;
}
}
break;
case ETH_PLUGIN_PROVIDE_TOKEN: {
ethPluginProvideToken_t *msg = (ethPluginProvideToken_t *) parameters;
erc20_parameters_t *context = (erc20_parameters_t *) msg->pluginContext;
PRINTF("erc20 plugin provide token 1: %d - 2: %d\n",
(msg->token1 != NULL),
(msg->token2 != NULL));
if (msg->token1 != NULL) {
context->target = TARGET_ADDRESS;
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_PROVIDE_TOKEN: {
ethPluginProvideToken_t *msg = (ethPluginProvideToken_t*)parameters;
erc20_parameters_t *context = (erc20_parameters_t*)msg->pluginContext;
PRINTF("erc20 plugin provide token 1: %d - 2: %d\n", (msg->token1 != NULL), (msg->token2 != NULL));
if (msg->token1 != NULL) {
context->target = TARGET_ADDRESS;
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: {
ethQueryContractID_t *msg = (ethQueryContractID_t *) parameters;
strcpy(msg->name, "Type");
strcpy(msg->version, "Approve");
msg->result = ETH_PLUGIN_RESULT_OK;
} break;
case ETH_PLUGIN_QUERY_CONTRACT_ID: {
ethQueryContractID_t *msg = (ethQueryContractID_t*)parameters;
strcpy(msg->name, "Type");
strcpy(msg->version, "Approve");
msg->result = ETH_PLUGIN_RESULT_OK;
}
break;
case ETH_PLUGIN_QUERY_CONTRACT_UI: {
ethQueryContractUI_t *msg = (ethQueryContractUI_t *) parameters;
erc20_parameters_t *context = (erc20_parameters_t *) msg->pluginContext;
switch (msg->screenIndex) {
case 0:
strcpy(msg->title, "Amount");
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: {
ethQueryContractUI_t *msg = (ethQueryContractUI_t*)parameters;
erc20_parameters_t *context = (erc20_parameters_t*)msg->pluginContext;
switch(msg->screenIndex) {
case 0:
strcpy(msg->title, "Amount");
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;
break;
default:
break;
}
} break;
msg->result = ETH_PLUGIN_RESULT_OK;
break;
default:
break;
}
}
break;
default:
PRINTF("Unhandled message %d\n", message);
}
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);
typedef struct erc721_parameters_t {
uint8_t selectorIndex;
uint8_t address[20];
uint8_t tokenId[32];
//tokenDefinition_t *tokenSelf;
//tokenDefinition_t *tokenAddress;
uint8_t selectorIndex;
uint8_t address[20];
uint8_t tokenId[32];
// tokenDefinition_t *tokenSelf;
// tokenDefinition_t *tokenAddress;
} erc721_parameters_t;
bool erc721_plugin_available_check() {
#ifdef HAVE_STARKWARE
if (quantumSet) {
switch(dataContext.tokenContext.quantumType) {
case STARK_QUANTUM_ERC721:
case STARK_QUANTUM_MINTABLE_ERC721:
return true;
default:
return false;
}
}
return false;
if (quantumSet) {
switch (dataContext.tokenContext.quantumType) {
case STARK_QUANTUM_ERC721:
case STARK_QUANTUM_MINTABLE_ERC721:
return true;
default:
return false;
}
}
return false;
#endif
}
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_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;
case ETH_PLUGIN_PROVIDE_PARAMETER: {
ethPluginProvideParameter_t *msg = (ethPluginProvideParameter_t *) parameters;
erc721_parameters_t *context = (erc721_parameters_t *) msg->pluginContext;
PRINTF("erc721 plugin provide parameter %d %.*H\n",
msg->parameterOffset,
32,
msg->parameter);
switch (msg->parameterOffset) {
case 4:
memmove(context->address, msg->parameter + 32 - 20, 20);
msg->result = ETH_PLUGIN_RESULT_OK;
break;
case 4 + 32:
memmove(context->tokenId, msg->parameter, 32);
msg->result = ETH_PLUGIN_RESULT_OK;
break;
default:
PRINTF("Unhandled parameter offset\n");
break;
}
} break;
case ETH_PLUGIN_PROVIDE_PARAMETER : {
ethPluginProvideParameter_t *msg = (ethPluginProvideParameter_t*)parameters;
erc721_parameters_t *context = (erc721_parameters_t*)msg->pluginContext;
PRINTF("erc721 plugin provide parameter %d %.*H\n", msg->parameterOffset, 32, msg->parameter);
switch(msg->parameterOffset) {
case 4:
memmove(context->address, msg->parameter + 32 - 20, 20);
msg->result = ETH_PLUGIN_RESULT_OK;
break;
case 4 + 32:
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: {
ethPluginFinalize_t *msg = (ethPluginFinalize_t *) parameters;
erc721_parameters_t *context = (erc721_parameters_t *) msg->pluginContext;
PRINTF("erc721 plugin finalize\n");
msg->tokenLookup1 = msg->pluginSharedRO->txContent->destination;
msg->tokenLookup2 = context->address;
msg->numScreens = 3;
msg->uiType = ETH_UI_TYPE_GENERIC;
msg->result = ETH_PLUGIN_RESULT_OK;
} break;
case ETH_PLUGIN_FINALIZE: {
ethPluginFinalize_t *msg = (ethPluginFinalize_t*)parameters;
erc721_parameters_t *context = (erc721_parameters_t*)msg->pluginContext;
PRINTF("erc721 plugin finalize\n");
msg->tokenLookup1 = msg->pluginSharedRO->txContent->destination;
msg->tokenLookup2 = context->address;
msg->numScreens = 3;
msg->uiType = ETH_UI_TYPE_GENERIC;
msg->result = ETH_PLUGIN_RESULT_OK;
}
break;
case ETH_PLUGIN_PROVIDE_TOKEN: {
ethPluginProvideToken_t *msg = (ethPluginProvideToken_t *) parameters;
erc721_parameters_t *context = (erc721_parameters_t *) msg->pluginContext;
PRINTF("erc721 plugin provide token dest: %d - address: %d\n",
(msg->token1 != NULL),
(msg->token2 != NULL));
// context->tokenSelf = msg->token1;
// context->tokenAddress = msg->token2;
msg->result = ETH_PLUGIN_RESULT_OK;
} break;
case ETH_PLUGIN_PROVIDE_TOKEN: {
ethPluginProvideToken_t *msg = (ethPluginProvideToken_t*)parameters;
erc721_parameters_t *context = (erc721_parameters_t*)msg->pluginContext;
PRINTF("erc721 plugin provide token dest: %d - address: %d\n", (msg->token1 != NULL), (msg->token2 != NULL));
//context->tokenSelf = msg->token1;
//context->tokenAddress = msg->token2;
msg->result = ETH_PLUGIN_RESULT_OK;
}
break;
case ETH_PLUGIN_QUERY_CONTRACT_ID: {
ethQueryContractID_t *msg = (ethQueryContractID_t *) parameters;
strcpy(msg->name, "Allowance");
strcpy(msg->version, "");
msg->result = ETH_PLUGIN_RESULT_OK;
} break;
case ETH_PLUGIN_QUERY_CONTRACT_ID: {
ethQueryContractID_t *msg = (ethQueryContractID_t*)parameters;
strcpy(msg->name, "Allowance");
strcpy(msg->version, "");
msg->result = ETH_PLUGIN_RESULT_OK;
}
break;
case ETH_PLUGIN_QUERY_CONTRACT_UI: {
ethQueryContractUI_t *msg = (ethQueryContractUI_t *) parameters;
erc721_parameters_t *context = (erc721_parameters_t *) msg->pluginContext;
switch (msg->screenIndex) {
case 0:
strcpy(msg->title, "Contract Name");
starkware_print_eth_address(tmpContent.txContent.destination, msg->msg);
msg->result = ETH_PLUGIN_RESULT_OK;
break;
case ETH_PLUGIN_QUERY_CONTRACT_UI: {
ethQueryContractUI_t *msg = (ethQueryContractUI_t*)parameters;
erc721_parameters_t *context = (erc721_parameters_t*)msg->pluginContext;
switch(msg->screenIndex) {
case 0:
strcpy(msg->title, "Contract Name");
starkware_print_eth_address(tmpContent.txContent.destination, msg->msg);
msg->result = ETH_PLUGIN_RESULT_OK;
break;
case 1:
strcpy(msg->title, "NFT Contract");
starkware_print_eth_address(context->address, msg->msg);
msg->result = ETH_PLUGIN_RESULT_OK;
break;
case 1:
strcpy(msg->title, "NFT Contract");
starkware_print_eth_address(context->address, msg->msg);
msg->result = ETH_PLUGIN_RESULT_OK;
break;
case 2:
strcpy(msg->title, "TokenID");
starkware_print_stark_key(context->tokenId, msg->msg);
msg->result = ETH_PLUGIN_RESULT_OK;
break;
case 2:
strcpy(msg->title, "TokenID");
starkware_print_stark_key(context->tokenId, msg->msg);
msg->result = ETH_PLUGIN_RESULT_OK;
break;
default:
break;
}
} break;
default:
break;
}
}
break;
default:
PRINTF("Unhandled message %d\n", message);
}
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_4 0
#define ETH2_DEPOSIT_PUBKEY_OFFSET 0x80
#define ETH2_DEPOSIT_PUBKEY_OFFSET 0x80
#define ETH2_WITHDRAWAL_CREDENTIALS_OFFSET 0xE0
#define ETH2_SIGNATURE_OFFSET 0x120
#define ETH2_DEPOSIT_PUBKEY_LENGTH 0x30
#define ETH2_SIGNATURE_OFFSET 0x120
#define ETH2_DEPOSIT_PUBKEY_LENGTH 0x30
#define ETH2_WITHDRAWAL_CREDENTIALS_LENGTH 0x20
#define ETH2_SIGNATURE_LENGTH 0x60
#define ETH2_SIGNATURE_LENGTH 0x60
typedef struct eth2_deposit_parameters_t {
uint8_t valid;
uint8_t valid;
} eth2_deposit_parameters_t;
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_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;
case ETH_PLUGIN_PROVIDE_PARAMETER: {
ethPluginProvideParameter_t *msg = (ethPluginProvideParameter_t *) parameters;
eth2_deposit_parameters_t *context = (eth2_deposit_parameters_t *) msg->pluginContext;
uint32_t index;
PRINTF("eth2 plugin provide parameter %d %.*H\n",
msg->parameterOffset,
32,
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 : {
ethPluginProvideParameter_t *msg = (ethPluginProvideParameter_t*)parameters;
eth2_deposit_parameters_t *context = (eth2_deposit_parameters_t*)msg->pluginContext;
uint32_t index;
PRINTF("eth2 plugin provide parameter %d %.*H\n", msg->parameterOffset, 32, 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 4 + (32 * 3): // deposit data root
case 4 + (32 * 5): // deposit pubkey
case 4 + (32 * 6):
case 4 + (32 * 10): // signature
case 4 + (32 * 11):
case 4 + (32 * 12):
msg->result = ETH_PLUGIN_RESULT_OK;
break;
case 4 + (32 * 3): // deposit data root
case 4 + (32 * 5): // deposit pubkey
case 4 + (32 * 6):
case 4 + (32 * 10): // signature
case 4 + (32 * 11):
case 4 + (32 * 12):
msg->result = ETH_PLUGIN_RESULT_OK;
break;
case 4 + (32 * 8): // withdrawal credentials
{
uint8_t tmp[48];
uint32_t withdrawalKeyPath[4];
withdrawalKeyPath[0] = WITHDRAWAL_KEY_PATH_1;
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;
case 4 + (32 * 8): // withdrawal credentials
{
uint8_t tmp[48];
uint32_t withdrawalKeyPath[4];
withdrawalKeyPath[0] = WITHDRAWAL_KEY_PATH_1;
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:
PRINTF("Unhandled parameter offset\n");
break;
}
} break;
default:
PRINTF("Unhandled parameter offset\n");
break;
}
}
break;
case ETH_PLUGIN_FINALIZE: {
ethPluginFinalize_t *msg = (ethPluginFinalize_t *) parameters;
eth2_deposit_parameters_t *context = (eth2_deposit_parameters_t *) msg->pluginContext;
PRINTF("eth2 plugin finalize\n");
if (context->valid) {
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: {
ethPluginFinalize_t *msg = (ethPluginFinalize_t*)parameters;
eth2_deposit_parameters_t *context = (eth2_deposit_parameters_t*)msg->pluginContext;
PRINTF("eth2 plugin finalize\n");
if (context->valid) {
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_QUERY_CONTRACT_ID: {
ethQueryContractID_t *msg = (ethQueryContractID_t *) parameters;
strcpy(msg->name, "ETH2");
strcpy(msg->version, "Deposit");
msg->result = ETH_PLUGIN_RESULT_OK;
} break;
case ETH_PLUGIN_QUERY_CONTRACT_ID: {
ethQueryContractID_t *msg = (ethQueryContractID_t*)parameters;
strcpy(msg->name, "ETH2");
strcpy(msg->version, "Deposit");
msg->result = ETH_PLUGIN_RESULT_OK;
}
break;
case ETH_PLUGIN_QUERY_CONTRACT_UI: {
ethQueryContractUI_t *msg = (ethQueryContractUI_t *) parameters;
// 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;
case ETH_PLUGIN_QUERY_CONTRACT_UI: {
ethQueryContractUI_t *msg = (ethQueryContractUI_t*)parameters;
//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);
}
default:
PRINTF("Unhandled message %d\n", message);
}
}
#endif

File diff suppressed because it is too large Load Diff