Refactored some type EIP712 formatting and hashing code to re-use it

This commit is contained in:
Alexandre Paillier
2022-06-29 14:08:08 +02:00
parent 1b00038859
commit 5450f0c46f
6 changed files with 188 additions and 103 deletions

View File

@@ -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

View File

@@ -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_

View File

@@ -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

View File

@@ -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_

View File

@@ -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)
{

View File

@@ -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)
{