Proper path implementation with array support
This commit is contained in:
@@ -20,9 +20,11 @@ bool init_eip712_context(void)
|
||||
mem_init();
|
||||
|
||||
if (init_sol_typenames() == false)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (init_path() == false)
|
||||
if (path_init() == false)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -108,7 +108,6 @@ const char *get_struct_field_typename(const uint8_t *ptr,
|
||||
uint8_t *const length);
|
||||
const char *get_struct_field_keyname(const uint8_t *ptr,
|
||||
uint8_t *const length);
|
||||
const uint8_t *get_next_struct_field_array_lvl(const uint8_t *ptr);
|
||||
const uint8_t *get_next_struct_field(const void *ptr);
|
||||
const uint8_t *get_structn(const uint8_t *const ptr,
|
||||
const char *const name_ptr,
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#include "context.h"
|
||||
#include "sol_typenames.h"
|
||||
#include "field_hash.h"
|
||||
#include "path.h"
|
||||
|
||||
|
||||
// lib functions
|
||||
@@ -380,12 +381,15 @@ bool handle_apdu(const uint8_t *const data)
|
||||
switch (data[OFFSET_P2])
|
||||
{
|
||||
case P2_NAME:
|
||||
// set root type
|
||||
path_set_root((char*)&data[OFFSET_DATA], data[OFFSET_LC]);
|
||||
type_hash(structs_array, (char*)&data[OFFSET_DATA], data[OFFSET_LC]);
|
||||
break;
|
||||
case P2_FIELD:
|
||||
field_hash(structs_array, &data[OFFSET_DATA], data[OFFSET_LC]);
|
||||
break;
|
||||
case P2_ARRAY:
|
||||
path_new_array_depth(data[OFFSET_DATA]);
|
||||
break;
|
||||
default:
|
||||
printf("Unknown P2 0x%x for APDU 0x%x\n", data[OFFSET_P2], data[OFFSET_INS]);
|
||||
|
||||
@@ -1,16 +1,36 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include "field_hash.h"
|
||||
#include "encode_field.h"
|
||||
#include "path.h"
|
||||
#include "eip712.h"
|
||||
|
||||
const uint8_t *field_hash(const void *const structs_array,
|
||||
const uint8_t *const data,
|
||||
const uint8_t data_length)
|
||||
{
|
||||
const char *type;
|
||||
uint8_t typelen;
|
||||
const char *key;
|
||||
uint8_t keylen;
|
||||
const void *field;
|
||||
|
||||
(void)structs_array;
|
||||
(void)data;
|
||||
(void)data_length;
|
||||
// get field by path
|
||||
encode_integer(data, data_length);
|
||||
// path += 1
|
||||
//encode_integer(data, data_length);
|
||||
field = path_get_field();
|
||||
if (field != NULL)
|
||||
{
|
||||
printf("==> ");
|
||||
type = get_struct_field_typename(field, &typelen);
|
||||
fwrite(type, sizeof(char), typelen, stdout);
|
||||
printf(" ");
|
||||
key = get_struct_field_keyname(field, &keylen);
|
||||
fwrite(key, sizeof(char), keylen, stdout);
|
||||
printf("\n");
|
||||
path_advance();
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -1,22 +1,406 @@
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include "path.h"
|
||||
#include "mem.h"
|
||||
#include "context.h"
|
||||
#include "eip712.h"
|
||||
|
||||
uint8_t *path_indexes;
|
||||
static s_path *path_struct = NULL;
|
||||
|
||||
/**
|
||||
* Allocates the the path indexes in memory and sets them all to 0 with a count of 1.
|
||||
* Get the field pointer to by the first N depths of the path.
|
||||
*
|
||||
* @param[out] fields_count_ptr the number of fields in the last evaluated depth
|
||||
* @param[in] depth_count the number of depths to evaluate (N)
|
||||
* @return the feld which the first Nth depths points to
|
||||
*/
|
||||
bool init_path(void)
|
||||
static const void *get_nth_field_from_path(uint8_t *const fields_count_ptr,
|
||||
uint8_t depth_count)
|
||||
{
|
||||
// + 1 for the used index count
|
||||
if ((path_indexes = mem_alloc(sizeof(uint8_t) * (MAX_PATH_DEPTH + 1))) != NULL)
|
||||
const void *struct_ptr = path_struct->root_struct;
|
||||
const void *field_ptr = NULL;
|
||||
const char *typename;
|
||||
uint8_t length;
|
||||
uint8_t fields_count;
|
||||
|
||||
if (depth_count > path_struct->depth_count) // sanity check
|
||||
{
|
||||
// set all to 0
|
||||
explicit_bzero(path_indexes + 1, sizeof(uint8_t) * MAX_PATH_DEPTH);
|
||||
*path_indexes = 1; // init count at 1, so the default path will be 0
|
||||
return NULL;
|
||||
}
|
||||
return path_indexes != NULL;
|
||||
for (uint8_t depth = 0; depth < depth_count; ++depth)
|
||||
{
|
||||
field_ptr = get_struct_fields_array(struct_ptr, &fields_count);
|
||||
|
||||
if (fields_count_ptr != NULL)
|
||||
{
|
||||
*fields_count_ptr = fields_count;
|
||||
}
|
||||
// check if the index at this depth makes sense
|
||||
if (path_struct->depths[depth] > fields_count)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (uint8_t index = 0; index < path_struct->depths[depth]; ++index)
|
||||
{
|
||||
field_ptr = get_next_struct_field(field_ptr);
|
||||
}
|
||||
if (struct_field_type(field_ptr) == TYPE_CUSTOM)
|
||||
{
|
||||
typename = get_struct_field_typename(field_ptr, &length);
|
||||
if ((struct_ptr = get_structn(structs_array, typename, length)) == NULL)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
return field_ptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the element the path is pointing to. (internal)
|
||||
*
|
||||
* @param[out] the number of fields in the depth of the returned field
|
||||
* @return the field which the path points to
|
||||
*/
|
||||
static inline const void *get_field_from_path(uint8_t *const fields_count)
|
||||
{
|
||||
return get_nth_field_from_path(fields_count, path_struct->depth_count);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the element the path is pointing to. (public facing)
|
||||
*
|
||||
* @return the field which the path points to
|
||||
*/
|
||||
const void *path_get_field(void)
|
||||
{
|
||||
return get_field_from_path(NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* Go down (add) a depth level.
|
||||
*
|
||||
* @return whether the push was succesful
|
||||
*/
|
||||
static bool path_depth_list_push(void)
|
||||
{
|
||||
if (path_struct->depth_count == MAX_PATH_DEPTH)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
path_struct->depths[path_struct->depth_count] = 0;
|
||||
path_struct->depth_count += 1;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Go up (remove) a depth level.
|
||||
*
|
||||
* @return whether the pop was successful
|
||||
*/
|
||||
static bool path_depth_list_pop(void)
|
||||
{
|
||||
if (path_struct->depth_count == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
path_struct->depth_count -= 1;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Go down (add) an array depth level.
|
||||
*
|
||||
* @param[in] path_idx the index in the path list
|
||||
* @param[in] the number of elements contained in that depth
|
||||
* @return whether the push was successful
|
||||
*/
|
||||
static bool array_depth_list_push(uint8_t path_idx, uint8_t size)
|
||||
{
|
||||
s_array_depth *arr = &path_struct->array_depths[path_struct->array_depth_count];
|
||||
|
||||
if (path_struct->array_depth_count == MAX_ARRAY_DEPTH)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
arr->path_index = path_idx;
|
||||
arr->size = size;
|
||||
path_struct->array_depth_count += 1;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Go up (remove) an array depth level.
|
||||
*
|
||||
* @return whether the pop was successful
|
||||
*/
|
||||
static bool array_depth_list_pop(void)
|
||||
{
|
||||
if (path_struct->array_depth_count == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
path_struct->array_depth_count -= 1;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the path so that it doesn't point to a struct-type field, but rather
|
||||
* only to actual fields.
|
||||
*
|
||||
* @return whether the path update worked or not
|
||||
*/
|
||||
static bool path_update(void)
|
||||
{
|
||||
uint8_t fields_count;
|
||||
const void *struct_ptr = path_struct->root_struct;
|
||||
const void *field_ptr;
|
||||
const char *typename;
|
||||
uint8_t typename_len;
|
||||
|
||||
if ((field_ptr = get_field_from_path(NULL)) == NULL)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
while (struct_field_type(field_ptr) == TYPE_CUSTOM)
|
||||
{
|
||||
// TODO: calculate the type hash here
|
||||
typename = get_struct_field_typename(field_ptr, &typename_len);
|
||||
if ((struct_ptr = get_structn(structs_array, typename, typename_len)) == NULL)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if ((field_ptr = get_struct_fields_array(struct_ptr, &fields_count)) == NULL)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
path_depth_list_push();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a new struct as the path root type
|
||||
*
|
||||
* @param[in] struct_name the root struct name
|
||||
* @param[in] name_length the root struct name length
|
||||
* @return boolean indicating if it was successful or not
|
||||
*/
|
||||
bool path_set_root(const char *const struct_name, uint8_t name_length)
|
||||
{
|
||||
if (path_struct == NULL)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
path_struct->root_struct = get_structn(structs_array, struct_name, name_length);
|
||||
|
||||
if (path_struct->root_struct == NULL)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// init depth, at 0 : empty path
|
||||
path_struct->depth_count = 0;
|
||||
path_depth_list_push();
|
||||
|
||||
// init array levels at 0
|
||||
path_struct->array_depth_count = 0;
|
||||
|
||||
// because the first field could be a struct type
|
||||
path_update();
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks the new array depth and adds it to the list
|
||||
*
|
||||
* @param[in] depth pointer to the array depth definition
|
||||
* @param[in] total_count number of array depth contained down to this array depth
|
||||
* @param[in] pidx path index
|
||||
* @param[in] size requested array depth size
|
||||
* @return whether the checks and add were successful or not
|
||||
*/
|
||||
static bool check_and_add_array_depth(const void *depth,
|
||||
uint8_t total_count,
|
||||
uint8_t pidx,
|
||||
uint8_t size)
|
||||
{
|
||||
uint8_t expected_size;
|
||||
uint8_t arr_idx = (total_count - path_struct->array_depth_count) - 1;
|
||||
e_array_type expected_type;
|
||||
|
||||
// we skip index 0, since we already have it
|
||||
for (uint8_t idx = 1; idx < (arr_idx + 1); ++idx)
|
||||
{
|
||||
if ((depth = get_next_struct_field_array_lvl(depth)) == NULL)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
expected_type = struct_field_array_depth(depth, &expected_size);
|
||||
if ((expected_type == ARRAY_FIXED_SIZE) && (expected_size != size))
|
||||
{
|
||||
printf("Unexpected array depth size. (expected %d, got %d)\n",
|
||||
expected_size, size);
|
||||
return false;
|
||||
}
|
||||
// add it
|
||||
if (!array_depth_list_push(pidx, size))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a new array depth with a given size (number of elements).
|
||||
*
|
||||
* @return whether the add was successful or not
|
||||
*/
|
||||
bool path_new_array_depth(uint8_t size)
|
||||
{
|
||||
const void *field_ptr, *depth;
|
||||
uint8_t depth_count;
|
||||
uint8_t total_count = 0;
|
||||
uint8_t pidx;
|
||||
|
||||
if (path_struct == NULL) // sanity check
|
||||
{
|
||||
printf("NULL struct check failed\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
for (pidx = 0; pidx < path_struct->depth_count; ++pidx)
|
||||
{
|
||||
if ((field_ptr = get_nth_field_from_path(NULL, pidx + 1)) == NULL)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (struct_field_is_array(field_ptr))
|
||||
{
|
||||
if ((depth = get_struct_field_array_lvls_array(field_ptr, &depth_count)) == NULL)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
total_count += depth_count;
|
||||
if (total_count > path_struct->array_depth_count)
|
||||
{
|
||||
if (!check_and_add_array_depth(depth, total_count, pidx, size))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (pidx == path_struct->depth_count)
|
||||
{
|
||||
printf("Did not find a matching array type.\n");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Advance within the struct that contains the field the path points to.
|
||||
*
|
||||
* @return whether the end of the struct has been reached.
|
||||
*/
|
||||
static bool path_advance_in_struct(void)
|
||||
{
|
||||
bool end_reached = true;
|
||||
uint8_t *depth = &path_struct->depths[path_struct->depth_count - 1];
|
||||
uint8_t fields_count;
|
||||
|
||||
if ((get_field_from_path(&fields_count)) == NULL)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (path_struct->depth_count > 0)
|
||||
{
|
||||
*depth += 1;
|
||||
end_reached = (*depth == fields_count);
|
||||
}
|
||||
if (end_reached)
|
||||
{
|
||||
path_depth_list_pop();
|
||||
}
|
||||
return end_reached;
|
||||
}
|
||||
|
||||
/**
|
||||
* Advance within the array levels of the current field the path points to.
|
||||
*
|
||||
* @return whether the end of the array levels has been reached.
|
||||
*/
|
||||
static bool path_advance_in_array(void)
|
||||
{
|
||||
bool end_reached;
|
||||
s_array_depth *arr_depth;
|
||||
|
||||
do
|
||||
{
|
||||
end_reached = false;
|
||||
arr_depth = &path_struct->array_depths[path_struct->array_depth_count - 1];
|
||||
|
||||
if ((path_struct->array_depth_count > 0) &&
|
||||
(arr_depth->path_index == (path_struct->depth_count - 1)))
|
||||
{
|
||||
arr_depth->size -= 1;
|
||||
if (arr_depth->size == 0)
|
||||
{
|
||||
array_depth_list_pop();
|
||||
end_reached = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
while (end_reached);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the path to point to the next field in order (DFS).
|
||||
*
|
||||
* @return whether the advancement was successful or not
|
||||
*/
|
||||
bool path_advance(void)
|
||||
{
|
||||
bool end_reached;
|
||||
|
||||
do
|
||||
{
|
||||
if (path_advance_in_array())
|
||||
{
|
||||
end_reached = path_advance_in_struct();
|
||||
}
|
||||
else
|
||||
{
|
||||
end_reached = false;
|
||||
}
|
||||
}
|
||||
while (end_reached);
|
||||
path_update();
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allocates the the path indexes in memory and sets it with a depth of 0.
|
||||
*
|
||||
* @return whether the memory allocation were successful.
|
||||
*/
|
||||
bool path_init(void)
|
||||
{
|
||||
if (path_struct == NULL)
|
||||
{
|
||||
path_struct = mem_alloc(sizeof(*path_struct));
|
||||
}
|
||||
return path_struct != NULL;
|
||||
}
|
||||
|
||||
@@ -1,12 +1,31 @@
|
||||
#ifndef PATH_H_
|
||||
#define PATH_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#define MAX_PATH_DEPTH 16
|
||||
#define MAX_ARRAY_DEPTH 4
|
||||
|
||||
extern uint8_t *path_indexes;
|
||||
typedef struct __attribute__((packed))
|
||||
{
|
||||
uint8_t path_index;
|
||||
uint8_t size;
|
||||
} s_array_depth;
|
||||
|
||||
bool init_path(void);
|
||||
typedef struct __attribute__((packed))
|
||||
{
|
||||
const void *root_struct;
|
||||
uint8_t depth_count;
|
||||
uint8_t depths[MAX_PATH_DEPTH];
|
||||
uint8_t array_depth_count;
|
||||
s_array_depth array_depths[MAX_ARRAY_DEPTH];
|
||||
} s_path;
|
||||
|
||||
bool path_set_root(const char *const struct_name, uint8_t length);
|
||||
const void *path_get_field(void);
|
||||
bool path_advance(void);
|
||||
bool path_init(void);
|
||||
bool path_new_array_depth(uint8_t size);
|
||||
|
||||
#endif // PATH_H_
|
||||
|
||||
Reference in New Issue
Block a user