Files
app-ethereum/src_plugins/eth2/eth2_plugin.c

265 lines
11 KiB
C
Raw Normal View History

2020-10-27 11:16:50 +01:00
#ifdef HAVE_ETH2
#include <string.h>
#include "eth_plugin_internal.h"
#include "eth_plugin_handler.h"
#include "shared_context.h"
#include "ethUtils.h"
#include "utils.h"
void getEth2PublicKey(uint32_t *bip32Path, uint8_t bip32PathLength, uint8_t *out);
#define WITHDRAWAL_KEY_PATH_1 12381
#define WITHDRAWAL_KEY_PATH_2 3600
2020-11-02 23:01:53 +01:00
#define WITHDRAWAL_KEY_PATH_4 0
2020-10-27 11:16:50 +01:00
2020-12-01 16:20:13 +01:00
#define ETH2_DEPOSIT_PUBKEY_OFFSET 0x80
2020-10-27 11:16:50 +01:00
#define ETH2_WITHDRAWAL_CREDENTIALS_OFFSET 0xE0
2020-12-01 16:20:13 +01:00
#define ETH2_SIGNATURE_OFFSET 0x120
#define ETH2_DEPOSIT_PUBKEY_LENGTH 0x30
2020-10-27 11:16:50 +01:00
#define ETH2_WITHDRAWAL_CREDENTIALS_LENGTH 0x20
2020-12-01 16:20:13 +01:00
#define ETH2_SIGNATURE_LENGTH 0x60
2020-10-27 11:16:50 +01:00
2021-04-22 11:38:21 +02:00
#define DEPOSIT_CONTRACT_ADDRESS "0x00000000219ab540356cbb839cbe05303d7705fa"
#define DEPOSIT_CONTRACT_LENGTH sizeof(DEPOSIT_CONTRACT_ADDRESS)
// Highest index for withdrawal derivation path.
#define INDEX_MAX 524288 // 2 ^ 19 : arbitrary value to protect from path attacks.
2020-10-27 11:16:50 +01:00
typedef struct eth2_deposit_parameters_t {
2020-12-01 16:20:13 +01:00
uint8_t valid;
char deposit_address[ETH2_DEPOSIT_PUBKEY_LENGTH];
2020-10-27 11:16:50 +01:00
} eth2_deposit_parameters_t;
2021-04-22 11:38:21 +02:00
static void to_lowercase(char *str, unsigned char size) {
for (unsigned char i = 0; i < size && str[i] != 0; i++) {
if (str[i] >= 'A' && str[i] <= 'Z') {
str[i] += 'a' - 'A';
}
}
}
2021-04-22 14:01:52 +02:00
// Fills the `out` buffer with the lowercase string representation of the pubkey passed in as binary
// format by `in`. Does not check the size, so expects `out` to be big enough to told the string
// representation. Returns the length of string (counting the null terminating character).
2021-04-22 13:57:09 +02:00
static int getEthDisplayableAddress(char *out, uint8_t *in) {
out[0] = '0';
out[1] = 'x';
2021-04-22 14:01:52 +02:00
getEthAddressStringFromBinary(in, (uint8_t *) out + 2, &global_sha3, chainConfig);
2021-04-22 11:38:21 +02:00
2021-04-22 14:01:52 +02:00
uint8_t destinationLen = strlen(out) + 1; // Adding one to account for \0.
2021-04-22 11:40:12 +02:00
2021-04-22 11:38:21 +02:00
// Ensure address is in lowercase, to match DEPOSIT_CONTRACT_ADDRESS' case.
2021-04-22 13:57:09 +02:00
to_lowercase(out, destinationLen);
return (destinationLen);
}
static int check_deposit_contract(ethPluginInitContract_t *msg) {
txContent_t *content = msg->pluginSharedRO->txContent;
char destinationAddress[DEPOSIT_CONTRACT_LENGTH];
// uint8_t destinationLen = getEthDisplayableAddress(destinationAddress, content->destination);
PRINTF("INSIDE content: string: |%s|\n", content->destination);
PRINTF("INSIDE content: bytes: |%.*H|\n", sizeof(content->destination), content->destination);
uint8_t destinationLen = 43;
2021-04-22 11:38:21 +02:00
if (destinationLen != DEPOSIT_CONTRACT_LENGTH) {
2021-04-22 14:04:09 +02:00
PRINTF("eth2plugin: destination lengths differ. Expected %u got %u\n",
2021-04-22 11:38:21 +02:00
DEPOSIT_CONTRACT_LENGTH,
destinationLen);
return 0;
} else if (memcmp(destinationAddress, DEPOSIT_CONTRACT_ADDRESS, DEPOSIT_CONTRACT_LENGTH) != 0) {
PRINTF("eth2plugin: destination addresses differ. Expected %s got %s\n",
DEPOSIT_CONTRACT_ADDRESS,
destinationAddress);
return 0;
} else {
return 1;
}
}
2020-10-27 11:16:50 +01:00
void eth2_plugin_call(int message, void *parameters) {
2020-12-01 16:20:13 +01:00
switch (message) {
case ETH_PLUGIN_INIT_CONTRACT: {
ethPluginInitContract_t *msg = (ethPluginInitContract_t *) parameters;
eth2_deposit_parameters_t *context = (eth2_deposit_parameters_t *) msg->pluginContext;
2021-04-22 11:38:21 +02:00
if (check_deposit_contract(msg) == 0) {
PRINTF("eth2plugin: failed to check deposit contract\n");
context->valid = 0;
msg->result = ETH_PLUGIN_RESULT_ERROR;
} else {
context->valid = 1;
msg->result = ETH_PLUGIN_RESULT_OK;
}
2020-12-01 16:20:13 +01:00
} break;
case ETH_PLUGIN_PROVIDE_PARAMETER: {
ethPluginProvideParameter_t *msg = (ethPluginProvideParameter_t *) parameters;
eth2_deposit_parameters_t *context = (eth2_deposit_parameters_t *) msg->pluginContext;
uint32_t index;
PRINTF("eth2 plugin provide parameter %d %.*H\n",
msg->parameterOffset,
32,
msg->parameter);
switch (msg->parameterOffset) {
case 4 + (32 * 0): // pubkey offset
case 4 + (32 * 1): // withdrawal credentials offset
case 4 + (32 * 2): // signature offset
case 4 + (32 * 4): // deposit pubkey length
case 4 + (32 * 7): // withdrawal credentials length
case 4 + (32 * 9): // signature length
{
uint32_t check = 0;
switch (msg->parameterOffset) {
case 4 + (32 * 0):
check = ETH2_DEPOSIT_PUBKEY_OFFSET;
break;
case 4 + (32 * 1):
check = ETH2_WITHDRAWAL_CREDENTIALS_OFFSET;
break;
case 4 + (32 * 2):
check = ETH2_SIGNATURE_OFFSET;
break;
case 4 + (32 * 4):
check = ETH2_DEPOSIT_PUBKEY_LENGTH;
break;
case 4 + (32 * 7):
check = ETH2_WITHDRAWAL_CREDENTIALS_LENGTH;
break;
case 4 + (32 * 9):
check = ETH2_SIGNATURE_LENGTH;
break;
default:
break;
}
index = U4BE(msg->parameter, 32 - 4);
if (index != check) {
PRINTF("eth2 plugin parameter check %d failed, expected %d got %d\n",
msg->parameterOffset,
check,
index);
context->valid = 0;
}
msg->result = ETH_PLUGIN_RESULT_OK;
} break;
2021-04-22 13:57:09 +02:00
case 4 + (32 * 5): // deposit pubkey 1
2021-04-22 14:01:52 +02:00
{
// Copy the first 32 bytes.
2021-04-22 15:06:12 +02:00
memcpy(context->deposit_address,
msg->parameter,
sizeof(context->deposit_address));
2021-04-22 14:01:52 +02:00
msg->result = ETH_PLUGIN_RESULT_OK;
break;
}
case 4 + (32 * 6): // deposit pubkey 2
{
// Copy the last 16 bytes.
2021-04-22 15:06:12 +02:00
memcpy(context->deposit_address + 32,
msg->parameter,
sizeof(context->deposit_address) - 32);
2021-04-22 13:57:09 +02:00
2021-04-22 14:01:52 +02:00
// Use a temporary buffer to store the string representation.
char tmp[ETH2_DEPOSIT_PUBKEY_LENGTH];
2021-04-22 15:06:12 +02:00
getEthDisplayableAddress(tmp, (uint8_t *) context->deposit_address);
2021-04-22 13:57:09 +02:00
2021-04-22 14:01:52 +02:00
// Copy back the string to the global variable.
2021-04-22 15:06:12 +02:00
strcpy(context->deposit_address, tmp);
2021-04-22 14:01:52 +02:00
msg->result = ETH_PLUGIN_RESULT_OK;
break;
}
case 4 + (32 * 3): // deposit data root
2020-12-01 16:20:13 +01:00
case 4 + (32 * 10): // signature
case 4 + (32 * 11):
case 4 + (32 * 12):
msg->result = ETH_PLUGIN_RESULT_OK;
break;
case 4 + (32 * 8): // withdrawal credentials
{
// uint8_t tmp[48];
// uint32_t withdrawalKeyPath[4];
// withdrawalKeyPath[0] = WITHDRAWAL_KEY_PATH_1;
// withdrawalKeyPath[1] = WITHDRAWAL_KEY_PATH_2;
// if (eth2WithdrawalIndex > INDEX_MAX) {
// PRINTF("eth2 plugin: withdrawal index is too big\n");
// PRINTF("Got %u which is higher than INDEX_MAX (%u)\n",
// eth2WithdrawalIndex,
// INDEX_MAX);
// context->valid = 0;
// }
// withdrawalKeyPath[2] = eth2WithdrawalIndex;
// withdrawalKeyPath[3] = WITHDRAWAL_KEY_PATH_4;
// getEth2PublicKey(withdrawalKeyPath, 4, tmp);
// PRINTF("eth2 plugin computed withdrawal public key %.*H\n", 48, tmp);
// cx_hash_sha256(tmp, 48, tmp, 32);
// tmp[0] = 0;
// if (memcmp(tmp, msg->parameter, 32) != 0) {
// PRINTF("eth2 plugin invalid withdrawal credentials\n");
// PRINTF("Got %.*H\n", 32, msg->parameter);
// PRINTF("Expected %.*H\n", 32, tmp);
// context->valid = 0;
// }
2020-12-01 16:20:13 +01:00
msg->result = ETH_PLUGIN_RESULT_OK;
} break;
default:
PRINTF("Unhandled parameter offset\n");
break;
}
} break;
case ETH_PLUGIN_FINALIZE: {
ethPluginFinalize_t *msg = (ethPluginFinalize_t *) parameters;
eth2_deposit_parameters_t *context = (eth2_deposit_parameters_t *) msg->pluginContext;
PRINTF("eth2 plugin finalize\n");
if (context->valid) {
2021-04-22 13:57:09 +02:00
msg->numScreens = 2;
2020-12-01 16:20:13 +01:00
msg->uiType = ETH_UI_TYPE_GENERIC;
msg->result = ETH_PLUGIN_RESULT_OK;
} else {
msg->result = ETH_PLUGIN_RESULT_FALLBACK;
}
} break;
case ETH_PLUGIN_QUERY_CONTRACT_ID: {
ethQueryContractID_t *msg = (ethQueryContractID_t *) parameters;
strcpy(msg->name, "ETH2");
strcpy(msg->version, "Deposit");
msg->result = ETH_PLUGIN_RESULT_OK;
} break;
case ETH_PLUGIN_QUERY_CONTRACT_UI: {
ethQueryContractUI_t *msg = (ethQueryContractUI_t *) parameters;
2021-04-22 15:06:12 +02:00
eth2_deposit_parameters_t *context = (eth2_deposit_parameters_t *) msg->pluginContext;
2020-12-01 16:20:13 +01:00
switch (msg->screenIndex) {
2021-04-22 14:01:52 +02:00
case 0: { // Amount screen
2020-12-01 16:20:13 +01:00
uint8_t decimals = WEI_TO_ETHER;
uint8_t *ticker = (uint8_t *) PIC(chainConfig->coinName);
strcpy(msg->title, "Amount");
amountToString(tmpContent.txContent.value.value,
tmpContent.txContent.value.length,
decimals,
(char *) ticker,
msg->msg,
100);
msg->result = ETH_PLUGIN_RESULT_OK;
} break;
2021-04-22 14:01:52 +02:00
case 1: { // Deposit pubkey screen
2021-04-22 13:57:09 +02:00
strcpy(msg->title, "Validator");
2021-04-22 15:06:12 +02:00
strcpy(msg->msg, context->deposit_address);
2021-04-22 13:57:09 +02:00
msg->result = ETH_PLUGIN_RESULT_OK;
}
2020-12-01 16:20:13 +01:00
default:
break;
}
} break;
default:
PRINTF("Unhandled message %d\n", message);
}
2020-10-27 11:16:50 +01:00
}
#endif