Skip to content

Commit

Permalink
start eip712 payload recognition
Browse files Browse the repository at this point in the history
  • Loading branch information
bitgamma committed Nov 14, 2024
1 parent 073a024 commit 16471e2
Show file tree
Hide file tree
Showing 4 changed files with 102 additions and 83 deletions.
106 changes: 49 additions & 57 deletions app/ethereum/eip712.c
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,11 @@ static app_err_t eip712_top_level(eip712_ctx_t* ctx) {
return found == 0xf ? ERR_OK : ERR_DATA;
}

static inline void eip712_string_from_field(struct eip712_string* str, int index, const eip712_ctx_t* ctx) {
str->str = &ctx->json[ctx->tokens[index].start];
str->len = ctx->tokens[index].end - ctx->tokens[index].start;
}

static int eip712_parse_types(uint8_t* heap, size_t heap_size, int types_token, struct eip712_type types[], int types_count, const eip712_ctx_t* ctx) {
int current_type = 0;
int fields_size = 0;
Expand All @@ -81,8 +86,7 @@ static int eip712_parse_types(uint8_t* heap, size_t heap_size, int types_token,
return -1;
}

types[current_type].name.len = (ctx->tokens[i].end - ctx->tokens[i].start);
types[current_type].name.str = &ctx->json[ctx->tokens[i].start];
eip712_string_from_field(&types[current_type].name, i, ctx);

if (ctx->tokens[++i].type != JSMN_ARRAY) {
return -1;
Expand Down Expand Up @@ -123,12 +127,10 @@ static int eip712_parse_types(uint8_t* heap, size_t heap_size, int types_token,

switch(p) {
case 'n':
types[current_type].fields[j].name.len = ctx->tokens[i].end - ctx->tokens[i].start;
types[current_type].fields[j].name.str = &ctx->json[ctx->tokens[i].start];
eip712_string_from_field(&types[current_type].fields[j].name, i, ctx);
break;
case 't':
types[current_type].fields[j].type.len = ctx->tokens[i].end - ctx->tokens[i].start;
types[current_type].fields[j].type.str = &ctx->json[ctx->tokens[i].start];
eip712_string_from_field(&types[current_type].fields[j].type, i, ctx);
break;
default:
return -1;
Expand Down Expand Up @@ -186,6 +188,35 @@ static int eip712_find_type(const struct eip712_type types[], int types_count, c
return -1;
}

static app_err_t eip712_copy_uint(int field_index, bool pad_right, uint8_t out[32], const eip712_ctx_t* ctx) {
struct eip712_string tmpstr;
eip712_string_from_field(&tmpstr, field_index, ctx);

if ((tmpstr.len > 2) && (tmpstr.str[0] == '0') && (tmpstr.str[1] == 'x')) {
int out_len = ((tmpstr.len - 1) >> 1);
int padding = 32 - out_len;
int offset;

if (pad_right) {
offset = 0;
memset(&out[offset], 0, padding);
} else {
offset = padding;
memset(out, 0, padding);
}

if (!base16_decode(&tmpstr.str[2], &out[offset], (tmpstr.len - 2))) {
return ERR_DATA;
}
} else {
if (!atoi256BE(tmpstr.str, tmpstr.len, out)) {
return ERR_DATA;
}
}

return ERR_OK;
}

static void eip712_hash_type(SHA3_CTX* sha3, const struct eip712_type* type) {
uint8_t sep;

Expand Down Expand Up @@ -300,8 +331,7 @@ static int eip712_find_data(const struct eip712_string* name, int start, const e
}

struct eip712_string key_name;
key_name.str = &ctx->json[ctx->tokens[i].start];
key_name.len = ctx->tokens[i].end - ctx->tokens[i].start;
eip712_string_from_field(&key_name, i, ctx);

if (eip712_streq(name, &key_name)) {
return i + 1;
Expand Down Expand Up @@ -426,8 +456,7 @@ static app_err_t eip712_encode_field(uint8_t out[32], uint8_t* heap, size_t heap
}

struct eip712_string tmpstr;
tmpstr.str = &ctx->json[ctx->tokens[field_val].start];
tmpstr.len = ctx->tokens[field_val].end - ctx->tokens[field_val].start;
eip712_string_from_field(&tmpstr, field_val, ctx);

__DECL_SHA3_CTX();

Expand Down Expand Up @@ -460,31 +489,9 @@ static app_err_t eip712_encode_field(uint8_t out[32], uint8_t* heap, size_t heap
memset(out, 0, 32);
out[31] = ctx->json[ctx->tokens[field_val].start] == 't';
} else {
struct eip712_string tmpstr;
tmpstr.str = &ctx->json[ctx->tokens[field_val].start];
tmpstr.len = ctx->tokens[field_val].end - ctx->tokens[field_val].start;

if ((tmpstr.len > 2) && (tmpstr.str[0] == '0') && (tmpstr.str[1] == 'x')) {
int out_len = ((tmpstr.len - 1) >> 1);
int padding = 32 - out_len;
int offset;

// bytesX are right padded, others are left padded
if (field_type->str[0] == 'b') {
offset = 0;
memset(&out[offset], 0, padding);
} else {
offset = padding;
memset(out, 0, padding);
}

if (!base16_decode(&tmpstr.str[2], &out[offset], (tmpstr.len - 2))) {
return ERR_DATA;
}
} else {
if (!atoi256BE(tmpstr.str, tmpstr.len, out)) {
return ERR_DATA;
}
// bytesX are right padded, others are left padded
if (eip712_copy_uint(field_val, (field_type->str[0] == 'b'), out, ctx) != ERR_OK) {
return ERR_DATA;
}
}

Expand Down Expand Up @@ -582,8 +589,7 @@ app_err_t eip712_hash(eip712_ctx_t *ctx, SHA3_CTX *sha3, uint8_t* heap, size_t h
eip712_hash_struct(tmp, heap, heap_size, struct_idx, types, types_count, ctx->index.domain, ctx);
keccak_Update(sha3, tmp, 32);

tmpstr.str = &json[ctx->tokens[ctx->index.primary_type].start];
tmpstr.len = (ctx->tokens[ctx->index.primary_type].end - ctx->tokens[ctx->index.primary_type].start);
eip712_string_from_field(&tmpstr, ctx->index.primary_type, ctx);
struct_idx = eip712_find_type(types, types_count, &tmpstr);

if (struct_idx == -1) {
Expand Down Expand Up @@ -672,15 +678,15 @@ size_t eip712_to_string(const eip712_ctx_t* ctx, uint8_t* out) {
return eip712_encode_object(ctx, out, &root, 0);
}

static inline int eip712_find_domain_data(const eip712_ctx_t* ctx, const char* key) {
static inline int eip712_find_data_from_str(const eip712_ctx_t* ctx, int parent_token, const char* key) {
struct eip712_string k;
k.str = key;
k.len = strlen(key);
return eip712_find_data(&k, ctx->index.domain, ctx);
return eip712_find_data(&k, parent_token, ctx);
}

static app_err_t eip712_extract_domain_string(const eip712_ctx_t* ctx, const char* key, char** out) {
int found = eip712_find_domain_data(ctx, key);
int found = eip712_find_data_from_str(ctx, ctx->index.domain, key);

if (found == -1) {
return ERR_DATA;
Expand All @@ -703,30 +709,16 @@ app_err_t eip712_extract_domain(const eip712_ctx_t* ctx, eip712_domain_t* out) {
return ERR_DATA;
}

int found = eip712_find_domain_data(ctx, "chainId");
int found = eip712_find_data_from_str(ctx, ctx->index.domain, "chainId");

if (found == -1) {
return ERR_DATA;
}

struct eip712_string tmpstr;
tmpstr.str = &ctx->json[ctx->tokens[found].start];
tmpstr.len = ctx->tokens[found].end - ctx->tokens[found].start;

uint8_t chain_bytes[32];

if ((tmpstr.len > 2) && (tmpstr.str[0] == '0') && (tmpstr.str[1] == 'x')) {
int out_len = ((tmpstr.len - 1) >> 1);
int padding = 32 - out_len;
memset(chain_bytes, 0, padding);

if (!base16_decode(&tmpstr.str[2], &chain_bytes[padding], (tmpstr.len - 2))) {
return ERR_DATA;
}
} else {
if (!atoi256BE(tmpstr.str, tmpstr.len, chain_bytes)) {
return ERR_DATA;
}
if (eip712_copy_uint(found, false, chain_bytes, ctx) != ERR_OK) {
return ERR_DATA;
}

out->chainID = (chain_bytes[28] << 24) | (chain_bytes[29] << 16) | (chain_bytes[30] << 8) | chain_bytes[31];
Expand Down
23 changes: 23 additions & 0 deletions app/ethereum/eth_data.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
#include "eth_data.h"
#include <string.h>

#define ETH_ERC20_TRANSFER_SIGNATURE_LEN 16
#define ETH_ERC20_TRANSFER_LEN 68

const uint8_t ETH_ERC20_TRANSFER_SIGNATURE[] = {
0xa9, 0x05, 0x9c, 0xbb, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};

eth_data_type_t eth_data_recognize(const txContent_t* tx) {
if (tx->dataLength == 0) {
return ETH_DATA_ABSENT;
} else if (tx->value.length == 0 && (tx->dataLength == ETH_ERC20_TRANSFER_LEN) && !memcmp(tx->data, ETH_ERC20_TRANSFER_SIGNATURE, ETH_ERC20_TRANSFER_SIGNATURE_LEN)) {
return ETH_DATA_ERC20_TRANSFER;
} else {
return ETH_DATA_UNKNOWN;
}
}

eip712_data_type_t eip712_recognize(const eip712_ctx_t* msg) {
return EIP712_UNKNOWN;
}
25 changes: 25 additions & 0 deletions app/ethereum/eth_data.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
#ifndef __ETH_DATA__
#define __ETH_DATA__

#include <stddef.h>
#include "ethUstream.h"
#include "eip712.h"

typedef enum {
ETH_DATA_ABSENT,
ETH_DATA_UNKNOWN,
ETH_DATA_ERC20_TRANSFER
} eth_data_type_t;

typedef enum {
EIP712_UNKNOWN,
EIP712_PERMIT,
} eip712_data_type_t;

#define ETH_ERC20_ADDR_OFF 16
#define ETH_ERC20_VALUE_OFF 36

eth_data_type_t eth_data_recognize(const txContent_t* tx);
eip712_data_type_t eip712_recognize(const eip712_ctx_t* msg);

#endif
31 changes: 5 additions & 26 deletions app/ui/dialog.c
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include "crypto/segwit_addr.h"
#include "crypto/script.h"
#include "crypto/util.h"
#include "ethereum/eth_data.h"
#include "ethereum/eth_db.h"
#include "ethereum/ethUstream.h"
#include "ethereum/ethUtils.h"
Expand All @@ -18,20 +19,8 @@
#define MESSAGE_MAX_X (SCREEN_WIDTH - TH_TEXT_HORIZONTAL_MARGIN)
#define MESSAGE_MAX_Y (SCREEN_HEIGHT - TH_NAV_HINT_HEIGHT)

const uint8_t ETH_ERC20_SIGNATURE[] = { 0xa9, 0x05, 0x9c, 0xbb, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
#define ETH_ERC20_SIGNATURE_LEN 16
#define ETH_ERC20_ADDR_OFF 16
#define ETH_ERC20_VALUE_OFF 36
#define ETH_ERC20_TRANSFER_LEN 68

#define BTC_DIALOG_PAGE_ITEMS 1

typedef enum {
ETH_DATA_ABSENT,
ETH_DATA_UNKNOWN,
ETH_DATA_ERC20
} eth_data_type_t;

static app_err_t dialog_wait_dismiss() {
dialog_nav_hints(0, ICON_NAV_NEXT);

Expand Down Expand Up @@ -285,17 +274,6 @@ static void dialog_indexed_string(char* dst, const char* label, size_t index) {
*dst = '\0';
}

// TODO: move this to more general function to recognize data and display correct data accordingly
static eth_data_type_t dialog_recognize_data(const txContent_t* tx) {
if (tx->dataLength == 0) {
return ETH_DATA_ABSENT;
} else if (tx->value.length == 0 && tx->dataLength == ETH_ERC20_TRANSFER_LEN && !memcmp(tx->data, ETH_ERC20_SIGNATURE, ETH_ERC20_SIGNATURE_LEN)) {
return ETH_DATA_ERC20;
} else {
return ETH_DATA_UNKNOWN;
}
}

app_err_t dialog_confirm_eth_tx() {
chain_desc_t chain;
erc20_desc_t token;
Expand All @@ -309,7 +287,7 @@ app_err_t dialog_confirm_eth_tx() {

i18n_str_id_t title;
const uint8_t* to;
eth_data_type_t data_type = dialog_recognize_data(g_ui_cmd.params.eth_tx.tx);
eth_data_type_t data_type = eth_data_recognize(g_ui_cmd.params.eth_tx.tx);

uint8_t* data = g_camera_fb[0];
size_t data_len = 0;
Expand All @@ -319,7 +297,7 @@ app_err_t dialog_confirm_eth_tx() {
size_t page = 0;
size_t last_page = 0;

if (data_type == ETH_DATA_ERC20) {
if (data_type == ETH_DATA_ERC20_TRANSFER) {
title = TX_CONFIRM_ERC20_TITLE;
token.chain = chain.chain_id;
token.addr = g_ui_cmd.params.eth_tx.tx->destination;
Expand Down Expand Up @@ -686,9 +664,9 @@ app_err_t dialog_confirm_text_based(const uint8_t* data, size_t len, eip712_doma

if (page == 0) {
ctx.y = TH_TITLE_HEIGHT;
dialog_address(&ctx, TX_SIGNER, g_ui_cmd.params.msg.addr_type, g_ui_cmd.params.msg.addr);

if (eip712) {
dialog_address(&ctx, TX_SIGNER, ADDR_ETH, g_ui_cmd.params.eip712.addr);
dialog_label(&ctx, LSTR(TX_CHAIN));

chain_desc_t chain;
Expand All @@ -705,6 +683,7 @@ app_err_t dialog_confirm_text_based(const uint8_t* data, size_t len, eip712_doma
dialog_label(&ctx, LSTR(EIP712_CONTRACT));
dialog_data(&ctx, eip712->address);
} else {
dialog_address(&ctx, TX_SIGNER, g_ui_cmd.params.msg.addr_type, g_ui_cmd.params.msg.addr);
dialog_label(&ctx, LSTR(MSG_LABEL));
}

Expand Down

0 comments on commit 16471e2

Please sign in to comment.