WIP field hashing support

This commit is contained in:
Alexandre Paillier
2022-04-14 18:22:35 +02:00
parent 0e9cd91ecc
commit a3f5eee116
5 changed files with 160 additions and 91 deletions

View File

@@ -7,56 +7,13 @@
/** /**
* Hash field value * Encode a field value to 32 bytes
* *
* @param[in] value pointer to value * @param[in] value field value to encode
* @param[in] length its bytelength * @param[in] length field length before encoding
* @param[in] dealloc if the value length should be deallocated from the memory * @return encoded field value
*/ */
static void *hash_field_value(const void *const value, uint16_t length, bool dealloc) static void *field_encode(const uint8_t *const value, uint8_t length)
{
uint8_t *hash_ptr = NULL;
if (value != NULL)
{
cx_keccak_init((cx_hash_t*)&global_sha3, 256);
cx_hash((cx_hash_t*)&global_sha3,
0,
(uint8_t*)value,
length,
NULL,
0);
if (dealloc)
{
// restore the memory location
mem_dealloc(length);
}
if ((hash_ptr = mem_alloc(KECCAK256_HASH_BYTESIZE)) == NULL)
{
return NULL;
}
// copy hash into memory
cx_hash((cx_hash_t*)&global_sha3,
CX_LAST,
NULL,
0,
hash_ptr,
KECCAK256_HASH_BYTESIZE);
}
return hash_ptr;
}
/**
* Encode an integer and hash it
*
* @param[in] value pointer to the "packed" integer received
* @param[in] length its byte-length
* @return the encoded (hashed) value
*/
void *encode_integer(const uint8_t *const value, uint16_t length)
{ {
uint8_t *padded_value; uint8_t *padded_value;
@@ -73,29 +30,30 @@ void *encode_integer(const uint8_t *const value, uint16_t length)
padded_value[EIP_712_ENCODED_FIELD_LENGTH - (length - idx)] = value[idx]; padded_value[EIP_712_ENCODED_FIELD_LENGTH - (length - idx)] = value[idx];
} }
} }
return hash_field_value(padded_value, EIP_712_ENCODED_FIELD_LENGTH, true); return padded_value;
} }
/** /**
* Encode a string and hash it * Encode an integer
* *
* @param[in] value pointer to the string received * @param[in] value pointer to the "packed" integer received
* @param[in] length its byte-length * @param[in] length its byte-length
* @return the encoded (hashed) value * @return the encoded (hashed) value
*/ */
void *encode_string(const char *const value, uint16_t length) void *encode_integer(const uint8_t *const value, uint8_t length)
{ {
return hash_field_value(value, length, false); // no length check here since it will be checked by field_encode
return field_encode(value, length);
} }
/** /**
* Encode a boolean and hash it * Encode a boolean
* *
* @param[in] value pointer to the boolean received * @param[in] value pointer to the boolean received
* @param[in] length its byte-length * @param[in] length its byte-length
* @return the encoded (hashed) value * @return the encoded (hashed) value
*/ */
void *encode_bool(const bool *const value, uint16_t length) void *encode_boolean(const bool *const value, uint8_t length)
{ {
if (length != 1) // sanity check if (length != 1) // sanity check
{ {
@@ -105,13 +63,13 @@ void *encode_bool(const bool *const value, uint16_t length)
} }
/** /**
* Encode an address and hash it * Encode an address
* *
* @param[in] value pointer to the address received * @param[in] value pointer to the address received
* @param[in] length its byte-length * @param[in] length its byte-length
* @return the encoded (hashed) value * @return the encoded (hashed) value
*/ */
void *encode_address(const uint8_t *const value, uint16_t length) void *encode_address(const uint8_t *const value, uint8_t length)
{ {
if (length != ADDRESS_LENGTH) // sanity check if (length != ADDRESS_LENGTH) // sanity check
{ {
@@ -119,15 +77,3 @@ void *encode_address(const uint8_t *const value, uint16_t length)
} }
return encode_integer(value, length); return encode_integer(value, length);
} }
/**
* Encode bytes and hash it
*
* @param[in] value pointer to the bytes received
* @param[in] length its byte-length
* @return the encoded (hashed) value
*/
void *encode_bytes(const uint8_t *const value, uint16_t length)
{
return hash_field_value(value, length, false);
}

View File

@@ -6,10 +6,8 @@
#define EIP_712_ENCODED_FIELD_LENGTH 32 #define EIP_712_ENCODED_FIELD_LENGTH 32
void *encode_integer(const uint8_t *const value, uint16_t length); void *encode_integer(const uint8_t *const value, uint8_t length);
void *encode_string(const char *const value, uint16_t length); void *encode_boolean(const bool *const value, uint8_t length);
void *encode_bool(const bool *const value, uint16_t length); void *encode_address(const uint8_t *const value, uint8_t length);
void *encode_address(const uint8_t *const value, uint16_t length);
void *encode_bytes(const uint8_t *const value, uint16_t length);
#endif // ENCODE_FIELD_H_ #endif // ENCODE_FIELD_H_

View File

@@ -386,7 +386,11 @@ bool handle_apdu(const uint8_t *const data)
type_hash(structs_array, (char*)&data[OFFSET_DATA], data[OFFSET_LC]); type_hash(structs_array, (char*)&data[OFFSET_DATA], data[OFFSET_LC]);
break; break;
case P2_FIELD: case P2_FIELD:
field_hash(structs_array, &data[OFFSET_DATA], data[OFFSET_LC]); if ((data[OFFSET_P1] != P1_COMPLETE) && (data[OFFSET_P1] != P1_PARTIAL))
{
return false;
}
field_hash(&data[OFFSET_DATA], data[OFFSET_LC], data[OFFSET_P1] == P1_PARTIAL);
break; break;
case P2_ARRAY: case P2_ARRAY:
path_new_array_depth(data[OFFSET_DATA]); path_new_array_depth(data[OFFSET_DATA]);

View File

@@ -3,34 +3,140 @@
#include "field_hash.h" #include "field_hash.h"
#include "encode_field.h" #include "encode_field.h"
#include "path.h" #include "path.h"
#include "mem.h"
#include "eip712.h" #include "eip712.h"
#include "shared_context.h"
const uint8_t *field_hash(const void *const structs_array, static s_field_hashing *fh = NULL;
const uint8_t *const data,
const uint8_t data_length) static bool field_hash_init(void)
{ {
if (fh == NULL)
{
if ((fh = mem_alloc(sizeof(*fh))) == NULL)
{
return false;
}
fh->state = FHS_IDLE;
}
return true;
}
const uint8_t *field_hash(const uint8_t *data,
uint8_t data_length,
bool partial)
{
const void *field_ptr;
const char *type; const char *type;
uint8_t typelen; uint8_t typelen;
const char *key; const char *key;
uint8_t keylen; uint8_t keylen;
const void *field; e_type field_type;
uint8_t *hash_ptr = NULL;
(void)structs_array;
(void)data; (void)data;
(void)data_length; if ((fh == NULL) && (field_hash_init() == false))
// get field by path
//encode_integer(data, data_length);
field = path_get_field();
if (field != NULL)
{ {
return NULL;
}
// get field by path
if ((field_ptr = path_get_field()) == NULL)
{
return NULL;
}
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;
cx_keccak_init((cx_hash_t*)&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 NULL;
}
printf("==> "); printf("==> ");
type = get_struct_field_typename(field, &typelen); type = get_struct_field_typename(field_ptr, &typelen);
fwrite(type, sizeof(char), typelen, stdout); fwrite(type, sizeof(char), typelen, stdout);
printf(" "); printf(" ");
key = get_struct_field_keyname(field, &keylen); key = get_struct_field_keyname(field_ptr, &keylen);
fwrite(key, sizeof(char), keylen, stdout); fwrite(key, sizeof(char), keylen, stdout);
printf("\n"); printf("\n");
uint8_t *value = NULL;
if (!IS_DYN(field_type))
{
switch (field_type)
{
case TYPE_SOL_INT:
case TYPE_SOL_UINT:
case TYPE_SOL_BYTES_FIX:
value = encode_integer(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 NULL;
}
if (value == NULL)
{
return NULL;
}
cx_hash((cx_hash_t*)&global_sha3,
0,
(uint8_t*)value,
EIP_712_ENCODED_FIELD_LENGTH,
NULL,
0);
// restore the memory location
mem_dealloc(EIP_712_ENCODED_FIELD_LENGTH);
}
if ((hash_ptr = mem_alloc(KECCAK256_HASH_BYTESIZE)) == NULL)
{
return NULL;
}
// copy hash into memory
cx_hash((cx_hash_t*)&global_sha3,
CX_LAST,
NULL,
0,
hash_ptr,
KECCAK256_HASH_BYTESIZE);
path_advance(); path_advance();
fh->state = FHS_IDLE;
} }
return NULL; else
{
if (!partial || !IS_DYN(field_type)) // only makes sense if marked as partial
{
return NULL;
}
}
return hash_ptr;
} }

View File

@@ -2,8 +2,23 @@
#define FIELD_HASH_H_ #define FIELD_HASH_H_
#include <stdint.h> #include <stdint.h>
#include <stdbool.h>
const uint8_t *field_hash(const void *const structs_array, #define IS_DYN(type) (((type) == TYPE_SOL_STRING) || ((type) == TYPE_SOL_BYTES_DYN))
const uint8_t *const data,
const uint8_t data_length); typedef enum
{
FHS_IDLE,
FHS_WAITING_FOR_MORE
} e_field_hashing_state;
typedef struct
{
uint16_t remaining_size;
uint8_t state; // e_field_hashing_state
} s_field_hashing;
const uint8_t *field_hash(const uint8_t *data,
uint8_t data_length,
bool partial);
#endif // FIELD_HASH_H_ #endif // FIELD_HASH_H_