Files
app-ethereum/src_features/signMessageEIP712/field_hash.c
2022-08-05 17:52:44 +02:00

161 lines
4.1 KiB
C

#include <stdlib.h>
#include "field_hash.h"
#include "encode_field.h"
#include "path.h"
#include "mem.h"
#include "mem_utils.h"
#include "eip712.h"
#include "shared_context.h"
static s_field_hashing *fh = NULL;
bool field_hash_init(void)
{
if (fh == NULL)
{
if ((fh = MEM_ALLOC_AND_ALIGN_TO_TYPE(sizeof(*fh), *fh)) == NULL)
{
return false;
}
fh->state = FHS_IDLE;
}
return true;
}
bool field_hash(const uint8_t *data,
uint8_t data_length,
bool partial)
{
const void *field_ptr;
e_type field_type;
uint8_t *value = NULL;
#ifdef DEBUG
const char *type;
uint8_t typelen;
const char *key;
uint8_t keylen;
#endif
if (fh == NULL)
{
return false;
}
// get field by path
if ((field_ptr = path_get_field()) == NULL)
{
return false;
}
field_type = struct_field_type(field_ptr);
if (fh->state == FHS_IDLE) // first packet for this frame
{
fh->remaining_size = (data[0] << 8) | data[1]; // network byte order
data += sizeof(uint16_t);
data_length -= sizeof(uint16_t);
fh->state = FHS_WAITING_FOR_MORE;
if (IS_DYN(field_type))
{
cx_keccak_init(&global_sha3, 256); // init hash
}
}
fh->remaining_size -= data_length;
// if a dynamic type -> continue progressive hash
if (IS_DYN(field_type))
{
cx_hash((cx_hash_t*)&global_sha3,
0,
data,
data_length,
NULL,
0);
}
if (fh->remaining_size == 0)
{
if (partial) // only makes sense if marked as complete
{
return false;
}
#ifdef DEBUG
PRINTF("=> ");
type = get_struct_field_typename(field_ptr, &typelen);
fwrite(type, sizeof(char), typelen, stdout);
PRINTF(" ");
key = get_struct_field_keyname(field_ptr, &keylen);
fwrite(key, sizeof(char), keylen, stdout);
PRINTF("\n");
#endif
if (!IS_DYN(field_type))
{
switch (field_type)
{
case TYPE_SOL_INT:
case TYPE_SOL_UINT:
value = encode_integer(data, data_length);
break;
case TYPE_SOL_BYTES_FIX:
value = encode_bytes(data, data_length);
break;
case TYPE_SOL_ADDRESS:
value = encode_address(data, data_length);
break;
case TYPE_SOL_BOOL:
value = encode_boolean((bool*)data, data_length);
break;
case TYPE_CUSTOM:
default:
PRINTF("Unknown solidity type!\n");
return false;
}
if (value == NULL)
{
return false;
}
}
else
{
if ((value = mem_alloc(KECCAK256_HASH_BYTESIZE)) == NULL)
{
return false;
}
// copy hash into memory
cx_hash((cx_hash_t*)&global_sha3,
CX_LAST,
NULL,
0,
value,
KECCAK256_HASH_BYTESIZE);
}
// TODO: Move elsewhere
uint8_t len = IS_DYN(field_type) ?
KECCAK256_HASH_BYTESIZE :
EIP_712_ENCODED_FIELD_LENGTH;
// last thing in mem is the hash of the previous field
// and just before it is the current hash context
cx_sha3_t *hash_ctx = (cx_sha3_t*)(value - sizeof(cx_sha3_t));
// start the progressive hash on it
cx_hash((cx_hash_t*)hash_ctx,
0,
value,
len,
NULL,
0);
// deallocate it
mem_dealloc(len);
path_advance();
fh->state = FHS_IDLE;
}
else
{
if (!partial || !IS_DYN(field_type)) // only makes sense if marked as partial
{
return false;
}
}
return true;
}