Skip to content

Commit 5e8bd95

Browse files
Move away from recursive calls when computing the EIP-712 type_hash
1 parent 31e3b60 commit 5e8bd95

1 file changed

Lines changed: 61 additions & 42 deletions

File tree

src/features/sign_message_eip712/type_hash.c

Lines changed: 61 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -69,56 +69,75 @@ typedef struct struct_dep {
6969
} s_struct_dep;
7070

7171
/**
72-
* Find all the dependencies from a given structure
72+
* Add a struct to the dependency list if not already present
7373
*
74-
* @param[out] deps_count count of how many struct dependency pointers
75-
* @param[in] first_dep pointer to the first dependency pointer
76-
* @param[in] struct_ptr pointer to the struct we are getting the dependencies of
77-
* @return pointer to the first found dependency, \ref NULL otherwise
74+
* @param[in,out] first_dep pointer to the head of the dependency list
75+
* @param[in] s pointer to the struct to add
76+
* @return \ref true on success, \ref false on memory allocation failure
7877
*/
79-
static bool get_struct_dependencies(s_struct_dep **first_dep, const s_struct_712 *struct_ptr) {
80-
const s_struct_712_field *field_ptr;
81-
const char *arg_structname;
82-
const s_struct_712 *arg_struct_ptr;
78+
static bool add_dep_if_new(s_struct_dep **first_dep, const s_struct_712 *s) {
8379
s_struct_dep *tmp;
8480
s_struct_dep *new_dep;
8581

82+
for (tmp = *first_dep; tmp != NULL; tmp = (s_struct_dep *) ((flist_node_t *) tmp)->next) {
83+
if (tmp->s == s) return true;
84+
}
85+
if ((new_dep = APP_MEM_ALLOC(sizeof(*new_dep))) == NULL) {
86+
apdu_response_code = SWO_INSUFFICIENT_MEMORY;
87+
return false;
88+
}
89+
new_dep->s = s;
90+
flist_push_back((flist_node_t **) first_dep, (flist_node_t *) new_dep);
91+
return true;
92+
}
93+
94+
/**
95+
* Scan all fields of a struct and add any unknown TYPE_CUSTOM dependencies
96+
*
97+
* @param[in,out] first_dep pointer to the head of the dependency list
98+
* @param[in] struct_ptr pointer to the struct whose fields are scanned
99+
* @return \ref true on success, \ref false on error
100+
*/
101+
static bool collect_direct_deps(s_struct_dep **first_dep, const s_struct_712 *struct_ptr) {
102+
const s_struct_712_field *field_ptr;
103+
const s_struct_712 *dep;
104+
const char *dep_name;
105+
86106
for (field_ptr = struct_ptr->fields; field_ptr != NULL;
87107
field_ptr = (s_struct_712_field *) ((flist_node_t *) field_ptr)->next) {
88-
if (field_ptr->type == TYPE_CUSTOM) {
89-
// get struct name
90-
arg_structname = get_struct_field_typename(field_ptr);
91-
// from its name, get the pointer to its definition
92-
if ((arg_struct_ptr = get_structn(arg_structname, strlen(arg_structname))) == NULL) {
93-
PRINTF("Error: could not find EIP-712 dependency struct \"");
94-
for (int i = 0; i < (int) strlen(arg_structname); ++i)
95-
PRINTF("%c", arg_structname[i]);
96-
PRINTF("\" during type_hash\n");
97-
return false;
98-
}
99-
100-
// check if it is not already present in the dependencies array
101-
for (tmp = *first_dep; tmp != NULL;
102-
tmp = (s_struct_dep *) ((flist_node_t *) tmp)->next) {
103-
// it's a match!
104-
if (tmp->s == arg_struct_ptr) {
105-
break;
106-
}
107-
}
108-
// if it's not present in the array, add it and recurse into it
109-
if (tmp == NULL) {
110-
if (APP_MEM_CALLOC((void **) &new_dep, sizeof(s_struct_dep)) == false) {
111-
apdu_response_code = SWO_INSUFFICIENT_MEMORY;
112-
return false;
113-
}
114-
new_dep->s = arg_struct_ptr;
115-
flist_push_back((flist_node_t **) first_dep, (flist_node_t *) new_dep);
116-
// TODO: Move away from recursive calls
117-
if (!get_struct_dependencies(first_dep, arg_struct_ptr)) {
118-
return false;
119-
}
120-
}
108+
if (field_ptr->type != TYPE_CUSTOM) continue;
109+
110+
dep_name = get_struct_field_typename(field_ptr);
111+
if ((dep = get_structn(dep_name, strlen(dep_name))) == NULL) {
112+
PRINTF("Error: could not find EIP-712 dependency struct \"");
113+
for (size_t i = 0; i < strlen(dep_name); ++i) PRINTF("%c", dep_name[i]);
114+
PRINTF("\" during type_hash\n");
115+
return false;
121116
}
117+
if (!add_dep_if_new(first_dep, dep)) return false;
118+
}
119+
return true;
120+
}
121+
122+
/**
123+
* Find all the transitive dependencies of a given structure
124+
*
125+
* Uses the dependency list itself as a worklist: new entries are appended at
126+
* the back while the cursor advances forward, so newly discovered dependencies
127+
* are processed without recursion and without extra allocations.
128+
*
129+
* @param[out] first_dep pointer to the head of the dependency list
130+
* @param[in] struct_ptr pointer to the struct we are getting the dependencies of
131+
* @return \ref true on success, \ref false on error
132+
*/
133+
static bool get_struct_dependencies(s_struct_dep **first_dep, const s_struct_712 *struct_ptr) {
134+
s_struct_dep *cursor;
135+
136+
if (!collect_direct_deps(first_dep, struct_ptr)) return false;
137+
138+
for (cursor = *first_dep; cursor != NULL;
139+
cursor = (s_struct_dep *) ((flist_node_t *) cursor)->next) {
140+
if (!collect_direct_deps(first_dep, cursor->s)) return false;
122141
}
123142
return true;
124143
}

0 commit comments

Comments
 (0)