Apply clang-format
This commit is contained in:
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
#include "shared_context.h"
|
||||
|
||||
uint32_t set_result_get_eth2_publicKey(void);
|
||||
|
||||
|
||||
@@ -10,4 +10,3 @@ uint32_t set_result_get_eth2_publicKey() {
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
#include "shared_context.h"
|
||||
|
||||
uint32_t set_result_get_publicKey(void);
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -2,4 +2,3 @@
|
||||
|
||||
customStatus_e customProcessor(txContext_t *context);
|
||||
void finalizeParsing(bool direct);
|
||||
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
@@ -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
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
#include "shared_context.h"
|
||||
|
||||
uint32_t set_result_get_stark_publicKey(void);
|
||||
|
||||
|
||||
@@ -11,5 +11,3 @@ uint32_t set_result_get_stark_publicKey() {
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user