WIP field hashing support
This commit is contained in:
@@ -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);
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -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_
|
||||||
|
|||||||
@@ -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]);
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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_
|
||||||
|
|||||||
Reference in New Issue
Block a user