diff --git a/src_features/signMessageEIP712/format_hash_field_type.c b/src_features/signMessageEIP712/format_hash_field_type.c new file mode 100644 index 0000000..399ef36 --- /dev/null +++ b/src_features/signMessageEIP712/format_hash_field_type.c @@ -0,0 +1,116 @@ +#ifdef HAVE_EIP712_FULL_SUPPORT + +#include "format_hash_field_type.h" +#include "mem.h" +#include "mem_utils.h" +#include "eip712.h" +#include "hash_bytes.h" + +/** + * Format & hash a struct field typesize + * + * @param[in] field_ptr pointer to the struct field + * @param[in] hash_ctx pointer to the hashing context + * @return whether the formatting & hashing were successful or not + */ +static bool format_hash_field_type_size(const void *const field_ptr, cx_hash_t *hash_ctx) +{ + uint16_t field_size; + char *uint_str_ptr; + uint8_t uint_str_len; + + field_size = get_struct_field_typesize(field_ptr); + switch (struct_field_type(field_ptr)) + { + case TYPE_SOL_INT: + case TYPE_SOL_UINT: + field_size *= 8; // bytes -> bits + break; + case TYPE_SOL_BYTES_FIX: + break; + default: + // should not be in here :^) + return false; + } + uint_str_ptr = mem_alloc_and_format_uint(field_size, &uint_str_len); + hash_nbytes((uint8_t*)uint_str_ptr, uint_str_len, hash_ctx); + mem_dealloc(uint_str_len); + return true; +} + +/** + * Format & hash a struct field array levels + * + * @param[in] field_ptr pointer to the struct field + * @param[in] hash_ctx pointer to the hashing context + * @return whether the formatting & hashing were successful or not + */ +static bool format_hash_field_type_array_levels(const void *const field_ptr, cx_hash_t *hash_ctx) +{ + uint8_t array_size; + char *uint_str_ptr; + uint8_t uint_str_len; + const void *lvl_ptr; + uint8_t lvls_count; + + lvl_ptr = get_struct_field_array_lvls_array(field_ptr, &lvls_count); + while (lvls_count-- > 0) + { + hash_byte('[', hash_ctx); + + switch (struct_field_array_depth(lvl_ptr, &array_size)) + { + case ARRAY_DYNAMIC: + break; + case ARRAY_FIXED_SIZE: + uint_str_ptr = mem_alloc_and_format_uint(array_size, &uint_str_len); + hash_nbytes((uint8_t*)uint_str_ptr, uint_str_len, hash_ctx); + mem_dealloc(uint_str_len); + break; + default: + // should not be in here :^) + return false; + } + hash_byte(']', hash_ctx); + lvl_ptr = get_next_struct_field_array_lvl(lvl_ptr); + } + return true; +} + +/** + * Format & hash a struct field type + * + * @param[in] field_ptr pointer to the struct field + * @param[in] hash_ctx pointer to the hashing context + * @return whether the formatting & hashing were successful or not + */ +bool format_hash_field_type(const void *const field_ptr, cx_hash_t *hash_ctx) +{ + const char *name; + uint8_t length; + + // field type name + name = get_struct_field_typename(field_ptr, &length); + hash_nbytes((uint8_t*)name, length, hash_ctx); + + // field type size + if (struct_field_has_typesize(field_ptr)) + { + if (!format_hash_field_type_size(field_ptr, hash_ctx)) + { + return false; + } + } + + // field type array levels + if (struct_field_is_array(field_ptr)) + { + if (!format_hash_field_type_array_levels(field_ptr, hash_ctx)) + { + return false; + } + } + return true; +} + +#endif // HAVE_EIP712_FULL_SUPPORT diff --git a/src_features/signMessageEIP712/format_hash_field_type.h b/src_features/signMessageEIP712/format_hash_field_type.h new file mode 100644 index 0000000..6baea31 --- /dev/null +++ b/src_features/signMessageEIP712/format_hash_field_type.h @@ -0,0 +1,12 @@ +#ifndef FORMAT_HASH_FIELD_TYPE_H_ +#define FORMAT_HASH_FIELD_TYPE_H_ + +#ifdef HAVE_EIP712_FULL_SUPPORT + +#include "cx.h" + +bool format_hash_field_type(const void *const field_ptr, cx_hash_t *hash_ctx); + +#endif // HAVE_EIP712_FULL_SUPPORT + +#endif // FORMAT_HASH_FIELD_TYPE_H_ diff --git a/src_features/signMessageEIP712/hash_bytes.c b/src_features/signMessageEIP712/hash_bytes.c new file mode 100644 index 0000000..0a5ee6a --- /dev/null +++ b/src_features/signMessageEIP712/hash_bytes.c @@ -0,0 +1,33 @@ +#ifdef HAVE_EIP712_FULL_SUPPORT + +#include "hash_bytes.h" + +/** + * Continue given progressive hash on given bytes + * + * @param[in] bytes_ptr pointer to bytes + * @param[in] n number of bytes to hash + * @param[in] hash_ctx pointer to the hashing context + */ +void hash_nbytes(const uint8_t *const bytes_ptr, uint8_t n, cx_hash_t *hash_ctx) +{ + cx_hash(hash_ctx, + 0, + bytes_ptr, + n, + NULL, + 0); +} + +/** + * Continue given progressive hash on given byte + * + * @param[in] byte byte to hash + * @param[in] hash_ctx pointer to the hashing context + */ +void hash_byte(uint8_t byte, cx_hash_t *hash_ctx) +{ + hash_nbytes(&byte, 1, hash_ctx); +} + +#endif // HAVE_EIP712_FULL_SUPPORT diff --git a/src_features/signMessageEIP712/hash_bytes.h b/src_features/signMessageEIP712/hash_bytes.h new file mode 100644 index 0000000..32e7d11 --- /dev/null +++ b/src_features/signMessageEIP712/hash_bytes.h @@ -0,0 +1,13 @@ +#ifndef HASH_BYTES_H_ +#define HASH_BYTES_H_ + +#ifdef HAVE_EIP712_FULL_SUPPORT + +#include "cx.h" + +void hash_nbytes(const uint8_t *const bytes_ptr, uint8_t n, cx_hash_t *hash_ctx); +void hash_byte(uint8_t byte, cx_hash_t *hash_ctx); + +#endif // HAVE_EIP712_FULL_SUPPORT + +#endif // HASH_BYTES_H_ diff --git a/src_features/signMessageEIP712/mem_utils.c b/src_features/signMessageEIP712/mem_utils.c index 09d98cd..e45280f 100644 --- a/src_features/signMessageEIP712/mem_utils.c +++ b/src_features/signMessageEIP712/mem_utils.c @@ -46,8 +46,7 @@ char *mem_alloc_and_format_uint(uint32_t value, uint8_t *const length) // +1 for the null character if ((mem_ptr = mem_alloc(sizeof(char) * (size + 1)))) { - // should be using %u, but not supported by toolchain - snprintf(mem_ptr, (size + 1), "%d", value); + snprintf(mem_ptr, (size + 1), "%u", value); mem_dealloc(sizeof(char)); // to skip the null character if (length != NULL) { diff --git a/src_features/signMessageEIP712/type_hash.c b/src_features/signMessageEIP712/type_hash.c index f9b28ca..b234c66 100644 --- a/src_features/signMessageEIP712/type_hash.c +++ b/src_features/signMessageEIP712/type_hash.c @@ -9,115 +9,29 @@ #include "type_hash.h" #include "shared_context.h" #include "ethUtils.h" // KECCAK256_HASH_BYTESIZE - -static inline void hash_nbytes(const uint8_t *b, uint8_t n) -{ -#ifdef DEBUG - for (int i = 0; i < n; ++i) - { - PRINTF("%c", b[i]); - } -#endif - cx_hash((cx_hash_t*)&global_sha3, - 0, - b, - n, - NULL, - 0); -} - -static inline void hash_byte(uint8_t b) -{ - hash_nbytes(&b, 1); -} - -/** - * - * @param[in] lvl_ptr pointer to the first array level of a struct field - * @param[in] lvls_count the number of array levels the struct field contains - * @return \ref true it finished correctly, \ref false if it didn't (memory allocation) - */ -static bool format_field_type_array_levels_string(const void *lvl_ptr, uint8_t lvls_count) -{ - uint8_t array_size; - char *uint_str_ptr; - uint8_t uint_str_len; - - while (lvls_count-- > 0) - { - hash_byte('['); - - switch (struct_field_array_depth(lvl_ptr, &array_size)) - { - case ARRAY_DYNAMIC: - break; - case ARRAY_FIXED_SIZE: - uint_str_ptr = mem_alloc_and_format_uint(array_size, &uint_str_len); - hash_nbytes((uint8_t*)uint_str_ptr, uint_str_len); - mem_dealloc(uint_str_len); - break; - default: - // should not be in here :^) - break; - } - hash_byte(']'); - lvl_ptr = get_next_struct_field_array_lvl(lvl_ptr); - } - return true; -} +#include "format_hash_field_type.h" +#include "hash_bytes.h" /** * * @param[in] field_ptr pointer to the struct field * @return \ref true it finished correctly, \ref false if it didn't (memory allocation) */ -static bool encode_and_hash_field(const void *field_ptr) +static bool encode_and_hash_field(const void *const field_ptr) { const char *name; uint8_t length; - uint16_t field_size; - uint8_t lvls_count; - const uint8_t *lvl_ptr; - char *uint_str_ptr; - uint8_t uint_str_len; - // field type name - name = get_struct_field_typename(field_ptr, &length); - hash_nbytes((uint8_t*)name, length); - - // field type size - if (struct_field_has_typesize(field_ptr)) + if (!format_hash_field_type(field_ptr, (cx_hash_t*)&global_sha3)) { - field_size = get_struct_field_typesize(field_ptr); - switch (struct_field_type(field_ptr)) - { - case TYPE_SOL_INT: - case TYPE_SOL_UINT: - field_size *= 8; // bytes -> bits - break; - case TYPE_SOL_BYTES_FIX: - break; - default: - // should not be in here :^) - break; - } - uint_str_ptr = mem_alloc_and_format_uint(field_size, &uint_str_len); - hash_nbytes((uint8_t*)uint_str_ptr, uint_str_len); - mem_dealloc(uint_str_len); - } - - // field type array levels - if (struct_field_is_array(field_ptr)) - { - lvl_ptr = get_struct_field_array_lvls_array(field_ptr, &lvls_count); - format_field_type_array_levels_string(lvl_ptr, lvls_count); + return false; } // space between field type name and field name - hash_byte(' '); + hash_byte(' ', (cx_hash_t*)&global_sha3); // field name name = get_struct_field_keyname(field_ptr, &length); - hash_nbytes((uint8_t*)name, length); + hash_nbytes((uint8_t*)name, length, (cx_hash_t*)&global_sha3); return true; } @@ -127,7 +41,7 @@ static bool encode_and_hash_field(const void *field_ptr) * @param[in] str_length length of the formatted string in memory * @return pointer of the string in memory, \ref NULL in case of an error */ -static bool encode_and_hash_type(const uint8_t *const struct_ptr) +static bool encode_and_hash_type(const void *const struct_ptr) { const char *struct_name; uint8_t struct_name_length; @@ -136,10 +50,10 @@ static bool encode_and_hash_type(const uint8_t *const struct_ptr) // struct name struct_name = get_struct_name(struct_ptr, &struct_name_length); - hash_nbytes((uint8_t*)struct_name, struct_name_length); + hash_nbytes((uint8_t*)struct_name, struct_name_length, (cx_hash_t*)&global_sha3); // opening struct parenthese - hash_byte('('); + hash_byte('(', (cx_hash_t*)&global_sha3); field_ptr = get_struct_fields_array(struct_ptr, &fields_count); for (uint8_t idx = 0; idx < fields_count; ++idx) @@ -147,7 +61,7 @@ static bool encode_and_hash_type(const uint8_t *const struct_ptr) // comma separating struct fields if (idx > 0) { - hash_byte(','); + hash_byte(',', (cx_hash_t*)&global_sha3); } if (encode_and_hash_field(field_ptr) == false) @@ -158,7 +72,7 @@ static bool encode_and_hash_type(const uint8_t *const struct_ptr) field_ptr = get_next_struct_field(field_ptr); } // closing struct parenthese - hash_byte(')'); + hash_byte(')', (cx_hash_t*)&global_sha3); return true; } @@ -302,9 +216,7 @@ const uint8_t *type_hash(const void *const structs_array, deps += 1; } mem_dealloc(mem_alloc(0) - mem_loc_bak); -#ifdef DEBUG - PRINTF("\n"); -#endif + // End progressive hashing if ((hash_ptr = mem_alloc(KECCAK256_HASH_BYTESIZE)) == NULL) {